> ## Documentation Index
> Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# OIDC

> OpenID Connect authentication middleware for identity provider integration.

## Overview

The `oidc` middleware provides OpenID Connect authentication, extending OAuth 2.0 with standardized identity tokens and user information endpoints.

Use it when you need:

* Enterprise SSO integration
* Standardized identity claims
* ID token validation

## Installation

```go theme={null}
import "github.com/go-mizu/mizu/middlewares/oidc"
```

## Quick Start

```go theme={null}
app := mizu.New()

// Configure OIDC provider
provider, _ := oidc.NewProvider("https://accounts.google.com")

config := oidc.Config{
    Provider:     provider,
    ClientID:     "your-client-id",
    ClientSecret: "your-client-secret",
    RedirectURL:  "http://localhost:3000/callback",
    Scopes:       []string{"openid", "email", "profile"},
}

app.Get("/login", oidc.Login(config))
app.Get("/callback", oidc.Callback(config, handleUser))
```

## Configuration

### Config

| Field          | Type        | Description      |
| -------------- | ----------- | ---------------- |
| `Provider`     | `*Provider` | OIDC provider    |
| `ClientID`     | `string`    | Client ID        |
| `ClientSecret` | `string`    | Client secret    |
| `RedirectURL`  | `string`    | Callback URL     |
| `Scopes`       | `[]string`  | Requested scopes |

## Examples

### Google OIDC

```go theme={null}
provider, _ := oidc.NewProvider("https://accounts.google.com")

config := oidc.Config{
    Provider:     provider,
    ClientID:     os.Getenv("GOOGLE_CLIENT_ID"),
    ClientSecret: os.Getenv("GOOGLE_CLIENT_SECRET"),
    RedirectURL:  "http://localhost:3000/auth/callback",
    Scopes:       []string{"openid", "email", "profile"},
}

app.Get("/auth/login", oidc.Login(config))
app.Get("/auth/callback", oidc.Callback(config, func(c *mizu.Ctx, claims *oidc.Claims) error {
    // claims.Subject - User ID
    // claims.Email - User email
    // claims.Name - User name
    return c.Redirect(302, "/dashboard")
}))
```

### Auth0

```go theme={null}
provider, _ := oidc.NewProvider("https://your-tenant.auth0.com/")

config := oidc.Config{
    Provider:     provider,
    ClientID:     os.Getenv("AUTH0_CLIENT_ID"),
    ClientSecret: os.Getenv("AUTH0_CLIENT_SECRET"),
    RedirectURL:  "http://localhost:3000/callback",
    Scopes:       []string{"openid", "email", "profile"},
}
```

### Keycloak

```go theme={null}
provider, _ := oidc.NewProvider("https://keycloak.example.com/realms/myrealm")

config := oidc.Config{
    Provider:     provider,
    ClientID:     "my-app",
    ClientSecret: os.Getenv("KEYCLOAK_SECRET"),
    RedirectURL:  "http://localhost:3000/callback",
    Scopes:       []string{"openid", "email", "roles"},
}
```

### Token Validation Middleware

```go theme={null}
verifier := oidc.NewVerifier(provider, oidc.VerifierConfig{
    ClientID: "your-client-id",
})

// Protect routes with ID token
app.Use(oidc.Verify(verifier))

app.Get("/api/me", func(c *mizu.Ctx) error {
    claims := oidc.GetClaims(c)
    return c.JSON(200, claims)
})
```

## API Reference

### Functions

```go theme={null}
// NewProvider creates OIDC provider from issuer URL
func NewProvider(issuer string) (*Provider, error)

// Login starts OIDC flow
func Login(config Config) mizu.Handler

// Callback handles OIDC callback
func Callback(config Config, handler func(*mizu.Ctx, *Claims) error) mizu.Handler

// Verify creates ID token verification middleware
func Verify(verifier *Verifier) mizu.Middleware

// GetClaims returns claims from context
func GetClaims(c *mizu.Ctx) *Claims
```

### Standard Claims

```go theme={null}
type Claims struct {
    Subject           string   // sub
    Issuer            string   // iss
    Audience          []string // aud
    Email             string   // email
    EmailVerified     bool     // email_verified
    Name              string   // name
    PreferredUsername string   // preferred_username
    Picture           string   // picture
    ExpiresAt         time.Time
}
```

## Technical Details

### Token Verification Process

The OIDC middleware implements a comprehensive JWT token verification process:

1. **Token Extraction**: Tokens are extracted from the `Authorization` header using the Bearer scheme by default. A custom `TokenExtractor` function can be provided for alternative extraction methods (e.g., from query parameters or cookies).

