Middleware
Middleware in CoreAPI lives in pkg/middleware and is applied per route in routes/routes.go.
What's available
// pkg/middleware/auth_middleware.go
middleware.Protected(jwtService) // validates JWT, rejects if missing or invalid
middleware.HasRole("ADMIN") // exact role match
middleware.HasAnyRole("ADMIN", "MEMBER") // matches any of the listed roles
Claims are set on c.Locals after Protected runs — accessible in handlers:
userID := c.Locals("userId").(string)
role := c.Locals("role").(string)
userType := c.Locals("userType").(string)
Adding middleware to a domain
Three files change — main.go, wire.go, routes.go. Handlers don't change.
main.go — create jwtService and pass it to Setup:
jwtService := jwt.NewJWTService(jwt.JWTConfig{
SecretKey: cfg.JWT.SecretKey,
AccessTokenTTL: int(cfg.JWT.AccessTokenTTL),
RefreshTokenTTL: int(cfg.JWT.RefreshTokenTTL),
})
yourdomainroutes.Setup(v1, db.GetDB(), jwtService)
routes/wire.go — accept and forward it:
func Setup(r fiber.Router, db *gorm.DB, jwtService jwt.JWTService) {
cfg := yourdomain.ConfigFromEnv()
h := handlers.NewHandler(db, cfg)
registerRoutes(r, h, jwtService)
}
routes/routes.go — apply per route:
func registerRoutes(r fiber.Router, h *handlers.Handler, jwtService jwt.JWTService) {
g := r.Group("/your-domain")
g.Get("/:id", h.GetByID) // public
g.Get("/", middleware.Protected(jwtService), h.List) // auth required
g.Post("/", middleware.Protected(jwtService), middleware.HasAnyRole("ADMIN"), h.Create) // auth + role
}
Tips
Not all routes need middleware — apply it only where needed. Public read endpoints often don't need auth.
Order matters — Protected must come before HasAnyRole. Role check depends on claims that Protected sets.
jwtService is currently wired in setup.go for ticketing domains. New CoreAPI domains wire it from main.go directly as shown above.