How to Implement JWT Authentication Middleware in Kratos
Kratos provides a production-ready JWT middleware in middleware/auth/jwt/jwt.go that handles both server-side token validation and client-side token generation.
The go-kratos/kratos framework ships with a complete JSON Web Token (JWT) authentication solution that plugs directly into the middleware chain. Located in the standard library at middleware/auth/jwt/jwt.go, this implementation supports HS256, RS256, and other signing algorithms while maintaining compatibility with Kratos' transport abstraction and error handling conventions.
Understanding the Kratos JWT Middleware Architecture
The JWT middleware follows Kratos' standard middleware pattern, allowing you to attach authentication logic to HTTP and gRPC transports uniformly.
Core Components and File Structure
The implementation spans several key files:
middleware/auth/jwt/jwt.go– ContainsServer()andClient()constructors, option functions, and context helpersmiddleware/auth/jwt/jwt_test.go– Unit tests covering claim factories and error scenarioserrors/errors.go– Defineserrors.Unauthorizedconstructors used for JWT failures
The middleware uses the github.com/golang-jwt/jwt/v5 library internally and exposes configuration through functional options.
Implementing Server-Side JWT Validation
Use the jwt.Server() function to validate incoming Bearer tokens from the Authorization header. According to the source code in lines 78-123, the server middleware:
- Extracts the token from the transport context
- Parses it using
jwt.ParseWithClaims(when a claim factory is provided) orjwt.Parse - Maps validation failures to Kratos-specific errors like
ErrTokenInvalid,ErrTokenExpired, andErrUnSupportSigningMethod - Stores verified claims in the request context via
NewContext
Server Configuration Example
Define a custom claim type and configure the validation middleware:
import (
"github.com/go-kratos/kratos/v2/middleware"
"github.com/go-kratos/kratos/v2/transport/http"
"github.com/go-kratos/kratos/v2/middleware/auth/jwt"
"github.com/golang-jwt/jwt/v5"
)
type MyClaims struct {
jwt.RegisteredClaims
Role string `json:"role"`
}
func keyFunc(token *jwt.Token) (any, error) {
return []byte("my-secret-key"), nil
}
srv := http.NewServer(
http.Address(":8080"),
http.Middleware(
jwt.Server(keyFunc,
jwt.WithSigningMethod(jwt.SigningMethodHS256),
jwt.WithClaims(func() jwt.Claims { return &MyClaims{} }),
),
),
)
Configuring Client-Side JWT Generation
The jwt.Client() middleware (implemented in lines 30-64) automatically generates and signs JWTs for outgoing requests. It:
- Creates a new token with
jwt.NewWithClaims(o.signingMethod, o.claims()) - Injects custom headers via
WithTokenHeader - Signs the token using your provided keyProvider function
- Adds the resulting Bearer token to the
Authorizationheader usingtransport.FromClientContext
Client Middleware Setup
Configure the client to attach a signed JWT to every request:
func keyProvider(token *jwt.Token) (any, error) {
return []byte("my-secret-key"), nil
}
customHeader := map[string]any{"kid": "my-key-id"}
client := http.NewClient(
http.Target("http://localhost:8080"),
http.Middleware(
jwt.Client(keyProvider,
jwt.WithSigningMethod(jwt.SigningMethodHS256),
jwt.WithTokenHeader(customHeader),
),
),
)
Accessing JWT Claims in Handlers
After the server middleware validates a token, retrieve the claims inside your service handlers using FromContext. This helper (defined in lines 68-76) returns the jwt.Claims interface and a boolean indicating success.
Retrieving Claims in Service Methods
func (s *MyService) Hello(ctx context.Context, req *pb.HelloReq) (*pb.HelloResp, error) {
if claims, ok := jwt.FromContext(ctx); ok {
if myClaims, ok := claims.(*MyClaims); ok {
// Access custom fields
fmt.Printf("User role: %s\n", myClaims.Role)
}
}
return &pb.HelloResp{Message: "Hello, world!"}, nil
}
Customizing JWT Options
The middleware exposes three primary Option functions for configuration:
WithSigningMethod(method jwt.SigningMethod)– Sets the algorithm (HS256, RS256, etc.)WithClaims(f func() jwt.Claims)– Supplies a factory function returning a fresh claim instance for type-safe parsingWithTokenHeader(header map[string]any)– Adds custom JWT header entries (useful for Key ID or algorithm variants) on the client side
These options apply to both server and client middleware constructors.
Summary
- The Kratos JWT implementation resides in
middleware/auth/jwt/jwt.goand supports both server validation and client generation. - Use
jwt.Server()with a Keyfunc to validate incoming Bearer tokens and map errors toerrors.Unauthorized. - Use
jwt.Client()with a keyProvider to automatically sign and inject tokens into outgoing requests. - Configure signing algorithms, custom claims, and headers via functional options:
WithSigningMethod,WithClaims, andWithTokenHeader. - Access validated claims in handlers using
jwt.FromContext()after storing them withNewContext.
Frequently Asked Questions
How do I change the signing algorithm in Kratos JWT middleware?
Pass the desired algorithm via jwt.WithSigningMethod(). The middleware accepts any jwt.SigningMethod implementation, including jwt.SigningMethodHS256 for HMAC or jwt.SigningMethodRS256 for RSA. Ensure your Keyfunc or keyProvider returns the appropriate key type (byte slice for HS256, *rsa.PublicKey/*rsa.PrivateKey for RS256).
Where does Kratos store JWT claims after validation?
The server middleware stores claims in the request context using context.WithValue through the internal NewContext helper. Service handlers retrieve them with jwt.FromContext(ctx), which returns the claims and a boolean indicating whether a valid token was present.
Can I use custom JWT claims with the Kratos middleware?
Yes. Define a struct embedding jwt.RegisteredClaims (or implementing jwt.Claims), then pass a factory function to jwt.WithClaims(func() jwt.Claims { return &MyCustomClaims{} }). This ensures jwt.ParseWithClaims populates your custom fields during validation.
How do I handle JWT validation errors in Kratos?
The middleware automatically converts standard JWT validation errors into Kratos-specific errors such as ErrTokenInvalid, ErrTokenExpired, and ErrUnSupportSigningMethod. These are constructed using errors.Unauthorized from errors/errors.go, allowing you to handle authentication failures uniformly across HTTP and gRPC transports.
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 →