Sign-in, sessions, and tokens

A credential is the value a caller presents to the platform to prove who it is: a cookie, a bearer token, or a one-time link. This page compares the credentials used by a browser, a Model Context Protocol (MCP) client, an unattended script, a deployed application, and the application's own users. For each, it says how it is obtained, how long it lasts, and what ends it. Management action tiers and approvals explains what each credential may do.

Credential Used by Presented as Lives Ended by
The browser's cookies you, in a browser cookies on the platform origin the site, dashboard, and application programming interface (API) cookies 30 days from your last visit, 90 days at most from the sign-in; the approval cookie 8 hours Sign out in that browser, Sign out everywhere, suspension, erasure, a passkey change's revert, expiry
The tool's connection your MCP client the Open Authorization (OAuth) access token, a bearer on the MCP endpoint 30 days, renewed through a refresh token that lasts 30 days longer Sign out everywhere, revoke_connection, suspension, erasure, a passkey change's revert, a replayed refresh token, 60 days without renewal
A minted token a script, a pipeline, a contractor's tool a bearer on the Hypertext Transfer Protocol (HTTP) API, the MCP endpoint, or the storage, logging, and egress endpoints, where it names the environment in the header x-turnzero-cloud-environment no expiry by default; optionally 1–3650 days from minting revoke_token, expiry, erasure, deletion of the application it is bound to; for a token from Turn Zero Blueprint's command, also 30 days unused, Sign out everywhere, a passkey change's revert, and suspension
The platform credential your deployed backend TURNZERO_CLOUD_TOKEN, a bearer on the platform's own endpoints until its environment replaces it: production at every deploy to production and every promote, development through rotate_secret on the development scope a deploy to production or a promote (production), rotate_secret on the development scope (development), the environment's deletion, the application's deletion, the account's erasure
An egress key your deployed backend's provider software development kit (SDK) the setting an upstream's settings names as its key, a bearer on that upstream's egress route alone until the environment's next deploy, promote, or restart_application replaces the copy that contains it that replacement, the failed deploy or promote that minted it, a re-declaration whose settings is null or has no key, the environment's deletion, the application's deletion, the account's erasure
An end-user session your application's users the cookie __Host-turnzero_cloud_realm on the application's own hostname, containing a signed token the token one hour, issued again while the session lasts its realm's session length, 30 days by default the user's sign-out, the user's ending of it from the session list, revoke_end_user, delete_end_user, revoke_realm_keys, the realm's end. A sign-in that would open the user's 101st live session ends the oldest.
A native app's session the users of your mobile app the same signed token as a bearer in the Authorization header, with a refresh credential the app keeps the token one hour; each refresh extends the session by the realm's session length, up to session_cap_days from the sign-in, 365 days by default the app's revocation call or its sign-out, POST /__account/signout under the bearer, an ending from the session list, a refresh credential replayed after sixty seconds, revoke_end_user, delete_end_user, revoke_realm_keys, the cap, the realm's end. A sign-in that would open the user's 101st live session ends the oldest.
A deploy code the turnzero-cloud command, from the line a deploy call returns to your tool a bearer on deploy on the HTTP API, once, for the call that prepares the deploy's upload until the returned expires_at, five minutes at most, and never past the expiry of the session or token whose call returned it its one use, a later deploy call for the application, expiry, application deletion, account suspension or erasure. For a session's code, also Sign out everywhere, a passkey change's revert, and its own session's end: Sign out in that browser, revoke_connection, or the session's expiry. For a token's code, also revoke_token or the token's expiry
A storage transfer grant a browser, a file-transfer client, or the turnzero-cloud command a bearer on one named storage file route and, for a deploy's upload grant, on deploy for its upload's one start, then on the command's progress reads of that deploy until the returned expiry time, and a deploy's upload grant's progress reads until five minutes after its deploy ends, never past fifteen minutes after the start; refused while the owning account is suspended the file being written using an upload grant, and for a deploy's upload grant its one start, then its progress window's end; expiry, application deletion, account erasure
An export download grant, a kind of transfer grant the turnzero-cloud command, on your machine a bearer on GET of a named storage file: every file of one completed export, and the application's stored files in the export's environment that were created by the time the export listed them. It writes nothing and lists nothing until the returned expiry time, five minutes after minting by default, and a read does not use it up; refused while the owning account is suspended expiry, application deletion, account erasure
A secret grant the turnzero-cloud command, on your machine a bearer on store_secret or rotate_secret on the HTTP API, for one write of one name at one scope until the returned expiry time, a few minutes; refused while the owning account is suspended its one write, expiry, application deletion, account erasure
A one-time link you, in a browser a URL your tool prints an invitation 14 days by default; a link ticket ten minutes its one use, expiry, revoke_invitation

