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
| Backend | DSN format | Notes |
|---|---|---|
postgres | postgres://user:pass@host/db | Tokens survive proxy restarts; suitable for production |
redis | redis://host:6379/0 | Fast; tokens lost if Redis is flushed without persistence |
memory | — | No 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
- Authentication — inbound auth (required) and other outbound strategies
- Tool Groups — per-group session configuration