Skip to main content

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

import "github.com/go-mizu/mizu/middlewares/oidc"

Quick Start

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

FieldTypeDescription
Provider*ProviderOIDC provider
ClientIDstringClient ID
ClientSecretstringClient secret
RedirectURLstringCallback URL
Scopes[]stringRequested scopes

Examples

Google OIDC

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

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

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

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

// 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

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 CaseDescriptionExpected Behavior
TestNewBasic middleware initialization without tokenReturns 401 Unauthorized
TestWithValidTokenValid token with correct issuer, audience, and expirationReturns 200 OK, claims accessible via GetClaims
TestExpiredTokenToken with expiration time in the pastReturns 401 Unauthorized
TestInvalidIssuerToken with incorrect issuer claimReturns 401 Unauthorized
TestInvalidAudienceToken with incorrect audience claimReturns 401 Unauthorized
TestSkipPathsConfigured paths that bypass authenticationSkipped paths return 200 OK without token, protected paths require token
TestCustomTokenExtractorCustom token extraction from query parametersSuccessfully authenticates using token from query string
TestCustomOnErrorCustom error handler configurationReturns custom error response (403 Forbidden)
TestClaimsHasAudienceString and array audience validationCorrectly identifies audience in both string and array formats
TestClaimsHasGroupGroup membership validationCorrectly identifies user group membership
TestClaimsHasRoleRole membership validationCorrectly identifies user role membership
TestRequireGroupGroup-based authorization middlewareAllows access with required group, denies without (403 Forbidden)
TestRequireScopeScope-based authorization middlewareAllows access with required scope, denies without (403 Forbidden)
TestInvalidTokenMalformed token formatReturns 401 Unauthorized
  • oauth2 - OAuth 2.0 authentication
  • jwt - JWT validation
  • session - Session management