Skip to content

Commit 95c56e8

Browse files
authored
Merge pull request #24 from probitas-test/feat/oauth2
Simplify echo-http authentication to environment-based OAuth2/OIDC
2 parents 52ca2b3 + 3e305f1 commit 95c56e8

32 files changed

+4546
-4537
lines changed

echo-connectrpc/docs/api.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,28 @@
1212
1313
## Environment Variables
1414

15-
The server supports the following environment variables for configuration:
15+
### Server Configuration
16+
17+
| Variable | Default | Description |
18+
| -------- | --------- | ------------ |
19+
| `HOST` | `0.0.0.0` | Bind address |
20+
| `PORT` | `8080` | Listen port |
1621

1722
### Protocol Control
1823

1924
| Variable | Default | Description |
2025
| -------------------- | ------- | ---------------------------- |
21-
| `HOST` | 0.0.0.0 | Host address to bind |
22-
| `PORT` | 8080 | Port number to listen on |
23-
| `DISABLE_CONNECTRPC` | false | Disable Connect RPC protocol |
24-
| `DISABLE_GRPC` | false | Disable gRPC protocol |
25-
| `DISABLE_GRPC_WEB` | false | Disable gRPC-Web protocol |
26+
| `DISABLE_CONNECTRPC` | `false` | Disable Connect RPC protocol |
27+
| `DISABLE_GRPC` | `false` | Disable gRPC protocol |
28+
| `DISABLE_GRPC_WEB` | `false` | Disable gRPC-Web protocol |
2629

2730
### Reflection Control
2831

2932
| Variable | Default | Description |
3033
| --------------------------------- | ------- | ----------------------------------------------------------- |
31-
| `REFLECTION_INCLUDE_DEPENDENCIES` | false | Include transitive dependencies (note: not fully supported) |
32-
| `DISABLE_REFLECTION_V1` | false | Disable gRPC reflection v1 API |
33-
| `DISABLE_REFLECTION_V1ALPHA` | false | Disable gRPC reflection v1alpha API |
34+
| `REFLECTION_INCLUDE_DEPENDENCIES` | `false` | Include transitive dependencies (note: not fully supported) |
35+
| `DISABLE_REFLECTION_V1` | `false` | Disable gRPC reflection v1 API |
36+
| `DISABLE_REFLECTION_V1ALPHA` | `false` | Disable gRPC reflection v1alpha API |
3437

3538
**Note:** At least one protocol must be enabled. The server will refuse to start if all protocols are disabled.
3639

