Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 14 additions & 9 deletions echo-connectrpc/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,28 @@
## Environment Variables

The server supports the following environment variables for configuration:
### Server Configuration

| Variable | Default | Description |
| -------- | --------- | ------------ |
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `8080` | Listen port |

### Protocol Control

| Variable | Default | Description |
| -------------------- | ------- | ---------------------------- |
| `HOST` | 0.0.0.0 | Host address to bind |
| `PORT` | 8080 | Port number to listen on |
| `DISABLE_CONNECTRPC` | false | Disable Connect RPC protocol |
| `DISABLE_GRPC` | false | Disable gRPC protocol |
| `DISABLE_GRPC_WEB` | false | Disable gRPC-Web protocol |
| `DISABLE_CONNECTRPC` | `false` | Disable Connect RPC protocol |
| `DISABLE_GRPC` | `false` | Disable gRPC protocol |
| `DISABLE_GRPC_WEB` | `false` | Disable gRPC-Web protocol |

### Reflection Control

| Variable | Default | Description |
| --------------------------------- | ------- | ----------------------------------------------------------- |
| `REFLECTION_INCLUDE_DEPENDENCIES` | false | Include transitive dependencies (note: not fully supported) |
| `DISABLE_REFLECTION_V1` | false | Disable gRPC reflection v1 API |
| `DISABLE_REFLECTION_V1ALPHA` | false | Disable gRPC reflection v1alpha API |
| `REFLECTION_INCLUDE_DEPENDENCIES` | `false` | Include transitive dependencies (note: not fully supported) |
| `DISABLE_REFLECTION_V1` | `false` | Disable gRPC reflection v1 API |
| `DISABLE_REFLECTION_V1ALPHA` | `false` | Disable gRPC reflection v1alpha API |

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

Expand All @@ -47,6 +50,8 @@ DISABLE_GRPC=true DISABLE_GRPC_WEB=true ./echo-connectrpc
DISABLE_REFLECTION_V1ALPHA=true ./echo-connectrpc
```

---

## Protocol

Connect RPC supports three protocols:
Expand Down
18 changes: 10 additions & 8 deletions echo-graphql/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,16 @@
> **Note:** The container listens on port 8080. When using `docker compose up`, the
> port is mapped to 14000 on the host.
## Endpoints

| Path | Description |
| ------------- | ------------------ |
| `/` | API documentation |
| `/graphql` | GraphQL endpoint |
| `/playground` | GraphQL Playground |
| `/health` | Health check |
## Environment Variables

### Server Configuration

| Variable | Default | Description |
| -------- | --------- | ------------ |
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `8080` | Listen port |

---

## Schema

Expand Down
31 changes: 23 additions & 8 deletions echo-grpc/docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@
> **Note:** The container listens on port 50051. The same port is exposed
> when using `docker compose up`.
## Environment Variables

### Server Configuration

| Variable | Default | Description |
| -------- | --------- | ------------ |
| `HOST` | `0.0.0.0` | Bind address |
| `PORT` | `50051` | Listen port |

### gRPC Reflection Configuration

| Variable | Default | Description |
| --------------------------------- | ------- | --------------------------------------------- |
| `REFLECTION_INCLUDE_DEPENDENCIES` | `false` | Include transitive dependencies in reflection |
| `DISABLE_REFLECTION_V1` | `false` | Disable gRPC reflection v1 API |
| `DISABLE_REFLECTION_V1ALPHA` | `false` | Disable gRPC reflection v1alpha API |

These flags allow testing client compatibility with different reflection API versions.

---

## Services

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

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

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

### Environment Variables

- `REFLECTION_INCLUDE_DEPENDENCIES` (default: `false`) - Include transitive dependencies in reflection responses
- `DISABLE_REFLECTION_V1` (default: `false`) - Disable gRPC reflection v1 API
- `DISABLE_REFLECTION_V1ALPHA` (default: `false`) - Disable gRPC reflection v1alpha API

These flags allow testing client compatibility with different reflection API versions.

## Metadata

Request metadata is echoed back in the `metadata` field of every response. Custom metadata can be sent using grpcurl's `-H` flag:
Expand Down
49 changes: 32 additions & 17 deletions echo-http/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ docker run -p 8080:80 ghcr.io/probitas-test/echo-http:latest

## Environment Variables

### Server Configuration

| Variable | Default | Description |
| -------- | --------- | ------------ |
| `HOST` | `0.0.0.0` | Bind address |
Expand All @@ -32,6 +34,11 @@ docker run -p 3000:3000 -e PORT=3000 ghcr.io/probitas-test/echo-http:latest
docker run -p 8080:8080 -v $(pwd)/.env:/app/.env ghcr.io/probitas-test/echo-http:latest
```

