OptionalAuth returns a middleware that parses JWT when present and sets user context. Does not return 401 when token is missing; continues to next handler.
(cfg *config.Config)
| 102 | // OptionalAuth returns a middleware that parses JWT when present and sets user context. |
| 103 | // Does not return 401 when token is missing; continues to next handler. |
| 104 | func OptionalAuth(cfg *config.Config) func(http.Handler) http.Handler { |
| 105 | return func(next http.Handler) http.Handler { |
| 106 | return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
| 107 | token, _ := extractToken(r) |
| 108 | if token == "" { |
| 109 | next.ServeHTTP(w, r) |
| 110 | return |
| 111 | } |
| 112 | claims := jwt.MapClaims{} |
| 113 | t, err := jwt.ParseWithClaims(token, &claims, func(_ *jwt.Token) (interface{}, error) { |
| 114 | return []byte(cfg.JWTSecret), nil |
| 115 | }) |
| 116 | if err != nil || !t.Valid { |
| 117 | next.ServeHTTP(w, r) |
| 118 | return |
| 119 | } |
| 120 | userID, _ := claims["sub"].(string) |
| 121 | role, _ := claims["role"].(string) |
| 122 | sessionID, _ := claims["sessionId"].(string) |
| 123 | if userID != "" { |
| 124 | ctx := r.Context() |
| 125 | ctx = context.WithValue(ctx, UserIDKey, userID) |
| 126 | ctx = context.WithValue(ctx, UserRoleKey, role) |
| 127 | if sessionID != "" { |
| 128 | ctx = context.WithValue(ctx, SessionIDKey, sessionID) |
| 129 | } |
| 130 | r = r.WithContext(ctx) |
| 131 | } |
| 132 | next.ServeHTTP(w, r) |
| 133 | }) |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | func extractToken(r *http.Request) (token, source string) { |
| 138 | if auth := r.Header.Get("Authorization"); auth != "" { |
nothing calls this directly
no test coverage detected