Skip to content
Agent Identity

Deployment pattern

All patterns

Host runtime

UserBrowser hostNative hostServer runtimeAuthorization server

Browser, native, and server-side agent hosts

/patterns/host-runtime

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

UserBrowser hostNative hostServer runtimeAuthorization server
  • UserSPA / chat UI (RFC 10017)Browser host
  • UserSystem browser (RFC 8252)Native host
  • UserOptional; server holds the client keyServer runtime
  • Browser hostAuth code + PKCE; prefer BFF cookiesAuthorization server
  • Native hostAuth code + PKCE; claimed HTTPS or loopbackAuthorization server
  • Server runtimeConfidential client + DPoP or mTLSAuthorization server
Three places the same OAuth client can live. Pick one; do not mix their token-storage rules.

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.

UserBrowser agent hostOptional BFFASAPI
  • UserUses the chat UIBrowser agent host
  • Browser agent hostPrefer the BFF as the confidential clientOptional BFF
  • Optional BFFAuth code + PKCEAS
  • Optional BFFServer-side call; HTTP-only session cookie to the pageAPI
RFC 10017: PKCE always. Tokens belong in a BFF cookie or in memory — not in localStorage.

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.

UserNative agent hostSystem browserAS
  • Native agent hostOpen authorize URLSystem browser
  • UserAuthenticate and consentSystem browser
  • System browserAuthorization code on claimed HTTPS or loopbackNative agent host
  • Native agent hostCode + PKCE exchangeAS
RFC 8252: system browser, PKCE, claimed HTTPS or loopback. No embedded webview.

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)Front end (no tokens)Server-side agentASAPI
  • User (optional UI)Session cookie onlyFront end (no tokens)
  • Server-side agentClient auth (private_key_jwt / mTLS) + user grant or client_credentialsAS
  • Server-side agentDPoP or mTLS-bound access tokenAPI
Confidential client. Authenticate with a key; sender-constrain the access token.

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

Optional

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

Back to the matrix