package server import ( "context" "net/http" "dance-lessons-coach/pkg/greet" "dance-lessons-coach/pkg/user" "github.com/rs/zerolog/log" ) // AuthMiddleware handles JWT authentication and adds user to context type AuthMiddleware struct { authService user.AuthService } // NewAuthMiddleware creates a new authentication middleware func NewAuthMiddleware(authService user.AuthService) *AuthMiddleware { return &AuthMiddleware{ authService: authService, } } // Middleware returns the authentication middleware function func (m *AuthMiddleware) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // Extract Authorization header authHeader := r.Header.Get("Authorization") if authHeader == "" { // No authorization header, pass through with no user next.ServeHTTP(w, r) return } // Extract token from "Bearer " format const bearerPrefix = "Bearer " if len(authHeader) < len(bearerPrefix) || authHeader[:len(bearerPrefix)] != bearerPrefix { log.Trace().Ctx(ctx).Str("auth_header", authHeader).Msg("Invalid authorization header format") next.ServeHTTP(w, r) return } token := authHeader[len(bearerPrefix):] // Validate JWT token validatedUser, err := m.authService.ValidateJWT(ctx, token) if err != nil { log.Trace().Ctx(ctx).Err(err).Msg("JWT validation failed") next.ServeHTTP(w, r) return } // Add user to context ctxWithUser := context.WithValue(ctx, greet.UserContextKey, validatedUser) r = r.WithContext(ctxWithUser) // Continue to next handler next.ServeHTTP(w, r) }) }