When an ending takes effect

An ending in the table is a revocation, a rotation, a suspension, or a reinstatement. Where it takes effect depends on the endpoint:

Endpoint When an ending takes effect During a control-plane outage
The HTTP API, the MCP endpoint, and the accounts service At once. —
The storage, logging, and egress endpoints Within 30 seconds, because each keeps a checked credential for 30 seconds before checking it again. Each keeps accepting a credential it has already checked, for up to an hour from its last successful check, then refuses it. The HTTPS tunnel's proxy keeps its last result for the same hour.
The serving router When the router's cached result expires and it checks the control plane again. It keeps serving the application's placement and its account's standing as it last read them, so your application stays up.

The egress endpoint caches an egress key's check the same way. Its ending reaches that endpoint within 30 seconds, and during an outage the endpoint accepts it for up to an hour from its last successful check.

A suspension or reinstatement made during an outage reaches the serving router when the control plane responds again. Platform staff can set a limit on that instead. Past the limit, every request on the application's hostname is refused with HTTP 503 and standing_stale until the control plane responds again.

Renaming an application with rename_application ends no end-user session. The session stays valid, but the browser's cookie stays with the previous hostname, which no longer responds. The person therefore signs in again on the new hostname. A rename retires both hostnames, so a user of the development realm also signs in again on the new development hostname.

Signing in

Signing in is one step. The sign-in page offers Google, GitHub, a six-digit code emailed to an address you enter, and a passkey once you have registered one. There is no password. You type the emailed code on the page that sent it, in the same browser, within ten minutes. The code goes only to the address entered, and the message contains no link.

While the platform is in private beta, a first sign-in creates an account only for an address that has an invitation. Connect your tool covers your first sign-in. The sign-in methods, the cookies below, and what ends a session do not change between those stages.

A sign-in creates browser cookies. When an MCP client started the sign-in, the sign-in also authorizes that client's connection. The two are separate sessions from then on: the site's Sign out ends that browser's cookies alone, and the connection keeps renewing until you end it or sign out everywhere. A sign-in started from the site's header creates browser cookies and authorizes no tool.

Browser cookies

A sign-in sets four cookies on the platform origin, each HttpOnly, Secure, and SameSite=Lax:

  • The site cookie, for the whole origin, lets the browser open the public pages and the documentation trees its account can read.
  • The dashboard cookie, for /dashboard, lets it open the signed-in site.
  • The API cookie, for https://turnzero.ai/api/v1/actions/, lets a signed-in page of the site call management actions. The platform accepts it only on a same-origin JSON post with no Authorization header, and only on the actions the signed-in pages use.
  • The approval cookie, for /approve, lasts 8 hours from the sign-in. After that, an approval link asks you to sign in again.

The site, dashboard, and API cookies are one session, and every page you open renews all three. They expire together 30 days after your last visit, and none lasts more than 90 days from the sign-in that created it. The site and the dashboard therefore open and close together.

A change made from the dashboard needs a sign-in within the last 8 hours. Such changes are storing or rotating a secret, changing a plan, running a schedule, adding or removing a passkey, and deleting the account. After 8 hours the page shows a Sign in again link in place of the form. The link returns you to the same page after the sign-in, and the pages stay readable throughout.

The tool's connection

Your MCP client authenticates as the MCP specification describes, and it performs every stage itself:

  1. Discovery. The server publishes its authorization-server metadata at /.well-known/oauth-authorization-server and its protected-resource metadata at /.well-known/oauth-protected-resource/mcp. A client registers itself at /oauth/register; nobody issues a client identifier by hand.
  2. Sign-in. The client opens /oauth/authorize in your browser with a Proof Key for Code Exchange (PKCE) challenge and the resource https://turnzero.ai/mcp. You sign in, and the browser returns a one-time code to the client.
  3. Tokens. The client exchanges the code, with its verifier and the same resource, at /oauth/token. It receives an access token that lasts 30 days and a refresh token that lasts 60 days. It presents the access token as a bearer on every request to the MCP endpoint.
  4. Renewal. When the access token expires, the client presents the refresh token and the same resource at /oauth/token and receives a new pair. The refresh token it presented is then used up. A renewal continues the same connection without another interactive sign-in.

The access token lasts a month because the platform ends it the moment you sign out everywhere, revoke the connection, or lose the account's standing. A short lifetime would add renewals without adding safety. A renewed connection stays bound to the same resource, the same client, and the original sign-in. A renewal that races a sign out everywhere does not keep the connection signed in. A refresh token issued before connections were bound to a resource is refused at renewal, and its holder signs in once more.

Connecting starts with the sign-in. The server answers every request from a connection that has not signed in, its first request included, with the authentication challenge that starts the sign-in. The published contracts and the library stay readable without an account over plain HTTP, at https://turnzero.ai/api/v1/actions/.

What ends a connection

Five things normally end a connection:

  • Sign out everywhere, on the Sign-in & security page or as the sign_out_everywhere action from a tool, ends every session of the account at once. That is every browser's cookies and every connection, on every device, the one that asked included. It also ends a passkey offer still open from a sign-in, which then registers nothing. A passkey you already have stays, because it ends sessions, not credentials. The header's Sign out is different: it ends that browser's cookies alone and no connection.
  • revoke_connection, or End this connection on the Account page, ends that one connection: its access token and its renewal are refused at once, and every other connection and the browser's cookies stay valid.
  • Suspension of the account ends its sessions, refuses renewal, and ends an open passkey offer. Erasure ends everything. Reverting a passkey change (Identities and passkeys) ends every session the same way, and signs the reverter's own browser in again in the same step.
  • A replayed refresh token. A used refresh token presented again within ten minutes gets a new pair from the same chain. A tool such as Claude Code keeps one stored credential for every process on your machine, and two of them can renew minutes apart. A used refresh token presented later than ten minutes revokes the whole chain to protect against a stolen token, and every holder signs in again. The window adds little risk: your tool renews about once a month, so the ten minutes after each renewal are the only time a stale copy would pass.
  • Sixty days without renewal, because the refresh token lasts 60 days.

Sign out everywhere, suspension, and reverting a passkey change also end every token Turn Zero Blueprint's command was given. Each answer counts them as exchange_tokens_revoked, and reinstating a suspended account does not bring them back. A token you minted with mint_token stays.

A host's own logout, or removing its MCP connection, is different. It disconnects that host and does not sign the account out everywhere.

A routine upgrade of Turn Zero Cloud does not end a connection. The connection and its refresh token are records in the platform's database, and your browser session is a record its signed cookies refer to, so all three survive an upgrade. An upgrade that changes a token or cookie format ends whatever still uses the old format, and its holder signs in once more.

If a client loses its stored credential or a renewal is refused, the client may ask you to reconnect. Sign in again through the host rather than editing tokens by hand.

Bearer tokens on the HTTP API

Every management action is also available as an HTTP endpoint on the platform origin, https://turnzero.ai/api/v1/actions/<action_name>. It accepts POST for every tier, and also GET for observe actions. The request body is the action's own payload, the same schema your tool reads in the published contracts (context://service_contracts), and refusals have the same names.

The credential is a bearer in the Authorization header: the connection's access token, or a minted token. For a deploy, the turnzero-cloud command presents the one-time deploy code from the line a deploy call returns, on the one call that prepares the upload. It then presents the upload grant that call returns, for the deploy's one start. For its one write on store_secret or rotate_secret, it can also be the secret grant in the line that such a call returns.

The one exception is the signed-in site's API cookie. A same-origin JSON post from a page of the site, with no Authorization header, is checked against that cookie on the actions the signed-in pages use. A state-changing action under it needs a sign-in within the last 8 hours. No other cookie is accepted there, and a request with an Authorization header is checked against the header alone, never the cookie.

The storage endpoints accept the same bearer, which is how a script uploads a deploy artifact.

The same bearer also gives access to the machine files of the documentation trees your account can read, which is how a tool without the site cookie reads this documentation. These are each tree's llms.txt, llms-full.txt, and docs.json, and the index.md beside every page. This tree's index is /cloud/llms.txt; /blueprint/ and /tzdocs/ are open to an account with Turn Zero Blueprint access. The origin root has /llms.txt and /llms-full.txt, covering the trees every account can read. A connected tool reads the same texts over its connection, through read_documentation and the docs:// resources. Machine surfaces of this documentation describes each file.

Minted tokens

A minted token authenticates unattended work. Its scope is set when it is created: the whole account or one application. Mint a token documents the mint_token arguments and how to use the token.

  • Expiry. expires_in_days, an integer from 1 to 3650, makes the token expire after that many days. Without it, the token does not expire.
  • Label. A label of 1 to 120 characters is optional.
  • Grants. A token receives only the grants its minting session both has and asks for. The destructive grant lets it request a destructive action, which a person still approves in the browser.

mint_token returns the value once. A token cannot mint another token. list_tokens returns token records without values, each with when it was minted, when it expires, and when it was last used, so you can see a token nothing uses any more.

A session or an account-scoped token also files feedback with submit_feedback and records a rating with rate_experience (Feedback and ratings). A token scoped to one application is refused all four feedback actions with token_scope_refused. The application's backend reaches its own space through the egress gateway instead.

Platform staff give their own test harnesses the synthetic_estate grant. A token minted with it is bounded to the actions that seed, purge, and read the synthetic test accounts, list_tokens, submit_feedback, the public reads, and two reporting actions. One posts a monitored check's run, and the other tells platform staff how a harness's run ended. A token minted with the feedback_queue grant, which platform staff give the tool that triages the feedback queue, is bounded to read_feedback, the queue included, the action that settles it, and the public reads.

Platform staff give one hosted test job a narrower grant, synthetic_seed_purge. A token minted with it is bounded to three actions: the one that seeds a synthetic test account, the one that purges it, and the one that reads that purge. It can also call the public reads. Each seed makes one account, whose own token lasts at most a day. At most 12 accounts it seeded can exist at once, and a further seed is refused until one is purged. The token purges and reads only what it seeded itself, and every other action refuses it.

A token minted with the issues grant is bounded to one issue space of your account. It can call relay_issue_act for that space, list_tokens, and the public reads. Every other action refuses it with issues_bounded (A token for one issue space).

revoke_token ends a token. Later requests with it are refused at once on the HTTP API and the MCP endpoint. The storage, logging, and egress endpoints refuse it within the interval that When an ending takes effect gives: 30 seconds normally, and up to an hour during a control-plane outage. Each action performed with a token records that token's identity.

Keep a token where your tool keeps environment values. A value that reaches a chat, a log, or a commit is exposed: revoke it and mint another.

A token from Turn Zero Blueprint's command

The platform serves the request below for Turn Zero Blueprint's command. The command's released version does not make it, so this section describes the request as the platform answers it.

