How to Implement JWT Authentication in Gorig: A Complete Guide

Gorig provides a built-in tokenx middleware package that leverages the jwt-go library to generate and validate JWT tokens using HS-256 signing, configurable via a simple secret key.

Gorig is a Go web framework that simplifies building secure APIs with its integrated authentication layer. To implement JWT authentication in Gorig, you utilize the framework's built-in tokenx package, which wraps the popular github.com/dgrijalva/jwt-go library and provides ready-to-use generators and validators wired into the configuration system.

Architecture of Gorig's JWT System

Core Components

The JWT implementation in Gorig is modular and consists of several key files:

Request Flow

  1. Configuration – Define the jwt.key secret in your configuration file.
  2. Startup – The tokenx service instantiates during application boot (see [bootstrap/startup.go](https://github.com/jom-io/gorig/blob/master/bootstrap/startup.go)), reading JwtKey to create the generator.
  3. Generate – After successful authentication, call Generate to create a signed token with custom claims.
  4. Validate – In protected handlers, call ParseToken to verify signatures, expiration, and structural integrity.
  5. Optional Revocation – Use the memory manager to invalidate tokens before natural expiry.

Configuring the JWT Secret

Before generating tokens, configure the signing secret in your config.yaml or any source that the configuration system reads:

jwt:
  key: "your-super-secret-string-min-32-characters"

The factory in [mid/tokenx/serv.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/serv.go) retrieves this value via configure.GetString("jwt.key", "") and initializes the generator.

Generating JWT Tokens

Defining Custom Claims

First, extend the standard claims with your application data in [mid/tokenx/claims.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/claims.go):

type CustomClaims struct {
    UserID string `json:"uid,omitempty"`
    Role   string `json:"role,omitempty"`
    
    jwt.StandardClaims
}

Creating the Token

The jwtGenerator in [mid/tokenx/jwt.generator.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/jwt.generator.go) provides the Generate method:

func (j *jwtGenerator) Generate(userId string, 
    userInfo map[string]interface{}, expireAt int64) (string, *errors.Error) {
    
    claims := CustomClaims{
        UserID: userId,
        Role:   fmt.Sprint(userInfo["role"]),
        StandardClaims: jwt.StandardClaims{
            ExpiresAt: expireAt,
            IssuedAt:  time.Now().Unix(),
            Issuer:    "gorig",
        },
    }

    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    signed, err := token.SignedString(j.secret)
    if err != nil {
        return "", errors.Sys("jwt sign string error", err)
    }
    return signed, nil
}

Login Handler Example

Wire the generator into your authentication flow:

func LoginHandler(c *gin.Context) {
    var req struct {
        Username string `json:"username"`
        Password string `json:"password"`
    }
    if err := c.BindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "invalid payload"})
        return
    }

    // ... verify credentials against database ...
    userID := "12345"
    roles := "admin"

    expiresAt := time.Now().Add(time.Hour).Unix()
    token, err := tokenx.NewJwtService().Generate(userID,
        map[string]interface{}{"role": roles}, expiresAt)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "token generation failed"})
        return
    }

    c.JSON(http.StatusOK, gin.H{"token": token})
}

Validating and Parsing Tokens

Token Verification

The ParseToken method in [mid/tokenx/jwt.generator.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/jwt.generator.go) validates signatures, expiration, and structural integrity:

func (j *jwtGenerator) ParseToken(tokenString string) (*CustomClaims, *errors.Error) {
    token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{},
        func(t *jwt.Token) (interface{}, error) {
            if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
                return nil, fmt.Errorf("unexpected signing method")
            }
            return j.secret, nil
        })

    if err != nil {
        if ve, ok := err.(*jwt.ValidationError); ok {
            switch {
            case ve.Errors&jwt.ValidationErrorMalformed != 0:
                return nil, errors.BadRequest("malformed token")
            case ve.Errors&jwt.ValidationErrorExpired != 0:
                return nil, errors.Unauthorized("token expired")
            case ve.Errors&jwt.ValidationErrorNotValidYet != 0:
                return nil, errors.Unauthorized("token not valid yet")
            default:
                return nil, errors.Unauthorized("invalid token")
            }
        }
        return nil, errors.Sys("jwt parse error", err)
    }

    if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
        // Optional revocation check
        if memManager.IsRevoked(claims.Id) {
            return nil, errors.Unauthorized("token revoked")
        }
        return claims, nil
    }
    return nil, errors.Unauthorized("invalid token")
}

Middleware Implementation

Protect routes using a Gin middleware that extracts the Bearer token:

func JwtAuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        authHeader := c.GetHeader("Authorization")
        if !strings.HasPrefix(authHeader, "Bearer ") {
            c.AbortWithStatusJSON(http.StatusUnauthorized,
                gin.H{"error": "missing token"})
            return
        }
        tokenStr := strings.TrimPrefix(authHeader, "Bearer ")

        claims, err := tokenx.NewJwtService().ParseToken(tokenStr)
        if err != nil {
            c.AbortWithStatusJSON(http.StatusUnauthorized,
                gin.H{"error": err.Message()})
            return
        }

        c.Set("jwtClaims", claims)
        c.Next()
    }
}

// Application setup
router := gin.Default()
router.POST("/login", LoginHandler)

protected := router.Group("/api")
protected.Use(JwtAuthMiddleware())
{
    protected.GET("/profile", ProfileHandler)
}

Managing Token Revocation

For scenarios requiring immediate token invalidation (logout or security breaches), Gorig includes an in-memory token manager in [mid/tokenx/mem.manager.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/mem.manager.go). You can store revoked token IDs and check against them during the ParseToken validation phase.

Summary

Frequently Asked Questions

What signing algorithm does Gorig use for JWT tokens?

Gorig uses HS-256 (HMAC with SHA-256) as the default signing method. The jwtGenerator struct in [mid/tokenx/jwt.generator.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/jwt.generator.go) explicitly calls jwt.NewWithClaims(jwt.SigningMethodHS256, claims) and validates the signing method during parsing to prevent algorithm confusion attacks.

How do I access JWT claims inside a protected handler?

After the JwtAuthMiddleware validates the token, it stores the *CustomClaims pointer in the Gin context using c.Set("jwtClaims", claims). Inside your handler, retrieve them with claims := c.MustGet("jwtClaims").(*tokenx.CustomClaims), then access custom fields like claims.UserID or claims.Role defined in [mid/tokenx/claims.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/claims.go).

Can I implement refresh tokens with Gorig's tokenx package?

Yes, though the package provides the building blocks rather than a complete refresh flow. You can generate long-lived refresh tokens using the same Generate() method with extended expiration times, store them in the in-memory manager ([mid/tokenx/mem.manager.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/mem.manager.go)), and validate them against the store before issuing new access tokens. For production systems, replace the in-memory store with Redis or database persistence.

Where is the JWT secret configured in a Gorig application?

The secret is defined in your configuration file (e.g., config.yaml) under the jwt.key path. The factory function in [mid/tokenx/serv.go](https://github.com/jom-io/gorig/blob/master/mid/tokenx/serv.go) retrieves this value via configure.GetString("jwt.key", "") from the global configuration system defined in [global/variable/variable.go](https://github.com/jom-io/gorig/blob/master/global/variable/variable.go). The secret is then injected into the jwtGenerator struct as a byte slice for HMAC signing.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →