MCP server OAuth 2.0 device flow security: headless agent authentication without redirect URIs
CLI-driven MCP servers and background agents can't use the Authorization Code flow — there's no browser to redirect. OAuth 2.0 Device Authorization Grant (RFC 8628) is the right solution, but it introduces its own security patterns that differ significantly from web-flow OAuth. This page covers device flow security for MCP servers: polling hygiene, scope binding, token lifetime management, and the common mistakes that create persistent auth vulnerabilities.
Why device flow for MCP servers
Most OAuth documentation assumes a web browser is available: the authorization code flow redirects the user to an identity provider, the user authenticates, and the provider redirects back to your callback URL with an authorization code. MCP servers running in CLI tools (like Claude Code), background worker processes, or server-to-server agent pipelines have no browser and no user-facing callback URL.
The Device Authorization Grant (RFC 8628) solves this. Instead of a redirect, the device (your MCP server or CLI client) displays a short URL and a user code. The user opens the URL on any device with a browser, enters the code, and authorizes. The MCP server polls the authorization server until the user approves or the device code expires. The MCP server then receives an access token — no redirect URI required.
The device flow sequence
The grant has four phases, each with security implications:
- Device Authorization Request: Client posts to
/device_authorizationwith itsclient_idand requestedscope. Server returnsdevice_code,user_code,verification_uri,expires_in, andinterval(minimum poll interval). - User Interaction: Client displays
verification_urianduser_code. User opens the URL in a browser, authenticates, enters the code, and grants (or denies) the requested scopes. - Access Token Polling: Client polls
/tokeneveryintervalseconds with thedevice_code. Server returnsauthorization_pendinguntil the user acts, then returns the access token (oraccess_denied). - Token Use: Client uses the access token as a Bearer token in MCP server requests. If a
refresh_tokenwas issued, client can refresh without re-running the device flow.
Device flow security: polling interval enforcement
The authorization server specifies a minimum polling interval (typically 5 seconds). A naive client implementation that ignores this interval and polls at maximum speed creates a brute-force-like load on the authorization server and may trigger rate limiting or account lockouts. More critically, a missing slow-down check on the server side means a compromised device code can be brute-forced if the server doesn't enforce back-off on authorization_pending responses.
Server-side: Track per-device-code poll count and enforce the interval. Return HTTP 429 (or RFC 8628's slow_down error with an incremented interval) if a client polls faster than the stated interval.
Client-side: Always honor the interval field from the device authorization response, not a hardcoded poll interval. Implement exponential back-off on slow_down responses by adding 5 seconds to the interval per error.
Device code scope binding
A critical mistake in device flow implementations: the scope requested at device authorization time is advisory, not binding, unless the server enforces it. If your MCP server requests scope=crm:read during device authorization but the issued token actually has scope=crm:read crm:write (because the server ignores the requested scope), your client has more authority than it asked for. This is ambient authority via overly-permissive token issuance.
Validate the token's scope claim on receipt. If the token has scopes your client didn't request, reject it and log the discrepancy — this indicates either an authorization server misconfiguration or an attempted scope escalation.
Token binding: preventing device code relay attacks
Device flow is vulnerable to a relay attack: an attacker social-engineers the user into entering the device code on the attacker's behalf (phishing the verification URL). RFC 8628 introduced verification_uri_complete — a URL that pre-fills the user code — which reduces friction but doesn't prevent phishing. OAuth 2.0 Demonstrating Proof of Possession (DPoP, RFC 9449) binds the access token to a specific client key pair, so a relayed token can't be used from a different device.
For MCP servers, DPoP implementation: the MCP client generates a key pair at startup, signs a DPoP proof on each request, and the authorization server issues tokens bound to the client's public key. Even if the access token is intercepted, it's useless without the private key.
Refresh token rotation for long-lived agent sessions
Background agent MCP servers often run for hours or days without user interaction. If the access token expires and there's no refresh token, the agent fails silently or interrupts with an unexpected re-auth flow. If the refresh token is long-lived without rotation, it becomes a persistent credential that survives far beyond the user's intent.
The correct pattern: issue a short-lived access token (15–60 minutes) with a refresh token that uses rotation (each refresh invalidates the old refresh token and issues a new one). If a refresh token is used twice (replay attack), invalidate the entire token family and require re-authorization. Store refresh tokens encrypted at rest — treat them as equivalent to a password.
What SkillAudit checks for device flow
SkillAudit's auth flow analysis flags these device flow patterns:
- Hardcoded poll interval: Client code that polls on a fixed timer rather than reading
intervalfrom the device auth response - Missing slow_down handling: No back-off logic when the server returns
slow_downerror - Scope not validated on token receipt: Access token's
scopeclaim is not checked against the requested scope - Refresh token stored in plaintext: Refresh tokens in config files, environment variables without encryption, or logged output
- Device code logged: The
device_codevalue logged to stdout/stderr (it's a credential — logging it exposes it to log aggregation systems)