@@ -47,6 +50,8 @@ DISABLE_GRPC=true DISABLE_GRPC_WEB=true ./echo-connectrpc
4750
DISABLE_REFLECTION_V1ALPHA=true ./echo-connectrpc
4851
```
4952

53+
---
54+
5055
## Protocol
5156

5257
Connect RPC supports three protocols:

echo-graphql/docs/api.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,16 @@
1010
> **Note:** The container listens on port 8080. When using `docker compose up`, the
1111
> port is mapped to 14000 on the host.
1212
13-
## Endpoints
14-
15-
| Path | Description |
16-
| ------------- | ------------------ |
17-
| `/` | API documentation |
18-
| `/graphql` | GraphQL endpoint |
19-
| `/playground` | GraphQL Playground |
20-
| `/health` | Health check |
13+
## Environment Variables
14+
15+
### Server Configuration
16+
17+
| Variable | Default | Description |
18+
| -------- | --------- | ------------ |
19+
| `HOST` | `0.0.0.0` | Bind address |
20+
| `PORT` | `8080` | Listen port |
21+
22+
---
2123

2224
## Schema
2325

echo-grpc/docs/api.md

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@
1010
> **Note:** The container listens on port 50051. The same port is exposed
1111
> when using `docker compose up`.
1212
13+
## Environment Variables
14+
15+
### Server Configuration
16+
17+
| Variable | Default | Description |
18+
| -------- | --------- | ------------ |
19+
| `HOST` | `0.0.0.0` | Bind address |
20+
| `PORT` | `50051` | Listen port |
21+
22+
### gRPC Reflection Configuration
23+
24+
| Variable | Default | Description |
25+
| --------------------------------- | ------- | --------------------------------------------- |
26+
| `REFLECTION_INCLUDE_DEPENDENCIES` | `false` | Include transitive dependencies in reflection |
27+
| `DISABLE_REFLECTION_V1` | `false` | Disable gRPC reflection v1 API |
28+
| `DISABLE_REFLECTION_V1ALPHA` | `false` | Disable gRPC reflection v1alpha API |
29+
30+
These flags allow testing client compatibility with different reflection API versions.
31+
32+
---
33+
1334
## Services
1435

1536
### Echo Service (echo.v1.Echo)
@@ -607,6 +628,8 @@ grpcurl -plaintext -d '{"service": ""}' \
607628

608629
The server supports gRPC server reflection for service discovery (both v1 and v1alpha versions).
609630

631+
> **Configuration:** See [Environment Variables](#environment-variables) section for reflection configuration options.
632+
610633
```bash
611634
# List all services
612635
grpcurl -plaintext localhost:50051 list
@@ -618,14 +641,6 @@ grpcurl -plaintext localhost:50051 describe echo.v1.Echo
618641
grpcurl -plaintext localhost:50051 describe echo.v1.EchoRequest
619642
```
620643

621-
### Environment Variables
622-
623-
- `REFLECTION_INCLUDE_DEPENDENCIES` (default: `false`) - Include transitive dependencies in reflection responses
624-
- `DISABLE_REFLECTION_V1` (default: `false`) - Disable gRPC reflection v1 API
625-
- `DISABLE_REFLECTION_V1ALPHA` (default: `false`) - Disable gRPC reflection v1alpha API
626-
627-
These flags allow testing client compatibility with different reflection API versions.
628-
629644
## Metadata
630645

631646
Request metadata is echoed back in the `metadata` field of every response. Custom metadata can be sent using grpcurl's `-H` flag:

echo-http/README.md

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ docker run -p 8080:80 ghcr.io/probitas-test/echo-http:latest
1919

2020
## Environment Variables
2121

22+
### Server Configuration
23+
2224
| Variable | Default | Description |
2325
| -------- | --------- | ------------ |
2426
| `HOST` | `0.0.0.0` | Bind address |
@@ -32,6 +34,11 @@ docker run -p 3000:3000 -e PORT=3000 ghcr.io/probitas-test/echo-http:latest
3234
docker run -p 8080:8080 -v $(pwd)/.env:/app/.env ghcr.io/probitas-test/echo-http:latest
3335
```
3436