### OAuth2/OIDC Configuration

For OAuth2/OIDC functionality configuration (client validation, scopes, PKCE, etc.),
see the [Environment Variables](./docs/api.md#environment-variables) section in the API documentation.

## API

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

### Authentication Endpoints

| Endpoint | Method | Description |
| ------------------------------------------------------ | -------- | ---------------------------------------- |
| `/basic-auth/{user}/{pass}` | GET | Basic auth (200 if match, 401 otherwise) |
| `/hidden-basic-auth/{user}/{pass}` | GET | Basic auth (200 if match, 404 otherwise) |
| `/bearer` | GET | Bearer token validation |
| `/oidc/{user}/{pass}/.well-known/openid-configuration` | GET | OIDC Discovery metadata (mock) |
| `/oidc/{user}/{pass}/authorize` | GET/POST | OIDC authorization endpoint (mock) |
| `/oidc/{user}/{pass}/callback` | GET | OIDC callback handler |
| `/oidc/{user}/{pass}/token` | POST | OIDC token endpoint (mock) |
| `/oidc/{user}/{pass}/demo` | GET | Interactive OIDC flow demo (browser) |
| Endpoint | Method | Description |
| -------------- | ------ | ---------------------------------------- |
| `/basic-auth` | GET | Basic auth (200 if match, 401 otherwise) |
| `/bearer-auth` | GET | Bearer token validation (SHA1 hash) |

### OAuth2/OIDC Endpoints

| Endpoint | Method | Description |
| ----------------------------------------- | -------- | ------------------------------------------- |
| `/.well-known/oauth-authorization-server` | GET | OAuth2 Authorization Server Metadata |
| `/.well-known/openid-configuration` | GET | OIDC Discovery metadata |
| `/.well-known/jwks.json` | GET | JWKS endpoint (JSON Web Key Set) |
| `/oauth2/authorize` | GET/POST | OAuth2/OIDC authorization endpoint |
| `/oauth2/callback` | GET | OAuth2/OIDC callback handler |
| `/oauth2/token` | POST | OAuth2/OIDC token endpoint |
| `/oauth2/userinfo` | GET | UserInfo endpoint |
| `/oauth2/demo` | GET | Interactive OAuth2/OIDC flow demo (browser) |

### Cookie Endpoints

Expand Down Expand Up @@ -141,16 +155,17 @@ curl http://localhost:8080/delay/5
curl -L http://localhost:8080/redirect/3

# Basic authentication
curl -u user:pass http://localhost:8080/basic-auth/user/pass
curl -u user:pass http://localhost:8080/basic-auth

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

# OIDC interactive demo (open in browser for complete flow demonstration)
open "http://localhost:8080/oidc/testuser/testpass/demo"
# OAuth2/OIDC interactive demo (open in browser for complete flow demonstration)
open "http://localhost:8080/oauth2/demo"

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

# Cookie handling
curl -c cookies.txt http://localhost:8080/cookies/set?session=abc123
Expand Down
71 changes: 51 additions & 20 deletions echo-http/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,25 @@ type Config struct {
Host string
Port string

// OIDC Configuration
OIDCClientID string
OIDCClientSecret string
OIDCSupportedScopes []string
OIDCRequirePKCE bool
OIDCSessionTTL int
OIDCTokenExpiry int
OIDCValidateRedirectURI bool
OIDCAllowedRedirectURIs string
OIDCEnableJWTSigning bool
// OAuth2 Configuration (shared across all flows)
AuthAllowedClientID string
AuthAllowedClientSecret string
AuthSupportedScopes []string
AuthTokenExpiry int
AuthAllowedGrantTypes []string

// Resource Owner Password Credentials / Basic Auth
AuthAllowedUsername string
AuthAllowedPassword string

// Authorization Code Flow Configuration
AuthCodeRequirePKCE bool
AuthCodeSessionTTL int
AuthCodeValidateRedirectURI bool
AuthCodeAllowedRedirectURIs string

// OIDC Configuration (id_token specific)
OIDCEnableJWTSigning bool
}

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

// OIDC settings
OIDCClientID: getEnv("OIDC_CLIENT_ID", ""),
OIDCClientSecret: getEnv("OIDC_CLIENT_SECRET", ""),
OIDCSupportedScopes: parseScopes(getEnv("OIDC_SUPPORTED_SCOPES", "openid,profile,email")),
OIDCRequirePKCE: getBoolEnv("OIDC_REQUIRE_PKCE", false),
OIDCSessionTTL: getIntEnv("OIDC_SESSION_TTL", 300),
OIDCTokenExpiry: getIntEnv("OIDC_TOKEN_EXPIRY", 3600),
OIDCValidateRedirectURI: getBoolEnv("OIDC_VALIDATE_REDIRECT_URI", true),
OIDCAllowedRedirectURIs: getEnv("OIDC_ALLOWED_REDIRECT_URIS", ""),
OIDCEnableJWTSigning: getBoolEnv("OIDC_ENABLE_JWT_SIGNING", false),
// OAuth2 settings (shared across all flows)
AuthAllowedClientID: getEnv("AUTH_ALLOWED_CLIENT_ID", ""),
AuthAllowedClientSecret: getEnv("AUTH_ALLOWED_CLIENT_SECRET", ""),
AuthSupportedScopes: parseScopes(getEnv("AUTH_SUPPORTED_SCOPES", "openid,profile,email")),
AuthTokenExpiry: getIntEnv("AUTH_TOKEN_EXPIRY", 3600),
AuthAllowedGrantTypes: parseGrantTypes(getEnv("AUTH_ALLOWED_GRANT_TYPES", "authorization_code,client_credentials")),

// Resource Owner Password Credentials / Basic Auth settings
AuthAllowedUsername: getEnv("AUTH_ALLOWED_USERNAME", "testuser"),
AuthAllowedPassword: getEnv("AUTH_ALLOWED_PASSWORD", "testpass"),

// Authorization Code Flow settings
AuthCodeRequirePKCE: getBoolEnv("AUTH_CODE_REQUIRE_PKCE", false),
AuthCodeSessionTTL: getIntEnv("AUTH_CODE_SESSION_TTL", 300),
AuthCodeValidateRedirectURI: getBoolEnv("AUTH_CODE_VALIDATE_REDIRECT_URI", false),
AuthCodeAllowedRedirectURIs: getEnv("AUTH_CODE_ALLOWED_REDIRECT_URIS", ""),

// OIDC settings (id_token specific)
OIDCEnableJWTSigning: getBoolEnv("OIDC_ENABLE_JWT_SIGNING", false),
}
}

Expand Down Expand Up @@ -69,6 +87,19 @@ func parseScopes(s string) []string {
return result
}

// parseGrantTypes parses comma-separated grant types into a slice of strings.
// Empty values and surrounding whitespace are trimmed.
func parseGrantTypes(s string) []string {
grantTypes := strings.Split(s, ",")
result := make([]string, 0, len(grantTypes))
for _, grantType := range grantTypes {
if trimmed := strings.TrimSpace(grantType); trimmed != "" {
result = append(result, trimmed)
}
}
return result
}

// getBoolEnv retrieves a boolean value from environment variables.
// Returns true if the value is "true" or "1", false otherwise.
// If the environment variable is not set or empty, returns defaultValue.
Expand Down
Loading