-
Notifications
You must be signed in to change notification settings - Fork 1
OAuth2 Grants and Tokens
This page explains the two supported OAuth2 grants, the interactive browser login, and how access and refresh tokens are managed at runtime. For the underlying module internals, see OAuth2 Internals.
| Grant | When to use | Human in the loop? |
|---|---|---|
client_credentials |
Service accounts, CI, headless automation. | No |
authorization_code |
End users acting as themselves, with consent. | Yes (first run) |
The grant is selected by oauth2.grant. A token endpoint (tokenUrl) is
required for either grant — supply it directly or let Discovery find it.
A single POST to the token endpoint:
grant_type=client_credentials
scope=<scope> (if set)
audience=<audience> (if set)
<extraParams…>
Client authentication follows authStyle:
-
"body"(default) —client_id/client_secretin the form body. -
"header"— HTTP BasicAuthorizationheader, withclient_idalso in the body.
There is no refresh token; the proxy simply re-runs the grant when the access token nears expiry.
This grant supports three input modes, tried in order:
-
Pre-existing refresh token (
oauth2.refreshToken, or a cached one) — the proxy goes straight to refreshing; no browser. -
Pre-supplied one-shot code (
oauth2.authorizationCode+oauth2.codeVerifier) — exchanged exactly once. - Interactive browser flow — the default for first-time human login.
- Generate a PKCE verifier (32 random bytes, base64url) and its S256 challenge.
- Generate a random
statevalue (CSRF protection). - Start a local HTTP listener on
callbackHost:callbackPort(default127.0.0.1:53682), path/callback. - Build the authorize URL (
response_type=code,code_challenge_method=S256,state,scope, redirect URI, anyextraParams) and open it in your default browser. The URL is also printed to stderr so you can open it manually (handy over SSH — see Remote Hosts (SSH Port Forwarding)). - The IdP redirects back to the local listener with
code+state. The proxy validatesstate, then closes the listener. - Exchange the code (plus PKCE verifier) at the token endpoint.
- If the response contains a refresh token, persist it (encrypted) and switch to the refresh-token grant for all future renewals.
The callback listener enforces a loopback-only Host header to defend against
DNS-rebinding attacks, and warns if you bind it to a non-loopback address. See
Security.
When a refresh produces a new refresh token (rotating IdPs), the proxy updates the in-memory token and rewrites the encrypted cache so the next launch uses the latest one.
A single TokenManager owns the access token for the process:
-
Caching. The current access token and its
expiresAtare kept in memory. -
Proactive refresh. When a request needs a token and the cached one is
within the skew window (
refreshSkewSeconds, default 30s) of expiry, it is refreshed first. - In-flight de-duplication. Concurrent callers awaiting a refresh share a single in-flight request rather than stampeding the token endpoint.
-
401 invalidation + retry. If the upstream returns
401, the bridge callsinvalidate()to drop the cached token, fetches a fresh one, and retries the request once. A second401is surfaced to the client. See Bridge Internals.
If expires_in is missing from a token response, it defaults to 3600
seconds; token_type defaults to Bearer.
For the authorization_code grant, the refresh token is cached on disk so you
only log in once per machine.
-
Encryption: AES-256-GCM. The file layout is
iv(12) ‖ tag(16) ‖ ciphertext. A random 32-byte key is generated once and stored next to the cache askey.binwith0600permissions. -
File name: derived from a SHA-256 of
clientId|tokenUrl(first 16 hex chars) so different clients/endpoints don't collide. -
Atomic writes: written to a temp file then renamed.
-
Default location (override with
OAUTH2_TOKEN_CACHE_DIR):OS Path Windows %APPDATA%\mcp-oauth2-proxy\macOS ~/Library/Application Support/mcp-oauth2-proxy/Linux ${XDG_CONFIG_HOME:-~/.config}/mcp-oauth2-proxy/
A corrupt or unreadable cache is ignored (with a warning) and the proxy falls back to interactive login.
See Security for the threat model around the cache, and OAuth2 Internals for the implementation.
GitHub repo · npm package · Licensed under MIT
Overview
Guides
- Getting Started
- Configuration
- OAuth2 Grants and Tokens
- Discovery
- Security
- Remote Hosts (SSH Port Forwarding)
- Troubleshooting
Internals