diff --git a/internal/transport/http/middleware/auth.go b/internal/transport/http/middleware/auth.go index 99c4d18..020acf2 100644 --- a/internal/transport/http/middleware/auth.go +++ b/internal/transport/http/middleware/auth.go @@ -99,11 +99,19 @@ func UserIDFromContext(ctx context.Context) (uuid.UUID, bool) { // prefix; case-insensitive matching is intentionally NOT performed // because RFC 6750 specifies the literal "Bearer" scheme name and being // strict here keeps the parsing surface small. +// +// As a fallback, ?token= query parameter is accepted for endpoints that +// cannot send custom headers (notably browser-native WebSocket connections). +// Callers must keep token lifetimes short so the URL-borne token is not a +// long-lived secret should it be logged by intermediaries. func extractBearer(r *http.Request) string { h := r.Header.Get("Authorization") const prefix = "Bearer " - if !strings.HasPrefix(h, prefix) { - return "" + if strings.HasPrefix(h, prefix) { + return strings.TrimSpace(h[len(prefix):]) } - return strings.TrimSpace(h[len(prefix):]) + if q := r.URL.Query().Get("token"); q != "" { + return q + } + return "" }