Per-User OAuth2 Sessions

Standard outbound OAuth2 Client Credentials grants a single machine identity for all users. Per-user OAuth2 sessions instead store individual user tokens — obtained via Authorization Code flow — so each user accesses the upstream API with their own identity and permissions.

When to use this

  • The upstream API enforces per-user scopes or data isolation
  • Audit logs on the upstream must show individual user identities
  • Users need to grant the proxy access to their own upstream accounts (e.g. GitHub, Google)

Configuration

upstreams:
  - name: github
    type: http
    tool_prefix: gh
    base_url: https://api.github.com
    openapi:
      source: https://raw.githubusercontent.com/github/rest-api-description/main/descriptions/api.github.com/api.github.com.yaml
    outbound_auth:
      strategy: oauth2_user_session
      oauth2_user_session:
        authorization_url: https://github.com/login/oauth/authorize
        token_url: https://github.com/login/oauth/access_token
        client_id: ${GITHUB_CLIENT_ID}
        client_secret: ${GITHUB_CLIENT_SECRET}
        scopes: [repo, read:user]
        redirect_url: https://my-proxy.example.com/oauth2/callback
        session_store:
          backend: postgres           # postgres | redis
          dsn: ${SESSION_STORE_DSN}

session_server:
  enabled: true
  base_url: https://my-proxy.example.com   # used to build redirect URLs

Session stores

BackendDSN formatNotes
postgrespostgres://user:pass@host/dbTokens survive proxy restarts; suitable for production
redisredis://host:6379/0Fast; tokens lost if Redis is flushed without persistence
memoryNo config required; tokens lost on restart — development only

Authorization flow

When an unauthenticated user calls a tool that requires a user session, the proxy returns an MCP error with a login_url field pointing to the upstream's OAuth2 authorization endpoint. The user visits that URL, grants access, and is redirected back to the proxy's callback endpoint. Subsequent tool calls from that user automatically use their stored token.

Token refresh

If the upstream provides a refresh_token the proxy will automatically refresh the access token before it expires. Refresh failures surface as MCP errors with a new login_url, prompting the user to re-authorize.

User identity

The user is identified by the JWT sub claim from inbound auth. Inbound auth must be configured when using per-user sessions. See Authentication.

See also