gin-jwt

repository·master·Indexed 25 days ago

https://github.com/appleboy/gin-jwt

A JWT authentication middleware for the Gin web framework built on golang-jwt/jwt. It provides built-in handlers for login, refresh, and logout, supporting both Cookie and Header-based tokens. Features include RFC 6749 compliant refresh token rotation, pluggable storage with Redis support, and programmatic token generation via TokenGenerator.

Tokens
23.9K
Snippets
50
Records
91
Agent score
79%

What's inside gin-jwt

  1. Overview of Gin JWT Middleware features

    master

    Gin JWT Middleware provides:

    • Simple JWT authentication for the Gin web framework.
    • Built-in handlers for login, refresh, and logout.
    • Customizable authentication, authorization, and claims.
    • Support for both Cookie and Header-based tokens.
    • RFC 6749 compliant refresh tokens (OAuth 2.0 standard) with automatic rotation.
    • Pluggable refresh token storage (In-memory or Redis).
    • Direct token generation capabilities without requiring HTTP middleware.
    • Structured Token type with metadata.
  2. Overview of gin-jwt features

    master

    gin-jwt is a powerful and flexible JWT authentication middleware for the Gin web framework, implemented based on golang-jwt/jwt.

    Key Features:

    • Simple JWT authentication for Gin.
    • Built-in handlers for Login, Refresh, and Logout.
    • Customizable authentication, authorization, and Claims.
    • Supports both Cookie and Header-based tokens.
    • Follows RFC 6749 OAuth 2.0 standards for Refresh Tokens (using opaque tokens and server-side storage).
    • Pluggable Refresh Token storage (Memory, Redis client cache).
    • Ability to generate tokens directly without HTTP middleware.
    • Structured token types and metadata.
  3. Explore Complete Implementation Examples

    master

    The repository provides several specialized examples for different authentication scenarios:

    • Basic Authentication: Standard JWT flow including login, protected routes, and token verification.
    • OAuth 2.0 SSO Integration: Supports Google and GitHub via the Authorization Code flow. Includes CSRF protection with state tokens, dual-authentication support (httpOnly cookies + Authorization headers), and an interactive demo.
    • Token Generator: A standalone utility to generate JWT tokens without HTTP middleware, useful for service-to-service communication or programmatic testing.
    • Redis Storage: Demonstrates integrating Redis for managing refresh tokens, featuring client-side caching and automatic fallback to in-memory storage.
    • Authorization Control: Advanced access control patterns including Role-Based Access Control (RBAC) and path-based authorization using multiple middleware instances.
  4. Implement a production-ready Azure AD JWKS provider

    master

    For production Azure AD integration, do not hardcode keys. Implement a provider that dynamically fetches and caches public keys from the Azure AD JWKS endpoint (e.g., https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys).

    Best Practices:

    • Dynamic Fetching: Use a library like github.com/lestrrat-go/jwx/v2/jwk to parse JWKS.
    • Caching: Store keys in memory to avoid latency on every request.
    • Automatic Rotation: Run a background goroutine with a time.Ticker to refresh keys periodically (e.g., every hour) to handle key rotation.
    type AzureADKeyProvider struct {
        jwksURL    string
        keys       map[string]*rsa.PublicKey
        mutex      sync.RWMutex
        lastUpdate time.Time
    }
    
    // RefreshKeys fetches new keys from the JWKS endpoint
    func (p *AzureADKeyProvider) RefreshKeys() error {
        // ... implementation using jwk.Fetch ...
    }
  5. Support multiple JWT providers using KeyFunc

    master

    To accept JWT tokens from multiple sources (e.g., your own system and external providers like Azure AD, Auth0, or Google), use a single middleware instance configured with a dynamic KeyFunc callback. This allows you to inspect the token's claims (such as the iss issuer claim) before validation and select the appropriate signing key or method dynamically.

    Key Benefits:

    • Supports hybrid authentication (internal + external).
    • Enables seamless migration between authentication systems.
    • Avoids the issues of chaining multiple middlewares where the first failure might abort the request.
  6. Apply different authorization rules to different routes

    master

    There are two primary ways to apply different authorization rules to different route groups:

    1. Multiple Middleware Instances: Create separate middleware instances for different roles (e.g., adminMiddleware and userMiddleware) and apply them to specific Gin route groups.
    2. Single Authorizer with Path Logic: Use one Authorizer function that inspects c.Request.URL.Path to determine which role is required for the current path.
    // Method 1: Multiple Middleware Instances
    adminMiddleware, _ := jwt.New(&jwt.GinJWTMiddleware{
        Authorizer: func(c *gin.Context, data any) bool {
            if user, ok := data.(*User); ok {
                return user.Role == "admin"
            }
            return false
        },
    })
    
    userMiddleware, _ := jwt.New(&jwt.GinJWTMiddleware{
        Authorizer: func(c *gin.Context, data any) bool {
            if user, ok := data.(*User); ok {
                return user.Role == "user" || user.Role == "admin"
            }
            return false
        },
    })
    
    adminRoutes := r.Group("/admin", adminMiddleware.MiddlewareFunc())
    userRoutes := r.Group("/user", userMiddleware.MiddlewareFunc())
  7. Enable Redis store in gin-jwt

    master

    You can use Redis as the backend store for refresh tokens using several convenience methods on the *jwt.GinJWTMiddleware instance. If the Redis connection fails, the middleware automatically falls back to an in-memory store to ensure high availability.

    // Method 1: Default Configuration
    middleware := &jwt.GinJWTMiddleware{
        // ... other configuration
        UseRedisStore: true,
    }
    // Or using convenience method
    middleware.EnableRedisStore()
    
    // Method 2: Custom Address
    middleware.EnableRedisStoreWithAddr("localhost:6379")
    
    // Method 3: Full Options (Address, Password, DB)
    middleware.EnableRedisStoreWithOptions("localhost:6379", "password", 0)
    
    // Method 4: Custom Configuration object
    config := store.DefaultRedisConfig()
    config.Addr = "localhost:6379"
    config.CacheSize = 128 * 1024 * 1024 // 128MB
    middleware.EnableRedisStoreWithConfig(config)
  8. Explore Gin JWT usage examples

    master

    The repository provides several specialized implementation examples:

    • Basic Authentication: Standard JWT flow with login, protected routes, and token verification.
    • OAuth 2.0 SSO Integration: Supports Google and GitHub using the Authorization Code flow, CSRF protection via state tokens, and dual-authentication (httpOnly cookies + Authorization headers).
    • Token Generator: A way to generate JWT tokens programmatically without using the HTTP middleware (useful for service-to-service communication or testing).
    • Redis Storage: Demonstrates integrating Redis for managing refresh tokens, including client-side caching and automatic fallback to in-memory storage.
    • Authorization Control: Advanced patterns including Role-Based Access Control (RBAC), path-based authorization, and managing multiple middleware instances.
  9. Implement the Login Request Flow

    master

    To implement a login endpoint, use the provided LoginHandler. You must provide an Authenticator and can optionally provide a PayloadFunc and LoginResponse.

    1. Authenticator (Required): A function that verifies user credentials (e.g., checking a password against a database). It must return a struct or map containing user data to be embedded in the JWT.
    2. PayloadFunc (Optional): Converts the data returned by the Authenticator into jwt.MapClaims. It must include an IdentityKey (default: "identity"). You can also set standard RFC 7519 claims like sub, iss, aud, nbf, iat, and jti.
    3. LoginResponse (Optional): Called after successful authentication and token creation. It receives a *core.Token object. Use this to return the token response to the user.
    PayloadFunc: func(data any) jwt.MapClaims {
        if user, ok := data.(*User); ok {
            return jwt.MapClaims{
                "sub":      user.ID,              // Standard: Subject (user ID)
                "iss":      "my-app",             // Standard: Issuer
                "aud":      "my-api",             // Standard: Audience
                "identity": user.UserName,        // Custom claim
                "role":     user.Role,            // Custom claim
            }
        }
        return jwt.MapClaims{}
    }
  10. Refresh tokens with RefreshHandler

    master

    The RefreshHandler manages token rotation following OAuth 2.0 security best practices. It automatically extracts the refresh_token from the following sources in order of priority:

    1. Cookie: The cookie named via RefreshTokenCookieName (default: "refresh_token").
    2. POST Form: The refresh_token form field.
    3. Query Parameter: The refresh_token query string parameter.
    4. JSON Body: The refresh_token field in the request body.

    If the refresh token is valid, the handler creates a new access token and a new refresh token (token rotation), revokes the old refresh token, and sets new cookies if SendCookie is enabled.

    RefreshResponse (Optional): Called after a successful refresh. It receives a *core.Token object. You should return a JSON response containing access_token, token_type, expires_in, and refresh_token to follow the RFC 6749 format.

    Function Signature for RefreshResponse: func(c *gin.Context, token *core.Token)