Authentication Middleware Example

Demonstrates authentication and authorization middleware patterns.

What You’ll Learn

Running

cd docs/01-router-guide/03-middleware/examples/02-auth-middleware
go run main.go

Testing

Use test.http or curl:

Public endpoint (no auth):

curl http://localhost:3000/public

Protected endpoint (requires API key):

# Without key - should fail
curl http://localhost:3000/protected

# With valid key - should work
curl -H "X-API-Key: secret-key-123" http://localhost:3000/protected

# With invalid key - should fail
curl -H "X-API-Key: wrong-key" http://localhost:3000/protected

Admin endpoint (requires API key + admin role):

# Without admin role - should fail
curl -H "X-API-Key: secret-key-123" http://localhost:3000/admin

# With admin role - should work
curl -H "X-API-Key: secret-key-123" -H "X-User-Role: admin" http://localhost:3000/admin

How It Works

1. Auth Middleware

func authMiddleware(ctx *request.Context) error {
    apiKey := ctx.GetHeader("X-API-Key")
    
    if apiKey == "" {
        return ctx.Api.Unauthorized("API key required")
    }
    
    if apiKey != "secret-key-123" {
        return ctx.Api.Forbidden("Invalid API key")
    }
    
    // Continue to next middleware or handler
    return ctx.Next()
}

2. Admin Middleware

func adminMiddleware(ctx *request.Context) error {
    role := ctx.GetHeader("X-User-Role")
    
    if role != "admin" {
        return ctx.Api.Forbidden("Admin access required")
    }
    
    return ctx.Next()
}

3. Per-Route Middleware

// Single route with middleware
router.GET("/protected", handler, authMiddleware)

// Multiple middleware (executed in order)
router.GET("/admin", handler, authMiddleware, adminMiddleware)

4. Group Middleware

// All routes in group use middleware
apiGroup := router.AddGroup("/api")
apiGroup.Use(authMiddleware)

apiGroup.GET("/users", handler)    // Protected
apiGroup.GET("/orders", handler)   // Protected

// Nested group with additional middleware
adminGroup := router.AddGroup("/api/admin")
adminGroup.Use(authMiddleware, adminMiddleware)

adminGroup.GET("/stats", handler)  // Protected + Admin only
adminGroup.GET("/logs", handler)   // Protected + Admin only

Alternative syntax with callback:

router.Group("/api", func(g lokstra.Router) {
    g.Use(authMiddleware)
    g.GET("/users", handler)
    g.GET("/orders", handler)
})

Middleware Execution Flow

Request: GET /admin

1. authMiddleware runs
   ├─ Checks X-API-Key
   └─ Calls ctx.Next()

2. adminMiddleware runs
   ├─ Checks X-User-Role
   └─ Calls ctx.Next()

3. Handler runs
   └─ Returns response

Response sent back to client

Expected Responses

No API key:

{
  "status": "error",
  "error": {
    "code": "UNAUTHORIZED",
    "message": "API key required"
  }
}

Invalid API key:

{
  "status": "error",
  "error": {
    "code": "FORBIDDEN",
    "message": "Invalid API key"
  }
}

No admin role:

{
  "status": "error",
  "error": {
    "code": "FORBIDDEN",
    "message": "Admin access required"
  }
}

Success:

{
  "status": "success",
  "data": {
    "message": "This is a protected endpoint",
    "access": "authenticated users only"
  }
}

Key Takeaways

Production Tips

In real applications: