keyfunc Go Package

repository·main·Indexed 19 days ago

https://github.com/micahparks/keyfunc

A Go package providing a jwt.Keyfunc implementation for the golang-jwt/jwt/v5 library. It enables JWT verification by consuming JSON Web Key Sets (JWKS) from remote HTTPS endpoints or local JSON data, featuring automatic background key rotation and refreshing. It acts as a wrapper around the jwkset package, allowing access to underlying jwkset.Storage for advanced features like X.509 URIs and private asymmetric keys.

Tokens
1.7K
Snippets
6
Records
10
Agent score
15%

What's inside keyfunc

  1. What is keyfunc and when to use it

    main

    The keyfunc package provides a jwt.Keyfunc implementation for the github.com/golang-jwt/jwt/v5 package. It is specifically designed to consume a JSON Web Key Set (JWK Set) from an HTTPS endpoint (common in OAuth 2.0 or OpenID Connect providers like Keycloak or AWS Cognito) and use those keys to parse and verify JSON Web Tokens (JWTs).

    Note: Always ensure the JWK Set endpoint uses HTTPS to guarantee keys are retrieved from a trusted source.

  2. Create a keyfunc.Keyfunc from a remote HTTP URL

    main

    To create a keyfunc.Keyfunc from a remote JWK Set URL, use keyfunc.NewDefaultCtx. This function requires a context.Context which is used to manage and eventually end the background refresh goroutine that automatically updates the keys.

    When using keyfunc.NewDefault (or NewDefaultCtx), the JWK Set is automatically refreshed in the background using jwkset.NewDefaultHTTPClient.

    // Create the keyfunc.Keyfunc.
    // Context is used to end the refresh goroutine.
    k, err := keyfunc.NewDefaultCtx(ctx, []string{server.URL})
    if err != nil {
    	log.Fatalf("Failed to create a keyfunc.Keyfunc from the server's URL.\nError: %s", err)
    }
  3. Create a Keyfunc for JWT verification

    main

    The Keyfunc interface is designed to be used as the jwt.Keyfunc callback for the github.com/golang-jwt/jwt/v5 library. It manages a JWK Set (via jwkset.Storage) to automatically resolve and provide the correct public key for verifying JWTs based on their kid (Key ID) and alg (Algorithm) headers.

    To use it, you typically initialize a Keyfunc using one of the provided constructor functions (depending on whether your keys are in a remote HTTP endpoint or local JSON) and then pass it to the jwt.Parse or jwt.ParseWithClaims methods.

    // Example: Using Keyfunc with golang-jwt
    keyfunc, err := keyfunc.NewDefault([]string{"https://example.com/.well-known/jwks.json"})
    if err != nil {
    	log.Fatal(err)
    }
    
    token, err := jwt.Parse(tokenString, keyfunc.Keyfunc)
  4. Parse and verify JWTs using keyfunc.Keyfunc

    main

    Once you have initialized a keyfunc.Keyfunc instance (k), you can pass its .Keyfunc property directly into the jwt.Parse method from the github.com/golang-jwt/jwt/v5 package to verify a signed token.

    // Parse the JWT.
    parsed, err := jwt.Parse(signed, k.Keyfunc)
    if err != nil {
    	log.Fatalf("Failed to parse the JWT.\nError: %s", err)
    }
  5. Access underlying jwkset.Storage

    main

    Since version 3.X.X, keyfunc acts as a thin wrapper around the github.com/MicahParks/jwkset package. You can access the underlying jwkset.Storage from a keyfunc.Keyfunc instance by calling the .Storage() method.

    Accessing the storage allows you to leverage advanced features provided by jwkset, such as:

    • Automatic refresh of remote HTTP resources when an unknown key ID (kid) is encountered.
    • Support for X.509 URIs or embedded certificate chains.
    • Support for private asymmetric keys.
    • Specified key operations and usage.
  6. Configure Keyfunc via the Override struct

    main

    The Override struct allows you to fine-tune the behavior of the automatic HTTP refresh mechanism in NewDefaultOverrideCtx.

    FieldTypeDescription
    Client*http.ClientCustom HTTP client for requests
    HTTPTimeouttime.DurationTimeout for HTTP requests
    NoErrorReturnFirstHTTPReq*boolIf true, returns the first request even if it results in an error
    RateLimitWaitMaxtime.DurationMaximum time to wait for rate limiting (defaults to 1m)
    RefreshErrorHandlerFuncfunc(u string) func(ctx context.Context, err error)Custom error handler for refresh failures
    RefreshIntervaltime.DurationHow often to refresh (defaults to 1h)
    RefreshUnknownKID*rate.LimiterRate limiter for requests triggered by unknown KIDs
    ValidationSkipAllboolIf true, skips all JWK validation steps
  7. Initialize Keyfunc from local JSON data

    main

    If your JWK data is stored locally as JSON, use these functions:

    • NewJWKJSON(raw json.RawMessage): Creates a Keyfunc from a single raw JWK object.
    • NewJWKSetJSON(raw json.RawMessage): Creates a Keyfunc from a raw JWK Set (an array of JWK objects).
    // From a JWK Set JSON
    rawJSON := json.RawMessage(`{"keys": [...]} `)
    kf, err := keyfunc.NewJWKSetJSON(rawJSON)
  8. Keyfunc Interface Reference

    main

    The Keyfunc interface provides the methods required to integrate with golang-jwt/jwt/v5 and manage the underlying key storage.

    • Keyfunc(token *jwt.Token) (any, error): The standard signature required by jwt.Keyfunc. It resolves the key for a given token.
    • KeyfuncCtx(ctx context.Context) jwt.Keyfunc: Returns a jwt.Keyfunc that uses the provided context for key resolution (e.g., for storage lookups).
    • Storage() jwkset.Storage: Returns the underlying jwkset.Storage instance.
    • VerificationKeySet(ctx context.Context) (jwt.VerificationKeySet, error): Returns all keys currently in the storage as a jwt.VerificationKeySet.
  9. Initialize Keyfunc from remote HTTP JWK Sets

    main

    Use these functions to create a Keyfunc that automatically fetches and refreshes JWK Sets from remote HTTP endpoints.

    • NewDefault(urls []string): Creates a Keyfunc with default settings. It starts a background goroutine to automatically refresh the remote resources.
    • NewDefaultCtx(ctx context.Context, urls []string): Same as NewDefault, but allows providing a context.Context to control the lifecycle of the background refresh goroutine.
    • NewDefaultOverrideCtx(ctx context.Context, urls []string, override Override): Same as NewDefaultCtx, but allows customizing behaviors like RefreshInterval, HTTPTimeout, and RateLimitWaitMax via the Override struct.
    // Using NewDefaultCtx to manage lifecycle
    ctx, cancel := context.WithCancel(context.Background())
    defer cancel()
    
    kf, err := keyfunc.NewDefaultCtx(ctx, []string{"https://auth.example.com/jwks"})
  10. Error: ErrKeyfunc

    main

    The package defines a sentinel error ErrKeyfunc which is wrapped when any internal keyfunc operation fails (e.g., storage issues, JSON unmarshaling, or key resolution errors).

    var ErrKeyfunc = errors.New("failed keyfunc")