Host runtime
Browser, native, and server-side agent hosts
Where the OAuth client actually runs changes token storage and client type. RFC 10017 for browser-based hosts, RFC 8252 for native apps, confidential client + DPoP or mTLS for server-side runtimes. Same grant, different failure modes.
When you see it
A chat SPA that holds the agent's tokens in the page. A desktop companion (Claude Desktop, a CLI with a loopback redirect). A backend worker that is the confidential client and never shows tokens to the model or the browser. This row is orthogonal to the others: an interactive delegated agent is also one of these three hosts.
Actors and trust
HumanUser
Still authenticates at the AS. The host type decides which user-agent and where tokens land afterwards.
Agent host (the OAuth client)Agent instance
Public client in a browser or many native apps; confidential client on a server. Must not leak tokens into model context, logs, or XSS-reachable storage.
Authorization serverOther
Enforces PKCE, exact redirect URIs, and (for confidential clients) client authentication.
Topology
- User→ SPA / chat UI (RFC 10017) →Browser host
- User→ System browser (RFC 8252) →Native host
- User→ Optional; server holds the client key →Server runtime
- Browser host→ Auth code + PKCE; prefer BFF cookies →Authorization server
- Native host→ Auth code + PKCE; claimed HTTPS or loopback →Authorization server
- Server runtime→ Confidential client + DPoP or mTLS →Authorization server
Three host runtimes
Browser-based agent host
The product UI is the OAuth client: a chat SPA, an embedded assistant, anything whose JavaScript could see a token.
- User→ Uses the chat UI →Browser agent host
- Browser agent host→ Prefer the BFF as the confidential client →Optional BFF
- Optional BFF→ Auth code + PKCE →AS
- Optional BFF→ Server-side call; HTTP-only session cookie to the page →API
Token pitfall: XSS on the chat page is token theft. localStorage and sessionStorage survive XSS. Do not put access tokens in the DOM, in analytics, or in model prompts. Implicit flow is gone.
Native app host
Desktop or mobile companion: Claude Desktop, a CLI, an IDE plugin that opens a browser for login.
- Native agent host→ Open authorize URL →System browser
- User→ Authenticate and consent →System browser
- System browser→ Authorization code on claimed HTTPS or loopback →Native agent host
- Native agent host→ Code + PKCE exchange →AS
Token pitfall: Embedded webviews are in-scope for phishing the password. Custom URI schemes are a last resort if claimed HTTPS is unavailable. OS token stores beat a plaintext file next to the binary.
Server-side agent runtime
The agent is a backend process. It can keep a client key. The browser, if any, never sees access tokens.
- User (optional UI)→ Session cookie only →Front end (no tokens)
- Server-side agent→ Client auth (private_key_jwt / mTLS) + user grant or client_credentials →AS
- Server-side agent→ DPoP or mTLS-bound access token →API
Token pitfall: Tokens in logs, traces, and tool arguments are the usual leak. Do not ship the client secret to the browser 'for convenience.' Do not hand the model the refresh token.
Primary
- OAuth for browser apps
RFC 10017 — browser-based hosts.
- OAuth for native apps
RFC 8252 — native / CLI hosts.
- OAuth 2.1
- PKCE
- DPoP
Server-side (and anywhere you can) sender-constraint.
Optional
- mTLS sender-constrained tokens
Confidential clients that already have a cert.
- OAuth Security BCP
RFC 9700.
Do not use
- Tokens in localStorage or the DOM
XSS reads them. RFC 10017 is explicit.
- Embedded webview for login
RFC 8252: use the system browser.
- Client secret in browser JavaScript
There is no confidential client in the page.
Why these, and not those
OAuth 2.1 does not change the fact that browsers cannot hide secrets, native apps must not embed a webview, and servers can keep a key. RFC 10017 is the browser BCP: prefer a Backend-for-Frontend with HTTP-only cookies; if tokens must live in the page, keep them in memory, never localStorage. RFC 8252 is the native BCP: system browser, PKCE, claimed HTTPS or loopback redirects. Server-side agents are confidential clients and should sender-constrain with DPoP or mTLS so a leaked access token is not replayable from a laptop. Token storage is the incident: XSS in the chat page, an embedded webview, a refresh token in localStorage, or a token concatenated into a prompt.
Related flows
Sequence diagrams, not this topology cut. All flows