### Install go-oidc module Source: https://github.com/luikyv/go-oidc/blob/main/README.md Use the go get command to add the library to your project. ```bash go get github.com/luikyv/go-oidc@latest ``` -------------------------------- ### Install pkgsite for Documentation Source: https://github.com/luikyv/go-oidc/blob/main/CONTRIBUTING.md Install the 'pkgsite' tool, which is required to view the project's documentation. This command uses 'go install' to fetch the latest version. ```bash go install golang.org/x/pkgsite/cmd/pkgsite@latest ``` -------------------------------- ### Run Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/01-provider-api.md Starts an HTTP server on the given address. ```APIDOC ## func (op *Provider) Run(address string, middlewares ...goidc.MiddlewareFunc) error ### Description Starts an HTTP server on the given address. ### Parameters - **address** (string) - Required - Server address (e.g., ":8080" or "localhost:8080"). - **middlewares** (...goidc.MiddlewareFunc) - Optional - HTTP middlewares applied to all endpoints. ### Returns - **error** - Error if the server fails to start or encounters a runtime error. ``` -------------------------------- ### RP Metadata Choices JSON Examples Source: https://github.com/luikyv/go-oidc/blob/main/README.md Examples of client registration metadata with priority lists and the corresponding server resolution response. ```json { "redirect_uris": ["https://client.example.com/callback"], "id_token_signing_alg_values_supported": ["PS256", "RS256", "ES256"] } ``` ```json { "client_id": "s6BhdRkqt3", "redirect_uris": ["https://client.example.com/callback"], "id_token_signed_response_alg": "PS256" } ``` -------------------------------- ### MakeToken Usage Example Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/01-provider-api.md Demonstrates how to call MakeToken with a populated grant object. ```go token, err := op.MakeToken(ctx, &goidc.Grant{ ID: "grant-123", Subject: "user@example.com", ClientID: "client-123", Scopes: "openid profile", }) ``` -------------------------------- ### JAR Discovery Response Example Source: https://github.com/luikyv/go-oidc/blob/main/README.md Example of the discovery response fields added when JAR is enabled. ```json { "request_parameter_supported": true, "request_object_signing_alg_values_supported": ["RS256", "PS256"] } ``` -------------------------------- ### Example usage of provider.New Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/01-provider-api.md Demonstrates initializing a Provider with a generated RSA key and a custom JWKS function. ```go import ( "context" "crypto/rand" "crypto/rsa" goidc "github.com/luikyv/go-oidc/pkg/goidc" "github.com/luikyv/go-oidc/pkg/provider" ) key, _ := rsa.GenerateKey(rand.Reader, 2048) jwks := goidc.JSONWebKeySet{ Keys: []goidc.JSONWebKey{{ KeyID: "key_id", Key: key, Algorithm: "RS256", }}, } op, err := provider.New( "http://localhost", nil, func(_ context.Context) (goidc.JSONWebKeySet, error) { return jwks, nil }, ) ``` -------------------------------- ### Run the provider directly Source: https://github.com/luikyv/go-oidc/blob/main/README.md Starts the provider on the specified port using the default runner. ```go op.Run(":80") ``` -------------------------------- ### Generate Project Documentation Source: https://github.com/luikyv/go-oidc/blob/main/CONTRIBUTING.md After installing 'pkgsite', run this command to generate the project's documentation. This relies on the 'make' utility. ```bash make docs ``` -------------------------------- ### Initialize and run an OIDC provider Source: https://github.com/luikyv/go-oidc/blob/main/README.md Create a new provider instance with a JWKS and start the server on a specified port. ```go key, _ := rsa.GenerateKey(rand.Reader, 2048) jwks := goidc.JSONWebKeySet{ Keys: []goidc.JSONWebKey{{ KeyID: "key_id", Key: key, Algorithm: "RS256", }}, } op, _ := provider.New( "http://localhost", nil, func(_ context.Context) (goidc.JSONWebKeySet, error) { return jwks, nil }, ) op.Run(":80") ``` -------------------------------- ### Implement simple username/password authentication Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of a policy that handles login form rendering and credential validation. ```go policy := goidc.NewPolicy( "basic_auth", func(r *http.Request, as *goidc.AuthnSession, c *goidc.Client) bool { // Always apply this policy return true }, func(w http.ResponseWriter, r *http.Request, as *goidc.AuthnSession, c *goidc.Client) (goidc.Status, error) { username := r.PostFormValue("username") password := r.PostFormValue("password") // First request: show login form if username == "" { renderLoginForm(w) return goidc.StatusPending, nil } // Validate credentials if !validatePassword(username, password) { return goidc.StatusFailure, errors.New("invalid credentials") } // Authentication succeeded as.Subject = username as.GrantedScopes = "openid profile" return goidc.StatusSuccess, nil }, ) op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithAuthCodeGrant(manager, goidc.ResponseTypeCode), provider.WithPolicies(policy), ) ``` -------------------------------- ### Configure Token Options Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using WithTokenOptions to set token lifetimes based on client ID. ```go provider.WithTokenOptions(func(ctx context.Context, grant *goidc.Grant, client *goidc.Client) goidc.TokenOptions { // Use longer lifetime for certain clients lifetime := 3600 if client.ID == "trusted_client" { lifetime = 7200 } return goidc.NewJWTTokenOptions(goidc.RS256, lifetime) }) ``` -------------------------------- ### Run Provider Server Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/00-index.md Starts the provider server using either the built-in runner or a custom HTTP mux. ```go op.Run(":8080") ``` ```go mux := http.NewServeMux() mux.Handle("/", op.Handler()) http.ListenAndServe(":8080", mux) ``` -------------------------------- ### Implement multi-step authentication Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of a policy using the session store to manage state across multiple authentication steps. ```go policy := goidc.NewPolicy( "mfa_auth", func(r *http.Request, as *goidc.AuthnSession, c *goidc.Client) bool { return true }, func(w http.ResponseWriter, r *http.Request, as *goidc.AuthnSession, c *goidc.Client) (goidc.Status, error) { // Initialize session store if empty if as.Store == nil { as.Store = make(map[string]any) } step, _ := as.Store["step"].(string) if step == "" { // Step 1: Collect username username := r.PostFormValue("username") if username == "" { renderUsernameForm(w) return goidc.StatusPending, nil } if !userExists(username) { return goidc.StatusFailure, errors.New("user not found") } // Store progress and show MFA form as.Store["step"] = "mfa" as.Store["username"] = username renderMFAForm(w) return goidc.StatusPending, nil } if step == "mfa" { // Step 2: Verify MFA code username, _ := as.Store["username"].(string) code := r.PostFormValue("code") if !verifyMFACode(username, code) { return goidc.StatusFailure, errors.New("invalid mfa code") } as.Subject = username as.GrantedScopes = "openid profile" return goidc.StatusSuccess, nil } return goidc.StatusFailure, errors.New("unknown step") }, ) ``` -------------------------------- ### Implement Token Options Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/04-provider-options.md Example usage of WithTokenOptions to return JWT options with RS256 signing and a 3600-second lifetime. ```go provider.WithTokenOptions(func(ctx context.Context, grant *goidc.Grant, client *goidc.Client) goidc.TokenOptions { return goidc.NewJWTTokenOptions(goidc.RS256, 3600) }) ``` -------------------------------- ### Define and Register an Authentication Policy Source: https://github.com/luikyv/go-oidc/blob/main/README.md Creates a new policy with a setup function that always returns true and an authentication function that validates a username from a POST form. The policy is then registered with the provider using provider.WithPolicies. ```go policy := goidc.NewPolicy( "main_policy", func(_ *http.Request, _ *goidc.AuthnSession, _ *goidc.Client) bool { return true }, func(w http.ResponseWriter, r *http.Request, as *goidc.AuthnSession, _ *goidc.Client) (goidc.Status, error) { username := r.PostFormValue("username") if username == "" { renderHTMLPage(w) return goidc.StatusPending, nil } if username == "banned_user" { return goidc.StatusFailure, errors.New("the user is banned") } as.Subject = username return goidc.StatusSuccess, nil }, ) op, _ := provider.New( ..., provider.WithAuthCodeGrant(manager, goidc.ResponseTypeCode), provider.WithPolicies(policy), ..., ) ``` -------------------------------- ### Handle Dynamic Client Registration Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using WithDCRClientHandler to validate and set default client metadata. ```go provider.WithDCRClientHandler(func(ctx context.Context, id string, meta *goidc.ClientMeta) error { // Validate sector identifier URI if meta.SectorIdentifierURI != "" && !isValidURI(meta.SectorIdentifierURI) { return goidc.NewError(goidc.ErrorCodeInvalidClientMetadata, "invalid sector identifier URI") } // Set default values if meta.TokenAuthnMethod == "" { meta.TokenAuthnMethod = goidc.AuthnMethodClientSecretBasic } return nil }) ``` -------------------------------- ### Run OIDC Provider with Default Server Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Starts the built-in HTTP server on the specified address with default timeouts and mux settings. ```go op.Run(":8080") ``` -------------------------------- ### Run Provider Server Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/01-provider-api.md Starts an HTTP server on the specified address. This is a blocking call that returns an error if the server fails. ```go func (op *Provider) Run(address string, middlewares ...goidc.MiddlewareFunc) error ``` ```go if err := op.Run(":80"); err != nil { log.Fatal(err) } ``` -------------------------------- ### PublishSSFEvent Usage Example Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/01-provider-api.md Demonstrates how to publish a CAEP session revoked event to an event stream. ```go err := op.PublishSSFEvent(ctx, "stream-123", goidc.SSFEvent{ Type: goidc.SSFEventTypeCAEPSessionRevoked, Subject: goidc.SSFSubject{ Format: goidc.SSFSubjectFormatEmail, Email: "user@example.com", }, }) ``` -------------------------------- ### Run Test Coverage Source: https://github.com/luikyv/go-oidc/blob/main/CONTRIBUTING.md Execute this command to check the test coverage for the project. Ensure you have the 'make' utility installed. ```bash make test-coverage ``` -------------------------------- ### Implement Audit Logging for Grants Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using a grant handler to perform audit logging upon grant creation. ```go provider.WithGrantHandler(func(ctx context.Context, gt goidc.GrantType, grant *goidc.Grant) error { auditLog.Info("Grant created", "grant_id", grant.ID, "grant_type", gt, "subject", grant.Subject, "scopes", grant.Scopes, ) return nil }) ``` -------------------------------- ### Implement Redis JTI Consumer Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example implementation of JTI replay protection using Redis to track consumed tokens. ```go provider.WithJTIConsumer(func(ctx context.Context, jti string) error { // Check if JTI was already used exists, err := redisClient.Exists(ctx, "jti:"+jti) if err != nil { return err } if exists { return errors.New("jti already consumed") } // Record JTI as used (with expiry) err = redisClient.Set(ctx, "jti:"+jti, true, 10*time.Minute) return err }) ``` -------------------------------- ### GET /.well-known/ssf-configuration Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Retrieves the Shared Signals Framework (SSF) configuration. ```APIDOC ## GET /.well-known/ssf-configuration ### Description Retrieves the configuration details for the Shared Signals Framework (SSF 1.0). ### Method GET ### Endpoint /.well-known/ssf-configuration ### Response #### Success Response (200) - **issuer** (string) - The issuer URL - **jwks_uri** (string) - The JWKS URI - **events_supported** (array) - List of supported event types - **delivery_methods_supported** (array) - List of supported delivery methods - **event_stream_management_endpoint** (string) - Stream management endpoint - **event_polling_endpoint** (string) - Event polling endpoint - **event_verification_endpoint** (string) - Event verification endpoint #### Response Example { "issuer": "http://localhost", "jwks_uri": "http://localhost/ssf/jwks", "events_supported": [ "https://schemas.openid.net/secevent/caep/event-type/session-revoked", "https://schemas.openid.net/secevent/caep/event-type/credential-change" ], "delivery_methods_supported": ["urn:ietf:rfc:8935", "urn:ietf:rfc:8936"], "event_stream_management_endpoint": "http://localhost/ssf/stream", "event_polling_endpoint": "http://localhost/ssf/poll", "event_verification_endpoint": "http://localhost/ssf/verify" } ``` -------------------------------- ### Implement Error Logging Callback Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using a custom error handler to log OIDC errors. ```go provider.WithErrorHandler(func(ctx context.Context, err error) { logger.WithError(err).Error("OIDC error") }) ``` -------------------------------- ### Define AuthnPolicy structures Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Core structures for defining authentication policies, including setup and authentication function signatures. ```go type AuthnPolicy struct { ID string // Unique policy identifier Setup SetupAuthnFunc // Decides if policy applies to current request Authenticate AuthnFunc // Performs authentication work } type SetupAuthnFunc func( *http.Request, *AuthnSession, *Client ) bool type AuthnFunc func( http.ResponseWriter, *http.Request, *AuthnSession, *Client ) (Status, error) type Status string const ( StatusSuccess Status = "success" StatusPending Status = "pending" StatusFailure Status = "failure" ) ``` -------------------------------- ### GET /.well-known/openid-configuration Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Retrieves the OpenID Connect discovery document containing configuration details for the provider. ```APIDOC ## GET /.well-known/openid-configuration ### Description OpenID Connect discovery endpoint (RFC 5789) that returns the provider's configuration metadata. ### Method GET ### Endpoint /.well-known/openid-configuration ### Response #### Success Response (200) - **issuer** (string) - The issuer URL - **authorization_endpoint** (string) - The authorization endpoint URL - **token_endpoint** (string) - The token endpoint URL - **userinfo_endpoint** (string) - The userinfo endpoint URL - **jwks_uri** (string) - The JWKS URI - **registration_endpoint** (string) - The registration endpoint URL - **introspection_endpoint** (string) - The introspection endpoint URL - **revocation_endpoint** (string) - The revocation endpoint URL - **response_types_supported** (array) - Supported response types - **response_modes_supported** (array) - Supported response modes - **grant_types_supported** (array) - Supported grant types - **subject_types_supported** (array) - Supported subject types - **id_token_signing_alg_values_supported** (array) - Supported ID token signing algorithms - **scope_values_supported** (array) - Supported scope values - **claims_supported** (array) - Supported claims - **request_parameter_supported** (boolean) - Whether request parameter is supported - **request_object_signing_alg_values_supported** (array) - Supported request object signing algorithms - **request_uri_parameter_supported** (boolean) - Whether request URI parameter is supported - **pushed_authorization_request_endpoint** (string) - Pushed authorization request endpoint URL - **require_pushed_authorization_requests** (boolean) - Whether PAR is required - **dpop_signing_alg_values_supported** (array) - Supported DPoP signing algorithms - **mtls_endpoint_aliases** (object) - mTLS endpoint aliases - **backchannel_authentication_endpoint** (string) - Backchannel authentication endpoint URL - **backchannel_token_delivery_modes_supported** (array) - Supported backchannel token delivery modes - **backchannel_user_code_parameter_supported** (boolean) - Whether backchannel user code parameter is supported - **device_authorization_endpoint** (string) - Device authorization endpoint URL #### Response Example { "issuer": "http://localhost", "authorization_endpoint": "http://localhost/authorize", "token_endpoint": "http://localhost/token", "userinfo_endpoint": "http://localhost/userinfo", "jwks_uri": "http://localhost/jwks", "registration_endpoint": "http://localhost/register", "introspection_endpoint": "http://localhost/introspect", "revocation_endpoint": "http://localhost/revoke", "response_types_supported": ["code", "id_token", "token"], "response_modes_supported": ["query", "fragment"], "grant_types_supported": ["authorization_code", "refresh_token", "implicit"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["RS256"], "scope_values_supported": ["openid", "profile", "email"], "claims_supported": ["sub", "name", "email"], "request_parameter_supported": true, "request_object_signing_alg_values_supported": ["RS256"], "request_uri_parameter_supported": true, "pushed_authorization_request_endpoint": "http://localhost/par", "require_pushed_authorization_requests": false, "dpop_signing_alg_values_supported": ["ES256"], "mtls_endpoint_aliases": { "token_endpoint": "https://mtls.localhost/token" }, "backchannel_authentication_endpoint": "http://localhost/bc-authorize", "backchannel_token_delivery_modes_supported": ["poll", "ping"], "backchannel_user_code_parameter_supported": true, "device_authorization_endpoint": "http://localhost/device_authorization" } ``` -------------------------------- ### Resource Indicators in Token Response Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Example JSON structure for a token response containing resource indicators. ```json { "access_token": "token", "aud": ["https://api.example.com"], "resource": "https://api.example.com" } ``` -------------------------------- ### GET /authorize Error Response Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Example of an error response returned via HTTP 302 redirect. ```http HTTP/1.1 302 Found Location: https://client.example.com/callback?error=invalid_request&error_description=Missing%20state%20parameter&state=abc123 ``` -------------------------------- ### GET /authorize Success Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Examples of HTTP 302 redirects for different authorization response types. ```http HTTP/1.1 302 Found Location: https://client.example.com/callback?code=auth_code&state=abc123 ``` ```http HTTP/1.1 302 Found Location: https://client.example.com/callback#id_token=eyJhbGc...&state=abc123 ``` ```http HTTP/1.1 302 Found Location: https://client.example.com/callback#access_token=token_value&token_type=Bearer&state=abc123 ``` -------------------------------- ### GET /register/{client_id} Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Reads the metadata for a registered client. ```APIDOC ## GET /register/{client_id} ### Description DCR client read endpoint. ### Method GET ### Endpoint /register/{client_id} ### Parameters #### Path Parameters - **client_id** (string) - Required - The ID of the client to retrieve ### Request Headers - **Authorization** (string) - Required - Bearer {registration_access_token} ``` -------------------------------- ### Implement Simple Logout Policy Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Demonstrates creating a logout policy and registering it with the provider. ```go logoutPolicy := goidc.NewLogoutPolicy( "simple_logout", func(r *http.Request, ls *goidc.LogoutSession, c *goidc.Client) bool { return true }, func(w http.ResponseWriter, r *http.Request, ls *goidc.LogoutSession) (goidc.Status, error) { // Clear session/cookies if any clearUserSession(w) return goidc.StatusSuccess, nil }, ) op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithLogout(manager, func(w http.ResponseWriter, r *http.Request, ls *goidc.LogoutSession) error { w.WriteHeader(http.StatusNoContent) return nil }), provider.WithLogoutPolicies(logoutPolicy), ) ``` -------------------------------- ### GET /device_authorization Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Device authorization endpoint for RFC 8628. ```APIDOC ## GET /device_authorization ### Description Device authorization endpoint. ### Method GET ### Endpoint /device_authorization ### Parameters #### Query Parameters - **client_id** (string) - Required - The client identifier. - **scope** (string) - Optional - Requested scopes. - **audience** (string) - Optional - Intended audience. ``` -------------------------------- ### GET /device Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Device verification endpoint for RFC 8628. ```APIDOC ## GET /device ### Description Device verification endpoint. ### Method GET ### Endpoint /device ### Parameters #### Query Parameters - **user_code** (string) - Required - The user code presented at device. ``` -------------------------------- ### Enable RP Metadata Choices in Provider Source: https://github.com/luikyv/go-oidc/blob/main/README.md Use the WithRPMetadataChoices option when initializing the provider to support priority-ordered algorithm lists. ```go op, _ := provider.New( ..., provider.WithDCR(manager), provider.WithRPMetadataChoices(), ..., ) ``` -------------------------------- ### GET /.well-known/openid-federation Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Retrieves the Entity Configuration for OpenID Federation 1.1. ```APIDOC ## GET /.well-known/openid-federation ### Description Retrieves the Entity Configuration as a JWT for OpenID Federation 1.1. ### Method GET ### Endpoint /.well-known/openid-federation ### Response #### Success Response (200) - **Content-Type** (string) - application/entity-statement+jwt #### Response Example HTTP/1.1 200 OK Content-Type: application/entity-statement+jwt eyJhbGciOiJSUzI1NiJ9... ``` -------------------------------- ### GET /device_authorization Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md JSON responses for device authorization requests. ```json { "device_code": "device_code_value", "user_code": "ABC1234", "verification_uri": "http://localhost:8080/device", "verification_uri_complete": "http://localhost:8080/device?user_code=ABC1234", "expires_in": 300, "interval": 5 } ``` ```json HTTP/1.1 400 Bad Request Content-Type: application/json { "error": "invalid_request", "error_description": "Missing client_id" } ``` -------------------------------- ### mTLS Endpoint Aliases Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Example of mTLS endpoint aliases published in discovery. ```json { "mtls_endpoint_aliases": { "token_endpoint": "https://mtls.example.com/token", "introspection_endpoint": "https://mtls.example.com/introspect", "revocation_endpoint": "https://mtls.example.com/revoke" } } ``` -------------------------------- ### Enable PKCE Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/04-provider-options.md Enables PKCE support for the provider. ```go func WithPKCE(methods ...goidc.CodeChallengeMethod) Option ``` -------------------------------- ### JWKS Endpoint Response Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Example response from the JSON Web Key Set endpoint. ```http HTTP/1.1 200 OK Content-Type: application/json { "keys": [ { "kty": "RSA", "alg": "RS256", "use": "sig", "kid": "key-1", "n": "...", "e": "AQAB" } ] } ``` -------------------------------- ### Token Endpoint Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Examples of successful and error responses for the POST /token endpoint. ```http HTTP/1.1 200 OK Content-Type: application/json Cache-Control: no-store { "access_token": "access_token_value", "token_type": "Bearer", "expires_in": 3600, "refresh_token": "refresh_token_value", "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImtleTEifQ.eyJpc3MiOiJodHRwOi8vbG9jYWxob3N0IiwiYXVkIjoiY2xpZW50LTEyMyIsInN1YiI6InVzZXIuMTAxMCIsImlhdCI6MTYyMzA0MTE2MCwiZXhwIjoxNjIzMDQ0NzYwLCJub25jZSI6ImFiYzEyMyJ9.signature" } ``` ```http HTTP/1.1 400 Bad Request Content-Type: application/json { "error": "invalid_grant", "error_description": "Authorization code is invalid or expired" } ``` -------------------------------- ### Initialize OpenID Connect Provider Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/00-index.md Creates a new provider instance with RSA signing keys, grant configurations, and custom authentication policies. ```go import ( "crypto/rand" "crypto/rsa" goidc "github.com/luikyv/go-oidc/pkg/goidc" "github.com/luikyv/go-oidc/pkg/provider" ) // Generate RSA key for signing key, _ := rsa.GenerateKey(rand.Reader, 2048) // Create JWKS jwks := goidc.JSONWebKeySet{ Keys: []goidc.JSONWebKey{{ KeyID: "key-1", Key: key, Algorithm: goidc.RS256, }}, } // Create provider op, err := provider.New( "http://localhost:8080", nil, // Uses in-memory grant manager by default func(_ context.Context) (goidc.JSONWebKeySet, error) { return jwks, nil }, provider.WithAuthCodeGrant(nil, goidc.ResponseTypeCode), provider.WithRefreshTokenGrant(nil), provider.WithPolicies(goidc.NewPolicy( "simple", func(r *http.Request, as *goidc.AuthnSession, c *goidc.Client) bool { return true }, func(w http.ResponseWriter, r *http.Request, as *goidc.AuthnSession, c *goidc.Client) (goidc.Status, error) { username := r.PostFormValue("username") if username == "" { renderLoginForm(w) return goidc.StatusPending, nil } as.Subject = username return goidc.StatusSuccess, nil }, )), ) if err != nil { panic(err) } ``` -------------------------------- ### GET /device Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md HTML responses for device verification success and error states. ```html Device authorization successful. You may close this window. ``` ```http HTTP/1.1 400 Bad Request Content-Type: text/html Invalid or expired user code. ``` -------------------------------- ### UserInfo Endpoint Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Examples of successful JSON and signed JWT responses from the UserInfo endpoint. ```http HTTP/1.1 200 OK Content-Type: application/json { "sub": "user.1010", "name": "John Doe", "email": "john@example.com", "email_verified": true, "given_name": "John", "family_name": "Doe" } ``` ```http HTTP/1.1 200 OK Content-Type: application/jwt eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9... ``` -------------------------------- ### CIBA Authentication Request Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Examples of successful and error responses for the POST /bc-authorize endpoint. ```http HTTP/1.1 200 OK Content-Type: application/json { "auth_req_id": "5ae62c6d-e5ec-48f9-85d7-48cf38d3adcc", "expires_in": 60, "interval": 5 } ``` ```http HTTP/1.1 400 Bad Request Content-Type: application/json { "error": "invalid_request", "error_description": "Missing scope" } ``` -------------------------------- ### Pushed Authorization Request Responses Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Examples of successful and error responses for the POST /par endpoint. ```http HTTP/1.1 201 Created Content-Type: application/json { "request_uri": "urn:example:bwc4QrDjnI6R1yNqNWpDZw8Z2PEKv3nH2K84jMsCuKI", "expires_in": 60 } ``` ```http HTTP/1.1 400 Bad Request Content-Type: application/json { "error": "invalid_request", "error_description": "Missing response_type" } ``` -------------------------------- ### Enable DPoP in Provider Source: https://github.com/luikyv/go-oidc/blob/main/README.md Configure DPoP support during provider initialization using the WithDPoP option. ```go op, _ := provider.New( ..., provider.WithDPoP(goidc.ES256), ..., ) ``` -------------------------------- ### DPoP Proof JWT Structure Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Example of the DPoP proof JWT header and payload structure. ```json { "typ": "dpop+jwt", "alg": "ES256", "jwk": { "kty": "EC", "crv": "P-256", "x": "...", "y": "..." } } { "jti": "unique-id", "htm": "POST", "htu": "https://server.example.com/token", "iat": 1623041160 } ``` -------------------------------- ### Configure Provider with JWKS Source: https://github.com/luikyv/go-oidc/blob/main/README.md Initializes a provider with a JWKS function returning both private and public key material. ```go key, _ := rsa.GenerateKey(rand.Reader, 2048) jwks := goidc.JSONWebKeySet{ Keys: []goidc.JSONWebKey{{ KeyID: "key_id", Key: key, Algorithm: "RS256", }}, } op, _ := provider.New( goidc.ProfileOpenID, "http://localhost", func(_ context.Context) (goidc.JSONWebKeySet, error) { return jwks, nil }, ) ``` -------------------------------- ### Register a new client via POST /register Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Submit client metadata to register a new client. ```json { "client_name": "Example Client", "application_type": "web", "redirect_uris": ["https://client.example.com/callback"], "token_endpoint_auth_method": "client_secret_basic", "grant_types": ["authorization_code", "refresh_token"] } ``` -------------------------------- ### GET /jwks Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Retrieves the JSON Web Key Set (JWKS) used for token validation. ```APIDOC ## GET /jwks ### Description Retrieves the JSON Web Key Set (JWKS) endpoint. ### Method GET ### Endpoint /jwks ### Response #### Success Response (200) - **keys** (array) - List of public keys ``` -------------------------------- ### Enable Rich Authorization Requests (RAR) Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Configure the provider to support specific RAR types during initialization. ```go op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithRAR("payment_initiation", "account_information"), ) ``` -------------------------------- ### GET /authorize Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/05-endpoints.md Initiates an authorization request as defined in RFC 6749 and OpenID Connect 1.0. ```APIDOC ## GET /authorize ### Description Authorization endpoint for initiating OIDC flows. ### Method GET ### Endpoint /authorize ### Parameters #### Query Parameters - **response_type** (string) - Required - Requested response type. - **client_id** (string) - Required - The client identifier. - **redirect_uri** (string) - Required - The client's redirect URI. - **scope** (string) - Conditional - Requested scopes. - **state** (string) - Recommended - Opaque value to maintain state. - **nonce** (string) - Conditional - Required for ID token responses. - **response_mode** (string) - Optional - Response mode. - **code_challenge** (string) - Conditional - PKCE code challenge. - **code_challenge_method** (string) - Optional - PKCE method. - **prompt** (string) - Optional - User interaction prompt. - **max_age** (integer) - Optional - Maximum age of authentication. - **login_hint** (string) - Optional - Hint to pre-select account. - **id_token_hint** (string) - Optional - Previously issued ID token. - **acr_values** (string) - Optional - Requested authentication context class references. - **display** (string) - Optional - Display mode. - **claims** (object) - Optional - Claims request object. - **authorization_details** (array) - Optional - Fine-grained authorization details. - **resource** (string or array) - Optional - Resource URI indicators. - **dpop_jkt** (string) - Optional - DPoP proof JWK thumbprint. - **request** (string) - Optional - Signed authorization request. - **request_uri** (string) - Optional - Reference to request object. ``` -------------------------------- ### Enable PKCE in Provider Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Configures the OIDC provider to support specific PKCE challenge methods during initialization. ```go op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithPKCE(goidc.CodeChallengeMethodSHA256, goidc.CodeChallengeMethodPlain), ) ``` -------------------------------- ### Configure High-Security Multi-Tenant Provider Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/00-index.md Sets up a robust provider instance supporting advanced features like OpenID Federation, SSF, and mTLS for multi-tenant environments. ```go op, _ := provider.New( issuer, customManager, jwksFunc, provider.WithAuthCodeGrant(manager, goidc.ResponseTypeCode), provider.WithRefreshTokenGrant(manager), provider.WithPKCE(goidc.CodeChallengeMethodSHA256), provider.WithDPoP(goidc.ES256), provider.WithMTLS(mtlsURL, clientCertFunc), provider.WithJWTBearerGrant(jwtBearerHandler), provider.WithTokenExchangeGrant(tokenExchangeHandler), provider.WithOpenIDFederation(nil, fedJWKSFunc, []string{}, []string{trustAnchor}), provider.WithSSF(ssfJWKSFunc, ssfReceiverFunc), provider.WithRARDetailsComparator(rarComparator), provider.WithVerifyClientSecretFunc(bcryptVerifier), provider.WithJTIConsumer(redisJTIConsumer), ) ``` -------------------------------- ### Configure Simple Public Provider Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/00-index.md Initializes a basic OIDC provider using in-memory defaults, suitable for simple public-facing applications. ```go op, _ := provider.New( issuer, nil, // In-memory default jwksFunc, provider.WithAuthCodeGrant(nil, goidc.ResponseTypeCode), provider.WithScopes(goidc.ScopeOpenID, goidc.ScopeProfile), provider.WithPolicies(basicAuthPolicy), ) ``` -------------------------------- ### Enable SSF in Provider Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Configure the provider with SSF support, including JWKS, receiver identification, event types, and delivery methods. ```go op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithSSF( func(_ context.Context) (goidc.JSONWebKeySet, error) { return ssfJWKS, nil }, func(ctx context.Context) (goidc.SSFReceiver, error) { receiverID, _ := extractReceiverFromContext(ctx) return goidc.SSFReceiver{ID: receiverID}, nil }, ), provider.WithSSFEventTypes( goidc.SSFEventTypeCAEPSessionRevoked, goidc.SSFEventTypeCAEPCredentialChange, ), provider.WithSSFDeliveryMethods( goidc.SSFDeliveryMethodPoll, goidc.SSFDeliveryMethodPush, ), ) ``` -------------------------------- ### Implement Context-Aware Token Options Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Demonstrates checking context cancellation before performing expensive operations in a callback. ```go type TokenOptionsFunc func( ctx context.Context, grant *Grant, client *Client ) TokenOptions // Implementation: func myTokenOptions(ctx context.Context, grant *goidc.Grant, client *goidc.Client) goidc.TokenOptions { // Check context before expensive operations select { case <-ctx.Done(): return goidc.TokenOptions{} // Context cancelled default: } // Proceed with logic... return goidc.NewJWTTokenOptions(goidc.RS256, 3600) } ``` -------------------------------- ### Initialize OpenID Federation Provider Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Configures a new provider instance with OpenID Federation support, including trust anchors and client registration types. ```go op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithOpenIDFederation( nil, // signerJWKS (nil = fetch via HTTP) func(_ context.Context) (goidc.JSONWebKeySet, error) { return fedJWKS, nil }, []string{}, // subordinates (URLs of intermediate entities) []string{"https://trust-anchor.example.com"}, // trust anchors ), provider.WithOpenIDFedClientRegistrationTypes( goidc.ClientRegistrationTypeAutomatic, goidc.ClientRegistrationTypeExplicit, ), ) ``` -------------------------------- ### Add Custom ID Token Claims Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using WithIDTokenClaims to inject custom claims into an ID token. ```go provider.WithIDTokenClaims(func(ctx context.Context, grant *goidc.Grant) map[string]any { return map[string]any{ "acr": "urn:example:loa:2", "roles": []string{"admin", "user"}, "tenant_id": grant.Store["tenant_id"], } }) ``` -------------------------------- ### Configure Dynamic Client Registration Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/04-provider-options.md Enables RFC 7591 Dynamic Client Registration with a specified manager. ```go func WithDCR(manager goidc.DCRManager) Option ``` -------------------------------- ### Create a new authentication policy Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Constructor function for initializing an AuthnPolicy instance. ```go func NewPolicy( id string, setupFunc SetupAuthnFunc, authnFunc AuthnFunc ) AuthnPolicy ``` -------------------------------- ### WithPKCE Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/04-provider-options.md Enables PKCE (RFC 7636). ```APIDOC ## WithPKCE ### Signature `func WithPKCE(methods ...goidc.CodeChallengeMethod) Option` ### Description Enables PKCE support for the provider. ``` -------------------------------- ### Configure Custom HTTP Server Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Provides full control over server timeouts and routing by using the provider's handler with a custom http.Server instance. ```go mux := http.NewServeMux() mux.Handle("/", op.Handler(myMiddleware)) server := &http.Server{ Addr: ":8080", Handler: mux, ReadTimeout: 5 * time.Second, WriteTimeout: 30 * time.Second, IdleTimeout: 60 * time.Second, } server.ListenAndServe() ``` -------------------------------- ### Implement Store Pattern for Custom Data Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Demonstrates passing custom data through the Store field during authentication and retrieving it during token issuance. ```go // During authentication as.Store["tenant_id"] = extractTenantID(r) as.Store["user_metadata"] = fetchUserMetadata(username) // During token issuance provider.WithTokenClaims(func(ctx context.Context, token *goidc.Token, grant *goidc.Grant) map[string]any { return map[string]any{ "tenant_id": grant.Store["tenant_id"], "user_metadata": grant.Store["user_metadata"], } }) ``` -------------------------------- ### Implement Custom Storage Manager Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Define a custom struct implementing the storage interface and inject it during provider initialization. ```go type CustomGrantManager struct { db *database.Connection } func (m *CustomGrantManager) SaveGrant(ctx context.Context, grant *goidc.Grant) error { return m.db.InsertOrUpdate("grants", grant) } func (m *CustomGrantManager) Grant(ctx context.Context, id string) (*goidc.Grant, error) { grant := &goidc.Grant{} if err := m.db.Get("grants", id, grant); err != nil { if err == database.ErrNotFound { return nil, goidc.ErrNotFound } return nil, err } return grant, nil } op, _ := provider.New( "http://localhost", &CustomGrantManager{db: dbConnection}, jwksFunc, ) ``` -------------------------------- ### Enable Resource Indicators Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/07-advanced-features.md Register supported resource URIs with the provider. ```go op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithResourceIndicators( "https://api.example.com", "https://ledger.example.com", ), ) ``` -------------------------------- ### Handle JWT Bearer Assertion Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using WithJWTBearerGrant to parse, validate, and extract claims from a JWT bearer assertion. ```go provider.WithJWTBearerGrant(func(ctx context.Context, assertion string) (goidc.JWTBearerResult, error) { // Parse and validate JWT claims := jwt.MapClaims{} token, err := jwt.ParseWithClaims(assertion, claims, func(token *jwt.Token) (interface{}, error) { kid := token.Header["kid"].(string) return getPublicKeyByID(kid) }) if err != nil || !token.Valid { return goidc.JWTBearerResult{}, errors.New("invalid assertion") } // Extract and validate required claims subject, _ := claims["sub"].(string) if subject == "" { return goidc.JWTBearerResult{}, errors.New("missing subject claim") } return goidc.JWTBearerResult{ Subject: subject, Store: map[string]any{ "assertion_claims": claims, }, }, nil }) ``` -------------------------------- ### Add Custom Access Token Claims Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/06-policies-callbacks.md Example of using WithTokenClaims to inject custom claims into a JWT access token. ```go provider.WithTokenClaims(func(ctx context.Context, token *goidc.Token, grant *goidc.Grant) map[string]any { return map[string]any{ "tenant_id": grant.Store["tenant_id"], "organization": grant.Store["org"], "permissions": grant.Store["permissions"], } }) ``` -------------------------------- ### Configure RP-initiated logout Source: https://github.com/luikyv/go-oidc/blob/main/README.md Defines a logout policy and initializes the provider with logout support. ```go logoutPolicy := goidc.NewLogoutPolicy( "main_logout_policy", func(_ *http.Request, _ *goidc.LogoutSession, _ *goidc.Client) bool { return true }, func(w http.ResponseWriter, _ *http.Request, _ *goidc.LogoutSession, _ *goidc.Client) (goidc.Status, error) { w.WriteHeader(http.StatusNoContent) return goidc.StatusSuccess, nil }, ) op, _ := provider.New( "http://localhost", manager, jwksFunc, provider.WithLogout(manager, func(w http.ResponseWriter, _ *http.Request, _ *goidc.LogoutSession) error { w.WriteHeader(http.StatusNoContent) return nil }), provider.WithLogoutPolicies(logoutPolicy), ) ``` -------------------------------- ### Configure DPoP Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/04-provider-options.md Enables Demonstrating Proof-of-Possession (RFC 9449) with optional signature algorithms. ```go func WithDPoP(sigAlgs ...goidc.SignatureAlgorithm) Option ``` -------------------------------- ### Configure Refresh Token Grant Source: https://github.com/luikyv/go-oidc/blob/main/_autodocs/04-provider-options.md Enables the refresh token grant, requiring an existing authorization code grant setup. ```go func WithRefreshTokenGrant(manager goidc.RefreshTokenManager) Option ``` ```go provider.WithRefreshTokenGrant(manager) ``` -------------------------------- ### Configure JWT-Secured Authorization Request (JAR) Source: https://github.com/luikyv/go-oidc/blob/main/README.md Enable JAR support using provider.WithJAR. Encryption can be enabled separately using provider.WithJAREncryption. ```go op, _ := provider.New( ..., provider.WithJAR(goidc.RS256, goidc.PS256), ..., ) ``` ```go provider.WithJAREncryption(goidc.RSA_OAEP_256) ``` -------------------------------- ### Set Additional Federation Options Source: https://github.com/luikyv/go-oidc/blob/main/README.md Configures miscellaneous federation settings including signature algorithms, chain depth, organization name, and custom HTTP clients. ```go provider.WithOpenIDFedSignatureAlgs(goidc.RS256, goidc.PS256) provider.WithOpenIDFedTrustChainMaxDepth(5) provider.WithOpenIDFedOrganizationName("Example Organization") provider.WithOpenIDFedHTTPClientFunc(func(_ context.Context) *http.Client { return customHTTPClient }) ``` -------------------------------- ### GET /userinfo Source: https://github.com/luikyv/go-oidc/blob/main/README.md The UserInfo endpoint returns claims about the authenticated subject. It requires an active access token with the 'openid' scope and must satisfy any proof-of-possession binding. ```APIDOC ## GET /userinfo ### Description Returns claims about the authenticated subject. The access token must be active, include the 'openid' scope, and satisfy any proof-of-possession binding such as DPoP or mTLS. ### Method GET ### Endpoint /userinfo ```