What is JWT? JWT is an open standard (RFC 7519) used to securely transfer information between parties. It is
JWT (JSON Web Token) Technical Guide
Published: 2025-08-23 (a year ago)
GOJWT

What is JWT?

JWT is an open standard (RFC 7519) used to securely transfer information between parties. It is a compact, URL-secure token commonly used for authentication and information exchange.

In modern web applications, JWT has become the preferred solution for stateless authentication, especially suitable for microservice architectures and API services.

JWT Structure

The JWT consists of three parts, separated by dots (.):

Copy
header.payload.signature

1. Header

Contains token type and signature algorithm information:

json Copy
{
  "alg": "HS256",
  "typ": "JWT"
}

2. Payload

Contains claims, i.e. the data that is actually to be transferred:

json Copy
{
  "sub": "1234567890",
  "name": "username",
  "role": "admin",
  "iat": 1516239022,
  "exp": 1516242622
}

3. Signature

Used to verify the integrity of the token:

Copy
HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)

Common Claim Types

Standard Statement

  • 'iss' (issuer): issuer
  • 'sub' (subject): Subject
  • 'aud' (audience): Audience
  • 'exp' (expiration): Expiration time
  • 'iat' (issued at): The time of issue
  • 'nbf' (not before): effective time

Custom Statements

Any custom fields can be added, such as user roles, permissions, etc.

Advantages of JWT

  • Stateless: The server does not need to store session information
  • Cross-Domain Support: Can be used between different domains
  • Mobile-Friendly: Suitable for mobile apps and APIs
  • Good Performance: Avoids database queries
  • Standardization: Based on open standards

Usage Scenarios

1. Identity authentication

The user logs in to obtain the JWT and subsequently requests to carry this token for authentication.

2. Information exchange

Securely transfer information between different services.

3. Single Sign-On (SSO)

Log in once, and multiple apps share the authentication status.

Security Considerations

Storage security

  • Avoid storing in localStorage (XSS risk)
  • httpOnly cookies are recommended
  • Consider using sessionStorage

Token Security

  • Set a reasonable expiration time
  • Sign with a strong key
  • Consider the token refresh mechanism
  • Implement token blacklists

Transmission Security

  • Always use HTTPS
  • Transfer in the Authorization header
  • Avoid transferring tokens in URLs

Project Architecture Design

Dual token mechanism

This project adopts a dual-token architecture of Access Token + Refresh Token:

  • Access Token: Short-term validity (configured expiration time) for API access authentication
  • Refresh Token: Long-term validity (configured expiration time) to refresh the Access Token

Core Components

1. Configuration management

yaml Copy
jwt:
  access_expire: 24# hours
  refresh_expire: 168 # hours (7 days)
  access_secret: "your-access-secret"
  refresh_secret: "your-refresh-secret"
  issuer: "your-app-name"

2. Declare the structural design

go Copy
Access Token statement
type AccessClaims struct {
    UserID   uint   `json:"user_id"`
    Username string `json:"username"`
    Role     string `json:"role"`
    jwt. RegisteredClaims
}

Refresh Token statement
type RefreshClaims struct {
    UserID uint `json:"user_id"`
    jwt. RegisteredClaims
}

Security features

1. Dual-key design

  • Access Token and Refresh Token use different signing keys
  • Reduce the risk of key compromise
  • Support for independent key rotation policies

2. Token blacklist mechanism

go Copy
Add a token to the blacklist
func AddToBlacklist(token string, expiration time. Duration) error {
    key := "blacklist:" + token
    return redis. Set(key, "1", expiration). Err()
}

Check if the token is on the blacklist
func IsBlacklisted(token string) bool {
    key := "blacklist:" + token
    _, err := redis. Get(key). Result()
    return err == nil
}

3. Geolocation tracking

Record user IP and geographical location information when logging in to enhance security auditing capabilities.

Middleware implementation

1. Basic certification middleware

go Copy
func AuthMiddleware() gin. HandlerFunc {
    return func(c *gin. Context) {
        token := c.GetHeader("Authorization")
        if token == "" {
            c.JSON(401, gin. H{"error": "Token not provided"})
            c.Abort()
            return
        }
        
        Validate the token
        claims, err := ValidateToken(token)
        if err != nil {
            c.JSON(401, gin. H{"error": "Invalid token"})
            c.Abort()
            return
        }
        
        Check the blacklist
        if IsBlacklisted(token) {
            c.JSON(401, gin. H{"error": "Token has expired"})
            c.Abort()
            return
        }
        
        c.Set("user_id", claims. UserID)
        c.Next()
    }
}

2. Privilege control middleware

go Copy
func RequireRole(requiredRole string) gin. HandlerFunc {
    return func(c *gin. Context) {
        userRole, exists := c.Get("user_role")
        if !exists {
            c.JSON(403, gin. H{"error": "Insufficient permissions"})
            c.Abort()
            return
        }
        
        if userRole != requiredRole {
            c.JSON(403, gin. H{"error": "Insufficient Role Privileges"})
            c.Abort()
            return
        }
        
        c.Next()
    }
}

3. Token refresh middleware

  • Verify the validity of the Refresh Token
  • Check the token blacklist status
  • Extract user identification information
  • Prepare for token refreshes

API Design Patterns

1. Login process

