Authentication
Agent reference for token scopes, pairing, claims, recovery, and revocation.
Charming’s HTTP API uses Bearer tokens. An MCP client with a browser should complete OAuth when it connects, which is the smoothest path and needs no token handling. A client without one can send a chrm_user_* token as its Bearer to an MCP surface instead, which is what pairing exists for. For HTTP request and response schemas, use the REST API reference.
Choose a credential
Use the smallest scope that fits the task.
| Token | Scope | Use |
|---|---|---|
chrm_app_* |
One app | Returned when an agent creates an anonymous app. It can read, update, and run that app. |
chrm_user_* |
One account | Used by agents that need the user’s apps, sharing, secrets, or account settings. Works on the HTTP API and on the MCP surfaces. |
chrm_render_* |
One app at runtime | Minted by Charming for window.charming. Agents do not mint or manage it. |
See Pricing and limits for token lifetimes.
Discovery
Do not hardcode auth metadata. Use these machine-readable sources:
- OpenAPI contract for routes, schemas, security rules, and errors.
- OAuth authorization server for sign-in and pairing endpoints. Its
agent_auth.anonymous.credential_types_supportedvalue is["api_key"], because pairing returns a personal access token after approval. - OAuth protected resource for the API’s authorization server.
- Path-scoped protected-resource metadata for one MCP surface, at
/.well-known/oauth-protected-resourcefollowed by the surface path —/mcp,/mcp/chatgpt,/mcp/inline. Each surface names its own document in theWWW-Authenticateheader it returns on a 401, and the document’sresourceis that surface rather than the origin. - Read
authorization_serversfrom the surface document rather than assuming the origin. A surface may name itself, in which case its authorization-server metadata lives at the RFC 8414 path-inserted URL for that issuer — for/mcp/chatgptthat is/.well-known/oauth-authorization-server/mcp/chatgpt. That document may carry a differentauthorization_endpointfrom the origin-wide one, on a host reachable to readers who cannot resolve this one. Everything else, including the token endpoint, stays on this origin. A client that hard-codes the root authorization-server document still works; it just signs in on this host.
Anonymous app token
Create an app without an Authorization header to receive a chrm_app_* token. Keep it secret. It works only for the returned app and cannot list other apps.
An anonymous app expires unless a user claims it. Claiming the app revokes its chrm_app_* token. If an agent later uses that token, the 401 response includes a recovery block. Follow that block instead of creating a replacement app.
User token
A signed-in user can mint a chrm_user_* token with Create token. Charming returns the plaintext once. Use List tokens to inspect active tokens and Revoke token to revoke one.
An agent without a browser session should pair:
- Call Start pairing.
- Show the returned
user_codeandverification_urlto the user. - Poll with Poll pairing at the returned interval.
- Store the
chrm_user_*token returned after approval. Charming returns it once.
Send that token as the Bearer on either transport: the HTTP API, or an MCP surface such as /mcp.
The device_code is private to the agent. The user_code is safe to show to the user.
Claim an anonymous app
There are two supported flows:
- Set
pair: truewhen you create an anonymous app. Approval pairs the agent and claims the app in one flow. - If you already have a
chrm_user_*token, call Claim app with the app’schrm_app_*token as proof.
Both flows revoke the app token after claim. Use the user token for later work.
Send a token
HTTP agents send Authorization: Bearer <token>. Do not put a user or app token in a URL. Follow build-http.md for request examples.
Rendered apps use window.charming.api() instead of managing credentials. Charming attaches the render token.
Recover from auth errors
401means the request has no valid credential. Followerror.recoverywhen present.403means the credential is valid but lacks access to the app or action. Do not retry with the same scope.token_revoked_post_claimmeans an app was claimed. Pair for a user token, then retry.token_expiredincludes the next auth step inerror.recovery.sign_in_required(401) means a claimed app refused a gated call from a caller it cannot name. Inside a rendered app,window.charming.withUser(action)signs the visitor in and re-runs the action; an HTTP agent sends a user token instead. Signing in fixes this one, unlikeunauthorized.
The OpenAPI contract defines every error field and reason.
Revoke access
Users can review and revoke agent tokens from the account menu: choose Account settings, then Connections. HTTP agents can use List tokens and Revoke token.
Claiming an anonymous app revokes its app token. Render tokens rotate when Charming renders the app again.
Related
- Set up Charming with an agent
- Gate an action behind sign-in: signing a visitor in from inside a rendered app, and what
sign_in_requiredandforbiddeneach mean there - HTTP build guide
- Pricing and limits