37+
### OAuth2/OIDC Configuration
38+
39+
For OAuth2/OIDC functionality configuration (client validation, scopes, PKCE, etc.),
40+
see the [Environment Variables](./docs/api.md#environment-variables) section in the API documentation.
41+
3542
## API
3643

3744
### Echo Endpoints
@@ -69,16 +76,23 @@ docker run -p 8080:8080 -v $(pwd)/.env:/app/.env ghcr.io/probitas-test/echo-http
6976

7077
### Authentication Endpoints
7178

72-
| Endpoint | Method | Description |
73-
| ------------------------------------------------------ | -------- | ---------------------------------------- |
74-
| `/basic-auth/{user}/{pass}` | GET | Basic auth (200 if match, 401 otherwise) |
75-
| `/hidden-basic-auth/{user}/{pass}` | GET | Basic auth (200 if match, 404 otherwise) |
76-
| `/bearer` | GET | Bearer token validation |
77-
| `/oidc/{user}/{pass}/.well-known/openid-configuration` | GET | OIDC Discovery metadata (mock) |
78-
| `/oidc/{user}/{pass}/authorize` | GET/POST | OIDC authorization endpoint (mock) |
79-
| `/oidc/{user}/{pass}/callback` | GET | OIDC callback handler |
80-
| `/oidc/{user}/{pass}/token` | POST | OIDC token endpoint (mock) |
81-
| `/oidc/{user}/{pass}/demo` | GET | Interactive OIDC flow demo (browser) |
79+
| Endpoint | Method | Description |
80+
| -------------- | ------ | ---------------------------------------- |
81+
| `/basic-auth` | GET | Basic auth (200 if match, 401 otherwise) |
82+
| `/bearer-auth` | GET | Bearer token validation (SHA1 hash) |
83+
84+
### OAuth2/OIDC Endpoints
85+
86+
| Endpoint | Method | Description |
87+
| ----------------------------------------- | -------- | ------------------------------------------- |
88+
| `/.well-known/oauth-authorization-server` | GET | OAuth2 Authorization Server Metadata |
89+
| `/.well-known/openid-configuration` | GET | OIDC Discovery metadata |
90+
| `/.well-known/jwks.json` | GET | JWKS endpoint (JSON Web Key Set) |
91+
| `/oauth2/authorize` | GET/POST | OAuth2/OIDC authorization endpoint |
92+
| `/oauth2/callback` | GET | OAuth2/OIDC callback handler |
93+
| `/oauth2/token` | POST | OAuth2/OIDC token endpoint |
94+
| `/oauth2/userinfo` | GET | UserInfo endpoint |
95+
| `/oauth2/demo` | GET | Interactive OAuth2/OIDC flow demo (browser) |
8296

8397
### Cookie Endpoints
8498

@@ -141,16 +155,17 @@ curl http://localhost:8080/delay/5
141155
curl -L http://localhost:8080/redirect/3
142156

143157
# Basic authentication
144-
curl -u user:pass http://localhost:8080/basic-auth/user/pass
158+
curl -u user:pass http://localhost:8080/basic-auth
145159

146-
# Bearer token
147-
curl -H "Authorization: Bearer my-token" http://localhost:8080/bearer
160+
# Bearer token (SHA1 of username:password)
161+
TOKEN=$(echo -n "user:pass" | shasum -a 1 | cut -d' ' -f1)
162+
curl -H "Authorization: Bearer $TOKEN" http://localhost:8080/bearer-auth
148163

149-
# OIDC interactive demo (open in browser for complete flow demonstration)
150-
open "http://localhost:8080/oidc/testuser/testpass/demo"
164+
# OAuth2/OIDC interactive demo (open in browser for complete flow demonstration)
165+
open "http://localhost:8080/oauth2/demo"
151166

152-
# OIDC manual flow (for programmatic testing)
153-
# curl "http://localhost:8080/oidc/testuser/testpass/authorize?redirect_uri=http://localhost:8080/oidc/testuser/testpass/callback&response_type=code"
167+
# OAuth2/OIDC manual flow (for programmatic testing)
168+
curl "http://localhost:8080/oauth2/authorize?client_id=my-app&redirect_uri=http://localhost:8080/oauth2/callback&response_type=code"
154169

155170
# Cookie handling
156171
curl -c cookies.txt http://localhost:8080/cookies/set?session=abc123

echo-http/config.go

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,25 @@ type Config struct {
1212
Host string
1313
Port string
1414

15-
// OIDC Configuration
16-
OIDCClientID string
17-
OIDCClientSecret string
18-
OIDCSupportedScopes []string
19-
OIDCRequirePKCE bool
20-
OIDCSessionTTL int
21-
OIDCTokenExpiry int
22-
OIDCValidateRedirectURI bool
23-
OIDCAllowedRedirectURIs string
24-
OIDCEnableJWTSigning bool
15+
// OAuth2 Configuration (shared across all flows)
16+
AuthAllowedClientID string
17+
AuthAllowedClientSecret string
18+
AuthSupportedScopes []string
19+
AuthTokenExpiry int
20+
AuthAllowedGrantTypes []string
21+
22+
// Resource Owner Password Credentials / Basic Auth
23+
AuthAllowedUsername string
24+
AuthAllowedPassword string
25+
26+
// Authorization Code Flow Configuration
27+
AuthCodeRequirePKCE bool
28+
AuthCodeSessionTTL int
29+
AuthCodeValidateRedirectURI bool
30+
AuthCodeAllowedRedirectURIs string
31+
32+
// OIDC Configuration (id_token specific)
33+
OIDCEnableJWTSigning bool
2534
}
2635

2736
func LoadConfig() *Config {
@@ -32,16 +41,25 @@ func LoadConfig() *Config {
3241
Host: getEnv("HOST", "0.0.0.0"),
3342
Port: getEnv("PORT", "80"),
3443

35-
// OIDC settings
36-
OIDCClientID: getEnv("OIDC_CLIENT_ID", ""),
37-
OIDCClientSecret: getEnv("OIDC_CLIENT_SECRET", ""),
38-
OIDCSupportedScopes: parseScopes(getEnv("OIDC_SUPPORTED_SCOPES", "openid,profile,email")),
39-
OIDCRequirePKCE: getBoolEnv("OIDC_REQUIRE_PKCE", false),
40-
OIDCSessionTTL: getIntEnv("OIDC_SESSION_TTL", 300),
41-
OIDCTokenExpiry: getIntEnv("OIDC_TOKEN_EXPIRY", 3600),
42-
OIDCValidateRedirectURI: getBoolEnv("OIDC_VALIDATE_REDIRECT_URI", true),
43-
OIDCAllowedRedirectURIs: getEnv("OIDC_ALLOWED_REDIRECT_URIS", ""),
44-
OIDCEnableJWTSigning: getBoolEnv("OIDC_ENABLE_JWT_SIGNING", false),
44+
// OAuth2 settings (shared across all flows)
45+
AuthAllowedClientID: getEnv("AUTH_ALLOWED_CLIENT_ID", ""),
46+
AuthAllowedClientSecret: getEnv("AUTH_ALLOWED_CLIENT_SECRET", ""),
47+
AuthSupportedScopes: parseScopes(getEnv("AUTH_SUPPORTED_SCOPES", "openid,profile,email")),
48+
AuthTokenExpiry: getIntEnv("AUTH_TOKEN_EXPIRY", 3600),
49+
AuthAllowedGrantTypes: parseGrantTypes(getEnv("AUTH_ALLOWED_GRANT_TYPES", "authorization_code,client_credentials")),
50+
51+
// Resource Owner Password Credentials / Basic Auth settings
52+
AuthAllowedUsername: getEnv("AUTH_ALLOWED_USERNAME", "testuser"),
53+
AuthAllowedPassword: getEnv("AUTH_ALLOWED_PASSWORD", "testpass"),
54+
55+
// Authorization Code Flow settings
56+
AuthCodeRequirePKCE: getBoolEnv("AUTH_CODE_REQUIRE_PKCE", false),
57+
AuthCodeSessionTTL: getIntEnv("AUTH_CODE_SESSION_TTL", 300),
58+
AuthCodeValidateRedirectURI: getBoolEnv("AUTH_CODE_VALIDATE_REDIRECT_URI", false),
59+
AuthCodeAllowedRedirectURIs: getEnv("AUTH_CODE_ALLOWED_REDIRECT_URIS", ""),
60+
61+
// OIDC settings (id_token specific)
62+
OIDCEnableJWTSigning: getBoolEnv("OIDC_ENABLE_JWT_SIGNING", false),
4563
}
4664
}
4765

@@ -69,6 +87,19 @@ func parseScopes(s string) []string {
6987
return result
7088
}
7189

90+
// parseGrantTypes parses comma-separated grant types into a slice of strings.
91+
// Empty values and surrounding whitespace are trimmed.
92+
func parseGrantTypes(s string) []string {
93+
grantTypes := strings.Split(s, ",")
94+
result := make([]string, 0, len(grantTypes))
95+
for _, grantType := range grantTypes {
96+
if trimmed := strings.TrimSpace(grantType); trimmed != "" {
97+
result = append(result, trimmed)
98+
}
99+
}
100+
return result
101+
}
102+
72103
// getBoolEnv retrieves a boolean value from environment variables.
73104
// Returns true if the value is "true" or "1", false otherwise.
74105
// If the environment variable is not set or empty, returns defaultValue.

0 commit comments

Comments
 (0)