go Copy
func Login(username, password string) (*TokenPair, error) {
    Verify user credentials
    user, err := ValidateCredentials(username, password)
    if err != nil {
        return nil, err
    }
    
    Generate an Access Token
    accessToken, err := GenerateAccessToken(user.ID, user. Role)
    if err != nil {
        return nil, err
    }
    
    Generate Refresh Token
    refreshToken, err := GenerateRefreshToken(user.ID)
    if err != nil {
        return nil, err
    }
    
    return &TokenPair{
        AccessToken:  accessToken,
        RefreshToken: refreshToken,
    }, nil
}

2. Token refresh process

go Copy
func RefreshToken(refreshToken string) (*TokenPair, error) {
    Verify the Refresh Token
    claims, err := ValidateRefreshToken(refreshToken)
    if err != nil {
        return nil, err
    }
    
    Check the blacklist
    if IsBlacklisted(refreshToken) {
        return nil, errors. New("Token Expired")
    }
    
    Get the latest user information
    user, err := GetUserByID(claims. UserID)
    if err != nil {
        return nil, err
    }
    
    Generate a new token pair
    newAccessToken, _ := GenerateAccessToken(user.ID, user. Role)
    newRefreshToken, _ := GenerateRefreshToken(user.ID)
    
    Add old tokens to the blacklist
    AddToBlacklist(refreshToken, time. Hour*24*7)
    
    return &TokenPair{
        AccessToken:  newAccessToken,
        RefreshToken: newRefreshToken,
    }, nil
}

3. Cancel the process

go Copy
func Logout(accessToken, refreshToken string) error {
    Parse tokens to get expiration time
    accessClaims, _ := ParseToken(accessToken)
    refreshClaims, _ := ParseToken(refreshToken)
    
    Calculate the remaining valid time
    accessTTL := time. Until(accessClaims.ExpiresAt.Time)
    refreshTTL := time. Until(refreshClaims.ExpiresAt.Time)
    
    Add to the blacklist
    AddToBlacklist(accessToken, accessTTL)
    AddToBlacklist(refreshToken, refreshTTL)
    
    return nil
}

Implement best practices

1. Token lifecycle management

go Copy
Token generation example
func GenerateAccessToken(userID uint, role string) (string, error) {
    claims := AccessClaims{
        UserID: userID,
        Role:   role,
        RegisteredClaims: jwt. RegisteredClaims{
            ExpiresAt: jwt. NewNumericDate(time. Now(). Add(time. Hour * 24)),
            IssuedAt:  jwt. NewNumericDate(time. Now()),
            Issuer:    "your-app",
        },
    }
    
    token := jwt. NewWithClaims(jwt. SigningMethodHS256, claims)
    return token. SignedString([]byte("your-secret"))
}

2. Error handling strategy

go Copy
type APIError struct {
    Code    int    `json:"code"`
    Message string `json:"message"`
    Details string `json:"details,omitempty"`
}

func HandleJWTError(err error) APIError {
    switch {
    case errors. Is(err, jwt. ErrTokenExpired):
        return APIError{Code: 401, Message: "Token expired"}
    case errors. Is(err, jwt. ErrTokenMalformed):
        return APIError{Code: 401, Message: "Token Malform"}
    default:
        return APIError{Code: 401, Message: "Authentication failed"}
    }
}

3. Performance optimization

  • Redis caches user information
  • Token parsing result caching
  • Bulk token validation
  • Asynchronous logging

4. Monitoring and auditing

  • Log in behavior logs
  • Abnormal access detection
  • Token usage statistics
  • Geolocation anomaly alerts

Common Problems and Solutions

Q: How to deal with token leaks?

Solution:

  • Implement Redis blacklist mechanism
  • Set a reasonable token expiration time
  • Monitor for anomalous IPs and geolocation access
  • Allow users to actively log out of all devices

Q: What are the advantages of the dual-token mechanism?

Advantage:

  • Access Token is effective in the short term, reducing the risk of leakage
  • Refresh Token is valid for a long time, enhancing user experience
  • Separate key and expiration policies
  • Supports fine-grained permission control

Q: How to implement cross-device login management?

Implementation method:

  • The token contains device identification information
  • Cache storage of the user's active device list
  • Support remote device logout
  • Limit on the number of devices that can be configured

Q: What are the performance optimization recommendations?

Optimization Strategy:

  • Caching user permission information
  • Token pre-validation mechanism
  • Bulk token operation processing
  • Asynchronous status updates

Q: How do I deal with clock offset issues?

Solution:

  • Set a reasonable clock offset tolerance
  • Synchronize server time using NTP
  • Added time buffer in token validation
  • Monitor server time synchronization status

Project Features and Advantages

1. Architectural advantages

  • Dual Token Design: Balancing security with user experience
  • Configurable Management: Flexible expiration time and key configuration
  • Middleware Mode: Unified authentication and authorization processing
  • Redis Integration: High-performance token state management

2. Safety features

  • Multi-Layer Verification: Token validity + blacklist check + role permissions
  • Geolocation Tracking: Enhance security auditing capabilities
  • Key Separation: Access and Refresh Tokens use different keys
  • Progressive Expiration: Supports elegant token renewals

3. O&M friendly

  • Detailed Logs: Complete authentication and authorization logging
  • Error Handling: Unified error response and exception handling
  • Monitoring Support: Built-in performance and safety monitoring points
  • Scalability: Supports multiple authentication methods and permission models