How to Implement API Request Signing Verification in Gorig
Gorig provides a ready-to-use signing middleware that validates JWT tokens from HTTP headers, verifies signatures using the tokenx service, and injects authenticated user context into Gin handlers.
The jom-io/gorig framework includes a complete API request signing verification system built on Gin middleware. This implementation handles JWT extraction, signature validation, and user context injection without requiring custom security logic in your handlers. The architecture cleanly separates token generation, storage, and request-time verification, allowing you to swap between in-memory and Redis backends without modifying business logic.
How API Request Signing Verification Works
The verification flow in httpx/mid.sign.go executes seven distinct operations for every protected request.
-
Extract the token. The
GetTokenByCtxfunction retrieves the JWT from theAuthorization: Bearer <token>header. Missing or malformed headers triggerresponse.ErrorTokenBaseInfo. -
Locate the token manager. The middleware accepts a
tokenx.ManagerType(Memory or Redis) and invokestokenx.Getto retrieve aTokenServicecontaining a generator and a manager. -
Validate token existence. The
TokenManager.GetUserIDmethod checks the token's presence in the selected store. Unknown tokens returnErrorTokenAuthFail. -
Parse and verify the JWT. The
TokenGenerator(implemented inmid/tokenx/jwt.generator.go) validates the token's signature and claims. Errors map to specificErrorToken*responses. -
Apply optional user filters. If a
userFiltermap is supplied,filterUserInfovalidates that the token's user payload contains required fields (e.g.,consts.NotNull). Failures result in a403 Forbiddenresponse. -
Set request context. On success, the middleware stores the raw token (
consts.TokenKey) and decoded user data usingapix.SetUserIDandapix.SetUserInfofor downstream handlers. -
Continue processing. Finally,
c.Next()passes control to the actual API handler.
Core Components for Request Signing
-
httpx/mid.sign.go: Contains the Gin middleware that orchestrates token extraction, validation, and context injection. -
mid/tokenx/serv.go: Factory that assembles aTokenServicewith the configured generator and manager implementations. -
mid/tokenx/jwt.generator.go: Implements JWT creation and signature verification through theGenerateandParsemethods. -
mid/tokenx/mem.manager.go: In-memory token manager that handles token recording, expiration, and user-ID lookups. -
apix/handle.go: ProvidesSetUserIDandSetUserInfohelpers for injecting user data into the Gin context. -
global/consts/consts.go: Defines token status codes (JwtTokenOK,JwtTokenExpired) and special filter values likeNotNull.
Implementing API Request Signing Verification
Configuring the Signing Middleware
Attach the middleware to your Gin router using httpx.SignDef() for in-memory storage or httpx.SignRedis() for Redis-backed sessions. For role-based access control, use httpx.SignUserDef() with a filter map that specifies required user claims.
package main
import (
"github.com/gin-gonic/gin"
"github.com/jom-io/gorig/httpx"
"github.com/jom-io/gorig/global/consts"
)
func main() {
r := gin.Default()
// Basic memory-based verification
r.Use(httpx.SignDef())
// Or with Redis backend
// r.Use(httpx.SignRedis())
// Or with user filtering: require role="admin" and non-empty dept
adminFilter := map[string]interface{}{
"role": "admin",
"dept": consts.NotNull,
}
r.Use(httpx.SignUserDef(adminFilter))
r.GET("/protected", protectedHandler)
r.Run(":8080")
}
Issuing and Recording Tokens
In your authentication endpoint, generate a JWT using the TokenGenerator and record it with the TokenManager so subsequent requests can validate against it.
package auth
import (
"github.com/gin-gonic/gin"
"github.com/jom-io/gorig/mid/tokenx"
"github.com/jom-io/gorig/utils/configure"
)
func LoginHandler(c *gin.Context) {
// ... validate credentials ...
userID := "user-123"
userInfo := map[string]interface{}{
"role": "admin",
"dept": "engineering",
}
// Get default memory service (or configure for Redis)
svc := tokenx.GetDef()
// Generate token with 7-day expiration
expire := int64(configure.GetInt("Jwt.TokenExpireAt", 604800))
token, err := svc.Generator.Generate(userID, userInfo, expire)
if err != nil {
c.JSON(500, gin.H{"error": "token generation failed"})
return
}
// Record in manager for future validation
svc.Manager.Record(token, userInfo)
c.JSON(200, gin.H{"token": token})
}
Accessing Authenticated User Data
Retrieve the validated user ID and metadata from the Gin context using the apix helpers. The signing middleware has already verified the token and injected this data before your handler executes.
package handler
import (
"github.com/gin-gonic/gin"
"github.com/jom-io/gorig/apix"
)
func ProtectedHandler(c *gin.Context) {
// Extract user data injected by Sign middleware
userID := apix.GetUserID(c)
userInfo := apix.GetUserInfo(c).(map[string]interface{})
c.JSON(200, gin.H{
"userId": userID,
"userInfo": userInfo,
"message": "Access granted to protected resource",
})
}
Summary
- Gorig's signing middleware in
httpx/mid.sign.goautomates JWT extraction and validation for Gin routers through a seven-step pipeline. - The tokenx service separates token generation (
jwt.generator.go) from storage (mem.manager.goor Redis), allowing backend swaps without code changes. - User filtering via
SignUserDefenforces role-based access control by validating claims against required fields likeconsts.NotNull. - Context injection through
apix.GetUserIDandapix.GetUserInfomakes authenticated data available to downstream handlers without repetitive validation logic.
Frequently Asked Questions
How do I switch from memory to Redis storage for tokens?
Change the middleware function from httpx.SignDef() to httpx.SignRedis() in your router configuration. The tokenx.Get function in mid/tokenx/serv.go automatically returns a TokenService configured with the appropriate manager implementation, so your token generation and validation code remains identical.
What happens when a JWT token expires?
When the TokenGenerator.Parse method in mid/tokenx/jwt.generator.go detects an expired token, it returns an error that maps to ErrorTokenExpired. The signing middleware catches this and returns an HTTP 401 response with the appropriate error code, preventing the request from reaching your handler.
Can I implement custom claim validation beyond the built-in user filter?
Yes. While httpx.SignUserDef handles basic field presence validation using consts.NotNull, you can implement custom logic by wrapping the standard middleware or by validating apix.GetUserInfo inside your handlers. For global custom validation, modify the filterUserInfo function in httpx/mid.sign.go to implement your specific business rules.
How do I retrieve the raw JWT string in my handler?
The signing middleware stores the original token string in the Gin context using the key consts.TokenKey. Access it using c.GetString(consts.TokenKey) if you need to pass the token to downstream microservices or include it in audit logs.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →