OAuth
Sign an MCP client into one workspace with OAuth, understand the four scopes it can ask for, and know how long each token lives.
OAuth signs an agent into one workspace as you: no key to paste, no credential on disk, and never more access than you already have. The client needs nothing but the server URL. Standards fetches the client's public metadata document, opens login and workspace consent, and hands the client an access token bound to https://api.standards.new/v1/mcp.
This page covers the inbound direction only: a client signing in to Standards. Standards signing in to a third-party server is on Outbound servers.
Scopes
| Scope | Unlocks, subject to your workspace permissions |
|---|---|
mcp:read | search, query and read: schema, records, documents, files and memory, plus propose_memory. |
mcp:write | write (batches of up to 100), edit_content and organize: records, richtext, folders and files. |
mcp:delete | delete, one reference per call: records and documents. |
mcp:people:read | search and read over the user kind, the workspace directory. Alone, it serves only those two tools, restricted to members. |
No scope implies another. mcp:write without mcp:read gets write, edit_content and organize and nothing to read or search with. A scope you hold but your workspace roles do not back yields nothing: the tool list is the intersection of both, see Tools.
Access levels
A connection has one access level, mapped to the mcp:* scopes. You choose it at consent and can change it later without reconnecting, from Connected apps.
| Level | Scopes | Defining capability |
|---|---|---|
| Read (Lecture) | mcp:read | read |
| Write (Écriture), the default | mcp:read mcp:write | write |
| Full (Complet) | mcp:read mcp:write mcp:delete mcp:people:read | delete |
The rights a connection really has are its level intersected with your role: a capability your role lacks is shown as not in your role and yields nothing. A level is offered only if your role has its defining capability and the client requested every one of its scopes.
The grant is the authority for every request. When you change a level, the next request of the connection carries it, and the new scopes apply even though the client's token was issued earlier. The scope returned in a token response is advisory after a level change: do not rely on it to know what the connection may do.
What the authorization server supports
| Capability | Value |
|---|---|
| Grant types | authorization_code, refresh_token, device authorization (urn:ietf:params:oauth:grant-type:device_code). |
response_types | code only. |
PKCE | Required on every authorization request. |
| Resource indicators | Mandatory. Every request names resource; the access token is issued with that audience and is refused anywhere else. |
scopes_supported | openid, offline_access and the four mcp:* scopes, so a client reading the authorization server metadata can request them itself. Standards never adds a scope the client did not request. |
| Refresh tokens | Rotated on every use. The refresh must name the same resource as the grant. |
| Revocation | Supported. A revoked grant denies the next refresh and the next request. You can also revoke from Connected apps. |
| Userinfo | Not served. |
| Dynamic client registration | disabled. Clients identify themselves with a Client ID Metadata Document instead. |
Access tokens are opaque. Decoding one tells you nothing; only the server can validate it.
Token lifetimes
| Token | Lifetime |
|---|---|
| Access token | 3600 seconds. |
| Refresh token | 90 days from its last use, rotating: each refresh issues a new one and restarts the 90 days. |
| Grant | 90 days from its last use, sliding: it moves forward each time the client refreshes. |
| Refresh reuse grace | 30 seconds. |
| Authorization code | 60 seconds. |
| Device code | 600 seconds. |
A client that keeps working stays connected; one unused for 90 days signs in again. There is no absolute limit.
A connection does not depend on the browser session that approved it. Signing out of that browser, or signing in there as another account to approve another connection, leaves it working: each connection stays bound to the account and workspace that approved it. It ends only when its owner revokes it, when a refresh token is replayed, after 90 days unused, or when the account loses access.
A client that loses a refresh response (a dropped connection, a retry) can send the same refresh token again within 30 seconds of its rotation and receives a new token pair of its own, beside the one the first request received. A refresh token replayed after those 30 seconds is treated as theft: the connection is revoked and the client signs in again.
Client admission rules
Dynamic client registration is disabled: a client identifies itself with a Client ID Metadata Document served at an https:// URL, and that URL is its client_id. The document is at most 5120 bytes and carries no secret: token_endpoint_auth_method is "none", or "private_key_jwt" with an asymmetric token_endpoint_auth_signing_alg (RS256, PS256, ES256, Ed25519 or EdDSA) and its public keys in exactly one of an https:// jwks_uri (at most 16384 bytes) or an inline jwks; client_secret_* methods are refused. It also declares response_types ["code"], grant_types containing authorization_code, plus optionally refresh_token, and https:// redirects (loopback http:// for a native app); a document that breaks a rule is refused before login starts. An extension grant the document also declares, such as urn:ietf:params:oauth:grant-type:jwt-bearer, is ignored rather than refused: it is never granted.
A client that runs in a browser — an extension service worker, a single-page app — always sends an Origin header, and the authorization server refuses a token request whose origin the client has not declared. Such a client lists the origins it speaks from in web_origins: each entry is a scheme and host with no path, trailing slash, query or fragment, such as chrome-extension://abcdefghijklmnop or https://app.example. A client that declares none is allowed no origin, which is what a client outside a browser wants.
Device authorization
A client with no browser of its own can use the device flow. It displays a code, you open the page Standards serves, enter the code, confirm the client, then sign in and review access as usual. The device code lives 600 seconds and the client polls for the result; a client that polls too fast is told to slow down by five seconds.
What you see at consent
The consent screen shows the client's name and the workspace you are signing into. The name comes from the client's metadata, cleaned before display: control characters removed, whitespace collapsed, at most 80 characters. A client with no usable name is shown by its hostname.
You choose one access level for the connection. You cannot grant more than the client asked for, and a level is offered only when the client requested all of its scopes and your role in the workspace holds its defining capability (see Access levels). When no level can be selected, nothing is granted. The grant records the scopes of the level you chose.
A client that requests no mcp:* scope at all, only openid for instance, cannot be approved. Approving it answers a page saying the client requested no permission for the resource and naming the scopes it could have asked for; nothing is granted. Reconnect from the client so that it requests at least one of them.
Errors
Every 5xx from the authorization server is rewritten to 503. A request that omits resource fails with invalid_target. A resource the server does not know fails the same way. Once you hold a token, the MCP endpoint's own answers are listed on the MCP page: 401 invalid_token, 403 insufficient_scope, 403 on a workspace mismatch.
Next steps
- MCP — connect Claude Code or Codex and read the endpoint's error table.
- Tools — what each scope unlocks, tool by tool.
- Connected apps — change a connection's level or revoke it.
- Workspaces and API keys — the key path, for clients without OAuth.
- Agent workflow — an OAuth sign-in followed by a full session.
- Book a demo