The platform serves a request that gets one issue space's token for Turn Zero Blueprint's command through the sign-in a connecting tool uses, with three differences. Its client identifier, turnzero-blueprint, is the platform's own, so nothing is registered for it. It asks for the scope issues, which no other client is given. And its code is exchanged for a minted token, never for a connection.

The request goes to /oauth/authorize with these parameters:

  • client_id is turnzero-blueprint.
  • response_type is code.
  • redirect_uri is http://127.0.0.1:<port>/callback or http://[::1]:<port>/callback, on whichever port the command listens on.
  • code_challenge, with code_challenge_method set to S256, and state are required.
  • scope is issues.
  • label is required. It names the clone the token is for, in 1 to 120 printable characters.
  • space is optional. It names an issue space your account owns.
  • component is optional. It names the component the repository files its issues under, which the confirm page shows. The token still reaches the whole space.

After the sign-in, the platform sends your browser to a confirm page under /approve/blueprint/. The page names the account you are signed in as and lists your spaces, or the one space names. Where the request names no space, it also offers to create one. It shows a request code: the first eight hexadecimal digits, in upper case, of the SHA-256 digest that code_challenge carries, in two groups of four. The program that opened the request holds the verifier the digest is made from, so it can show the same code, and you can tell its request from another program's.

Confirming sends the program that opened the request a code, which it exchanges once at /approve/blueprint/token with its verifier, as a form-encoded or a JSON body. The token endpoint /oauth/token refuses that code, naming this address. A new space you asked for is created at that exchange, so a code never exchanged leaves nothing behind. The answer carries the token in access_token, beside space, level, label, origin, token_id, and replaced, the tokens it revoked. It carries no refresh token, and list_connections shows no new connection.

The exchange mints the token and, in the same step, revokes the earlier token this request issued under that label in that space. If your sign-in ends while the token is minted, for example by Sign out everywhere, the exchange ends that token and refuses with invalid_grant, so no token is sent. A token from Turn Zero Blueprint's command says what the token can do and lists the refusals.

The token has no expiry date, but it does not last forever. It ends when it goes 30 days without being used, and a daily check ends it. It also ends when you sign out everywhere, when you undo a passkey change, and when the account is suspended. Each of those answers counts the tokens it ended as exchange_tokens_revoked.

These ends exist because the token holds the owner level for its space: a clone that is deleted, or a session someone else took over, should not leave one behind. A token you minted with mint_token ends in none of these ways. Once a clone's token has ended, make the authorization request again from that clone.

The platform credential

A deployed backend calls the platform with a credential the platform creates for the application's environment and supplies as TURNZERO_CLOUD_TOKEN. The backend uses it on the storage endpoints, the logging service, the egress gateway, and the accounts service's verification route. The credential is bound to its environment, so every call under it reaches that environment's storage, secret scope, log stream, and realm without naming it. On an application with one environment, which has no development realm, the verification route checks the development credential's sessions against production's realm. It checks a session someone already has, and starts none.

There is one current credential per environment, and every application has a development one for its local runs. A deploy to development supplies the current value without creating a new one. How each environment's value is created:

  • Development. The first manifest submission creates it. On the HTTP API the result returns it once, and through the MCP tool the submission withholds it. A submission that names local_run returns the provision line and withholds it on either route. The line creates a new value with rotate_secret on the development scope and writes it into a local run's environment file. A new line replaces a lost value.
  • Production. Every deploy to production, on one environment, and every promote create a new value and supply it to the new container. The platform switches to that container only after its health check passes, so a failed deploy or promote leaves the current value in place.

Neither the deploy result nor the promote result returns the credential's value, and no production credential is ever shown to you.

Some service routes also accept session or minted tokens. Those tokens are bound to no environment, so they name it in the header x-turnzero-cloud-environment. Each route's contract states which credential kinds it accepts.

End-user sessions

Your application's users are not accounts on the platform. They belong to the application's own realm on the accounts service; Manage end users covers the realm's sign-in methods and settings. A signed-in user has a session cookie on the application's own origin. It lasts the realm's session length: 30 days by default, or the 1 to 30 days that configure_realm's session_days sets.

