Middleware
Middleware in Okapi allows you to intercept and process HTTP requests before they reach your route handlers. This is useful for authentication, logging, request validation, and more.
Built-in Middleware
Basic Authentication
auth := okapi.BasicAuth{
Username: "admin",
Password: "password",
Realm: "Restricted",
ContextKey: "user", // where to store the username (default: "username")
}
// Global middleware
o.Use(auth.Middleware)
// Route-specific middleware
o.Get("/admin", adminHandler).Use(auth.Middleware)
CORS Middleware
cors := okapi.Cors{
AllowedOrigins: []string{"http://localhost:8080", "https://example.com"},
AllowedHeaders: []string{"Content-Type", "Authorization"},
}
o := okapi.New(okapi.WithCors(cors))
JWT Middleware
Okapi includes powerful JWT middleware to secure your routes with JSON Web Tokens.
Features
- HS256 symmetric signing via
SigningSecret - RS256 and other asymmetric algorithms via
RSAKey - Remote JWKS discovery via
JwksUrl(e.g., OIDC or Auth0) - Local JWKS via
JwksFile - Claims validation with
ClaimsExpressionorValidateClaims - OpenAPI integration with
.WithBearerAuth() - Selective claim forwarding using
ForwardClaims
Basic HS256 Authentication
jwtAuth := okapi.JWTAuth{
SigningSecret: []byte("supersecret"), // Shared secret for HS256
TokenLookup: "header:Authorization", // Token source
ContextKey: "user", // Key for storing claims in context
}
Remote JWKS (OIDC, Auth0)
jwtAuth := okapi.JWTAuth{
JwksUrl: "https://example.com/.well-known/jwks.json",
TokenLookup: "header:Authorization",
ContextKey: "user",
}
Claims Expression
Use ClaimsExpression to validate claims using simple expressions:
Supported Functions
Equals(field, value)Prefix(field, prefix)Contains(field, val1, val2, ...)OneOf(field, val1, val2, ...)
Logical Operators
!— NOT&&— AND||— OR
jwtAuth := okapi.JWTAuth{
SigningSecret: []byte("supersecret"),
ClaimsExpression: "Equals(`email_verified`, `true`) && Equals(`user.role`, `admin`)",
TokenLookup: "header:Authorization",
ContextKey: "user",
}
Forwarding Claims to Context
jwtAuth.ForwardClaims = map[string]string{
"email": "user.email",
"role": "user.role",
"name": "user.name",
}
Access claims in your handler:
func whoAmIHandler(c *okapi.Context) error {
email := c.GetString("email")
if email == "" {
return c.AbortUnauthorized("Unauthorized", fmt.Errorf("user not authenticated"))
}
return c.JSON(http.StatusOK, okapi.M{
"email": email,
"role": c.GetString("role"),
"name": c.GetString("name"),
})
}
Custom Claim Validation
jwtAuth.ValidateClaims = func(c *Context, claims jwt.Claims) error {
mapClaims, ok := claims.(jwt.MapClaims)
if !ok {
return errors.New("invalid claims type")
}
if emailVerified, _ := mapClaims["email_verified"].(bool); !emailVerified {
return errors.New("email not verified")
}
if role, _ := mapClaims["role"].(string); role != "admin" {
return errors.New("unauthorized role")
}
return nil
}
Custom Error Handling
auth := okapi.JWTAuth{
Audience: "okapi.example.com",
SigningSecret: SigningSecret,
OnUnauthorized: func(c *okapi.Context) error {
return c.ErrorUnauthorized("Unauthorized")
},
}
Protecting Routes
// Apply middleware globally
o.Use(jwtAuth.Middleware)
// Protect specific group
admin := o.Group("/admin", jwtAuth.Middleware).
WithBearerAuth() // Adds Bearer auth to OpenAPI docs
admin.Get("/users", adminGetUsersHandler)
// Route-specific middleware
o.Get("/protected", protectedHandler).Use(jwtAuth.Middleware)
Custom Middleware
Create your own middleware functions:
func customMiddleware(next okapi.HandlerFunc) okapi.HandlerFunc {
return func(c *okapi.Context) error {
start := time.Now()
err := next(c)
log.Printf("Request took %v", time.Since(start))
return err
}
}
o.Use(customMiddleware)
Standard Library Middleware
You can also use standard http.Handler middleware:
o.UseMiddleware(func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
slog.Info("Hello from standard HTTP middleware")
handler.ServeHTTP(w, r)
})
})
Middleware Chaining
Apply multiple middleware to a route or group:
o.Get("/admin",
adminHandler,
).Use(
authMiddleware,
loggingMiddleware,
rateLimitMiddleware,
)