JWTRBACSECURITY
AUTHENTICATION & AUTHORIZATION
JWT-based auth, RBAC implementation, permission matrices, and security best practices.
JWT — Do It Right
Store access tokens in memory (not localStorage — XSS vulnerable). Use short expiry with refresh tokens in httpOnly cookies. Never store sensitive data in JWT payload.
go
// Go — JWT generation with short-lived access + refresh tokens
func (s *AuthService) GenerateTokens(user *User) (*TokenPair, error) {
// Access token — 15 min, stored in memory on client
accessClaims := jwt.MapClaims{
"sub": user.ID,
"role": user.Role,
"org": user.OrgID,
"exp": time.Now().Add(15 * time.Minute).Unix(),
}
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, accessClaims)
access, err := accessToken.SignedString(s.accessSecret)
if err != nil { return nil, err }
// Refresh token — 7 days, httpOnly cookie
refreshClaims := jwt.MapClaims{
"sub": user.ID,
"exp": time.Now().Add(7 * 24 * time.Hour).Unix(),
}
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, refreshClaims)
refresh, err := refreshToken.SignedString(s.refreshSecret)
if err != nil { return nil, err }
return &TokenPair{Access: access, Refresh: refresh}, nil
}RBAC Middleware
Roles map to permission sets. Check permissions in middleware, not in business logic — this lets you change access rules without touching code.
go
// Permission check middleware
func (a *Auth) HasPermission(permission string) fiber.Handler {
return func(c *fiber.Ctx) error {
userID := c.Locals("userID").(string)
orgID := c.Locals("orgID").(string)
// Fetch from cache first, then DB
perms, err := a.permCache.Get(userID + ":" + orgID)
if err != nil {
perms, err = a.repo.GetUserPermissions(userID, orgID)
if err != nil { return c.Status(500).JSON(errInternal) }
a.permCache.Set(userID+":"+orgID, perms, 5*time.Minute)
}
if !perms.Has(permission) {
return c.Status(403).JSON(fiber.Map{
"error": "insufficient permissions",
"required": permission,
})
}
return c.Next()
}
}
// Usage in routes
tickets.Post("/", auth.HasPermission("tickets:create"), h.CreateTicket)
tickets.Delete("/:id", auth.HasPermission("tickets:delete"), h.DeleteTicket)