Skip to content

fix(oauth): restrict OAuth client access tokens on account-management… - #2878

Open
Denx00 wants to merge 1 commit into
supabase:masterfrom
Denx00:fix/oauth-scope-limit
Open

Denx00 wants to merge 1 commit into
supabase:masterfrom
Denx00:fix/oauth-scope-limit

Conversation

@Denx00

@Denx00 Denx00 commented Oct 18, 2026 •

Copy link
Copy Markdown

Fixes #2877

Summary of Fix

Delegated third-party OAuth 2.1 client tokens (such as MCP connectors) should only have authorization according to their consented scopes and should not possess account-management privileges. I have addressed Issue #2877 by restricting OAuth client access tokens from modifying credentials, factors, or account state, while scope-limiting user profile reads.

Changes Made

  1. OAuth Client Detection (Session.IsOAuth()):

    • Added s.IsOAuth() on *models.Session to check if session.OAuthClientID is set.
    • Added isOAuthClientRequest(ctx) in internal/api/auth.go checking both JWT claims (client_id) and session data.
  2. Route Middleware (requireNotOAuthClient):

    • Rejects requests originating from third-party OAuth client sessions with 403 Forbidden (no_authorization).
    • Mounted across sensitive routes in internal/api/api.go:
      • PUT /user
      • /factors/* (enrollment, challenge, verify, unenroll, recovery codes)
      • /passkeys/* (registration options & verify, delete, patch)
      • /user/identities/* (link, unlink)
      • /user/oauth/grants (grant management)
      • /oauth/authorizations/* (authorization view and consent)
      • /reauthenticate
      • /logout
  3. Defense-in-Depth Handler Checks:

    • In addition to router middleware, added direct safeguards inside handlers (UserUpdate, EnrollFactor, requirePasskeyManagementAAL, DeleteIdentity, LinkIdentity, Reauthenticate, Logout, OAuthServerConsent, UserListOAuthGrants, UserRevokeOAuthGrant).
  4. Scope-Limiting on GET /auth/v1/user:

    • For applications using @supabase/supabase-js with OAuth tokens (getUser()), GET /auth/v1/user now runs through sanitizeUserForOAuth():
      • Internal security fields (app_metadata, identities, factors) are always stripped.
      • email, phone, and user_metadata are only included if the respective scopes (email, phone, profile) were explicitly consented.
  5. Unit Tests:

    • Added unit test suites in internal/api/oauth_client_restriction_test.go and internal/api/oauthserver/oauth_client_restriction_test.go verifying that OAuth client tokens are blocked from account modification and correctly scope-limited on GET /user.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OAuth 2.1 server: OAuth client access tokens can call /user and /factors (modify user, enroll MFA)

1 participant