2. **Token Structure Validation**: The token is split into three parts (header, payload, signature) and validated for correct JWT format.

3. **Header Decoding**: The JWT header is decoded to extract the algorithm (`alg`), key ID (`kid`), and token type (`typ`).

4. **Claims Decoding**: The payload is decoded into standard OIDC claims including issuer, subject, audience, expiration, and custom claims.

5. **Validation Checks**:
   * **Issuer Validation**: Verifies the token was issued by the expected OIDC provider
   * **Audience Validation**: Ensures the token is intended for this application (supports both string and array audiences)
   * **Expiration Check**: Validates the token has not expired using the `exp` claim
   * **Not Before Check**: Validates the token is valid using the `nbf` claim if present

6. **Context Storage**: Validated claims are stored in the request context for downstream handlers to access via `GetClaims()`.

### Claims Structure

The middleware supports both standard OIDC claims and custom claims:

* **Standard Claims**: `iss`, `sub`, `aud`, `exp`, `iat`, `nbf`, `email`, `name`
* **Authorization Claims**: `groups`, `roles`, `scope`
* **Raw Claims**: All claims are also stored in a `Raw` map for accessing custom provider-specific claims

### Authorization Helpers

Three specialized middleware functions provide fine-grained access control:

* **RequireGroup**: Validates the user belongs to a specific group (checks `groups` claim)
* **RequireRole**: Validates the user has a specific role (checks `roles` claim)
* **RequireScope**: Validates the token includes a specific OAuth scope (checks space-delimited `scope` claim)

### Error Handling

The middleware provides customizable error handling through the `OnError` callback:

* **Default Behavior**: Returns a 401 Unauthorized JSON response with error details
* **Custom Handler**: Can be configured to log errors, return custom responses, or redirect to login

### Path Skipping

The `SkipPaths` option allows certain routes to bypass authentication (e.g., health checks, public endpoints) while keeping the middleware globally applied.

## Best Practices

* Use OIDC discovery (/.well-known/openid-configuration)
* Validate ID tokens for security
* Store only necessary claims in sessions
* Implement proper logout with end\_session\_endpoint
* Configure appropriate `RefreshInterval` for JWKS key rotation
* Use `SkipPaths` for public endpoints instead of conditional middleware application
* Implement custom `OnError` handlers for security-sensitive logging
* Leverage `RequireGroup`, `RequireRole`, and `RequireScope` for authorization

## Testing

The OIDC middleware includes comprehensive test coverage for various scenarios:

| Test Case                  | Description                                               | Expected Behavior                                                        |
| -------------------------- | --------------------------------------------------------- | ------------------------------------------------------------------------ |
| `TestNew`                  | Basic middleware initialization without token             | Returns 401 Unauthorized                                                 |
| `TestWithValidToken`       | Valid token with correct issuer, audience, and expiration | Returns 200 OK, claims accessible via GetClaims                          |
| `TestExpiredToken`         | Token with expiration time in the past                    | Returns 401 Unauthorized                                                 |
| `TestInvalidIssuer`        | Token with incorrect issuer claim                         | Returns 401 Unauthorized                                                 |
| `TestInvalidAudience`      | Token with incorrect audience claim                       | Returns 401 Unauthorized                                                 |
| `TestSkipPaths`            | Configured paths that bypass authentication               | Skipped paths return 200 OK without token, protected paths require token |
| `TestCustomTokenExtractor` | Custom token extraction from query parameters             | Successfully authenticates using token from query string                 |
| `TestCustomOnError`        | Custom error handler configuration                        | Returns custom error response (403 Forbidden)                            |
| `TestClaimsHasAudience`    | String and array audience validation                      | Correctly identifies audience in both string and array formats           |
| `TestClaimsHasGroup`       | Group membership validation                               | Correctly identifies user group membership                               |
| `TestClaimsHasRole`        | Role membership validation                                | Correctly identifies user role membership                                |
| `TestRequireGroup`         | Group-based authorization middleware                      | Allows access with required group, denies without (403 Forbidden)        |
| `TestRequireScope`         | Scope-based authorization middleware                      | Allows access with required scope, denies without (403 Forbidden)        |
| `TestInvalidToken`         | Malformed token format                                    | Returns 401 Unauthorized                                                 |

## Related Middlewares

* [oauth2](/middlewares/oauth2) - OAuth 2.0 authentication
* [jwt](/middlewares/jwt) - JWT validation
* [session](/middlewares/session) - Session management
