diff --git a/internal/serveredition/auth/middleware.go b/internal/serveredition/auth/middleware.go index 09571b7e8..dc4169f35 100644 --- a/internal/serveredition/auth/middleware.go +++ b/internal/serveredition/auth/middleware.go @@ -188,12 +188,14 @@ func (m *ServerEditionAuthMiddleware) authenticateFromSession(r *http.Request) ( // Authorization header and returns an AuthContext if successful. // Returns (nil, nil) if no Bearer token is present. func (m *ServerEditionAuthMiddleware) authenticateFromBearer(r *http.Request) (*coreauth.AuthContext, error) { + // The auth-scheme name is case-insensitive (RFC 7235 ยง2.1). authHeader := r.Header.Get("Authorization") - if !strings.HasPrefix(authHeader, "Bearer ") { + const scheme = "Bearer " + if len(authHeader) < len(scheme) || !strings.EqualFold(authHeader[:len(scheme)], scheme) { return nil, nil } - token := strings.TrimPrefix(authHeader, "Bearer ") + token := authHeader[len(scheme):] if token == "" { return nil, nil } diff --git a/internal/serveredition/auth/middleware_test.go b/internal/serveredition/auth/middleware_test.go index ea095c6e8..75a7be8c6 100644 --- a/internal/serveredition/auth/middleware_test.go +++ b/internal/serveredition/auth/middleware_test.go @@ -800,3 +800,24 @@ func TestMiddleware_BearerContextFieldParity(t *testing.T) { } } } + +func TestMiddleware_ValidJWT_SchemeCaseInsensitive(t *testing.T) { + s := setupMiddlewareTest(t) + token := s.generateJWT(t, s.testUser.ID, s.testUser.Email, s.testUser.DisplayName, "user", s.testUser.Provider, 1*time.Hour) + handler := s.middleware.Middleware()(authContextHandler()) + + for _, scheme := range []string{"bearer", "BEARER"} { + req := httptest.NewRequest(http.MethodGet, "/api/v1/servers", nil) + req.Header.Set("Authorization", scheme+" "+token) + rr := httptest.NewRecorder() + handler.ServeHTTP(rr, req) + + var body map[string]interface{} + if err := json.Unmarshal(rr.Body.Bytes(), &body); err != nil { + t.Fatalf("%s: failed to unmarshal response (%d): %v", scheme, rr.Code, err) + } + if rr.Code != http.StatusOK || body["user_id"] != s.testUser.ID { + t.Errorf("%s: expected 200 for user %q, got %d: %s", scheme, s.testUser.ID, rr.Code, rr.Body.String()) + } + } +}