Every environment of the application has its own realm: production's alone on one environment, and a development realm too once development is turned on. configure_realm takes an optional environment that defaults to production, so two realms are configured separately. If delete_environment removed the development realm, the next create_environment creates it again with the default sign-in methods, so configure any other sign-in methods again.

The backend checks a session in one of two ways: locally, with the realm's public keys the platform supplies to the container, or through the accounts service's verification route with its own credential. Verifying an end user describes both. revoke_end_user ends a user's sessions. Under an invited audience, the realms accept only invited users from the moment the manifest declares it, and you issue the invitations there.

Native sessions

A mobile app signs its users in through the realm's own authorization endpoint and keeps the session as a bearer, not a cookie. The token is the same signed token the cookie contains. The serving router treats a bearer of the token's form as it treats the cookie. Where a cookie is sent with it, the bearer takes precedence. The router sets the same session header on the forwarded request and applies the audience rule to the result, on every audience.

A bearer the router cannot verify is refused 401 authentication_required with WWW-Authenticate: Bearer error="invalid_token", on every audience. The router never renews a bearer; the app refreshes at the token endpoint. The realm's own routes and the verification route accept the bearer too, and the backend verifies it through the account package's verify client.

Beside the token the app keeps a refresh credential. Each refresh returns a fresh token and a fresh credential, and extends the session by the realm's session length, up to session_cap_days from the sign-in.

A refresh credential is single-use. Presenting a replaced one within sixty seconds returns a fresh pair, because a lost response is not theft. Presenting it later ends the session, and the app signs in again. Sign in from a native app covers the declaration, the exchange, and the refresh.

Some tasks finish in your browser, and your tool prints the URL:

  • An approval link, /approve/<id>, for a pending destructive action. The page shows the platform's own description of what will be destroyed, and your click approves or declines it under the approval cookie. Your tool reads the outcome with read_pending_action.
  • A link ticket, /link/<ticket>, from link_identity, valid for ten minutes. It opens the guided steps that add a second sign-in method to your account.
  • An invitation URL from issue_invitation, for one address and one use, valid 14 days by default. See Invitation URLs.
  • The passkey offer after a sign-in by emailed code, open for ten minutes and bound to that sign-in. Signing out everywhere ends it early: the offer is refused as invalid_grant, and you add the passkey from the passkey page after a new sign-in. Signing that browser out clears the offer's cookie, so its routes refuse offer_cookie_required and the passkey is offered again at your next sign-in by code. A suspension of the account also ends it: the offer is refused as account_suspended, and no page follows until the account is reinstated.

Invitation URLs

An invitation to an application's realm is a URL on the application's own origin, which you issue. issue_invitation takes an optional environment that defaults to production, and the URL is on that environment's hostname. The platform sends nothing for an application's realm, so you deliver the URL yourself.

An invitation to the platform itself is a URL of the form /auth/invitation/<token> on the platform origin, which only platform staff issue. The platform emails it to the invited address, and the result's emailed says whether it was sent. The issue_invitation reference states when it is false.

Opening an invitation URL shows the invitation's own page. It shows the invited address and the time the invitation expires, to the minute in UTC, and offers the sign-in methods; a link that cannot be used says only that. After a rename, an invitation URL issued earlier no longer responds, because it contains the previous hostname. The token in it still works on the new hostname.

What your tool does

Your tool signs in at its first request to the server, keeps the tokens, and renews them without asking. Without an account it can still read the contracts and the library over plain HTTP at https://turnzero.ai/api/v1/actions/. For a script or a pipeline, it mints a token bounded to the application and presents it as a bearer. It never prints a token: a value in a chat or a log is exposed, so the tool revokes it and mints another. It leaves destructive approvals to your browser and reads the outcome with read_pending_action.

For its own deploy, your tool mints no token. It runs the line a deploy call returns once, as given, and pastes it nowhere, because the line's deploy code is a credential until it ends.