74 lines
2.4 KiB
Go
74 lines
2.4 KiB
Go
// monorepo/cloud/maplefile-backend/internal/maplefile/interface/http/middleware/jwt.go
|
|
package middleware
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"go.uber.org/zap"
|
|
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config/constants"
|
|
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/pkg/httperror"
|
|
)
|
|
|
|
func (mid *middleware) JWTProcessorMiddleware(fn http.HandlerFunc) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
ctx := r.Context()
|
|
|
|
// Extract the Authorization header
|
|
reqToken := r.Header.Get("Authorization")
|
|
|
|
// Validate that Authorization header is present
|
|
if reqToken == "" {
|
|
problem := httperror.NewUnauthorizedError("Authorization not set")
|
|
problem.WithInstance(r.URL.Path).
|
|
WithTraceID(httperror.ExtractRequestID(r))
|
|
httperror.RespondWithProblem(w, problem)
|
|
return
|
|
}
|
|
|
|
// Extract the token from the Authorization header
|
|
// Support both "Bearer" (RFC 6750 standard) and "JWT" schemes for compatibility
|
|
var token string
|
|
if strings.HasPrefix(reqToken, "Bearer ") {
|
|
token = strings.TrimPrefix(reqToken, "Bearer ")
|
|
} else if strings.HasPrefix(reqToken, "JWT ") {
|
|
token = strings.TrimPrefix(reqToken, "JWT ")
|
|
} else {
|
|
problem := httperror.NewBadRequestError("Not properly formatted authorization header")
|
|
problem.WithInstance(r.URL.Path).
|
|
WithTraceID(httperror.ExtractRequestID(r))
|
|
httperror.RespondWithProblem(w, problem)
|
|
return
|
|
}
|
|
|
|
// Validate the token is not empty after prefix removal
|
|
if token == "" {
|
|
problem := httperror.NewBadRequestError("Not properly formatted authorization header")
|
|
problem.WithInstance(r.URL.Path).
|
|
WithTraceID(httperror.ExtractRequestID(r))
|
|
httperror.RespondWithProblem(w, problem)
|
|
return
|
|
}
|
|
|
|
// Process the JWT token
|
|
sessionID, err := mid.jwt.ProcessJWTToken(token)
|
|
if err != nil {
|
|
// Log the actual error for debugging but return generic message to client
|
|
mid.logger.Error("JWT processing failed", zap.Error(err))
|
|
problem := httperror.NewUnauthorizedError("Invalid or expired token")
|
|
problem.WithInstance(r.URL.Path).
|
|
WithTraceID(httperror.ExtractRequestID(r))
|
|
httperror.RespondWithProblem(w, problem)
|
|
return
|
|
}
|
|
|
|
// Update our context to save our JWT token content information
|
|
ctx = context.WithValue(ctx, constants.SessionIsAuthorized, true)
|
|
ctx = context.WithValue(ctx, constants.SessionID, sessionID)
|
|
|
|
// Flow to the next middleware with our JWT token saved
|
|
fn(w, r.WithContext(ctx))
|
|
}
|
|
}
|