Configure sign-in

Sign in from the CLI and MCP clients

Use the provider's device flow for the CLI or approve an MCP client through the console.

For: cluster and tenant administrators.

Use the provider's device flow for the CLI or approve an MCP client through the console.

The CLI: oz0 login

A person signs in to the CLI through one of the cluster's identity providers, without a certificate. The CLI shows a code and a link; they open the link on any device (a laptop's browser, a phone), sign in at the provider and enter the code: the OAuth 2.0 device flow (RFC 8628), which works over SSH and in containers too.

Use the final management and edge addresses in your CLI context. The CLI refuses HTTP redirects on these connections to keep credentials at the endpoint you selected; if a proxy redirects, configure the destination address directly.

Terminal
oz0 login --management https://oz0.example.com:9443 --ca-cert ca.crt --provider okta   # the first time
oz0 login                                                                               # later; asks which provider when there are several
oz0 tenant list                                                                         # as yourself
oz0 logout
Output
To sign in, open https://acme.okta.com/activate and enter the code BCDF-GHJK
Waiting for you to approve it there...
Signed in as alice through okta. The session lasts until 2026-10-17 09:12:00; `oz0 logout` ends it.
  • The provider's own rules apply. Management asks the provider for the code with the provider's client (and its secret, which never leaves management), and checks the ID token the provider answers as it does for the console. The person's account is found, linked or made as at a console sign-in, and the provider's group rules give their roles. The provider's second factor and conditional access apply; a tenant's policy for passwords is about passwords, and there is no password sign-in on the CLI.
  • Enter only a code your own oz0 login showed you. Whoever approves a code signs in the CLI that asked for it, as themselves: a code someone sends you is a request to give them your access (RFC 8628's remote phishing). Management polls the provider at most once a second per sign-in, and starts at most ten sign-ins a minute from one address.
  • The provider must offer the device flow. Its discovery document lists a device_authorization_endpoint, and the client the cluster uses must be allowed the device grant (Okta: Device Authorization under the app's grant types; Entra ID: Allow public client flows; Keycloak: OAuth 2.0 Device Authorization Grant on the client). Without it oz0 login says so.
  • The CLI acts as the person on the admin API and the runtime API, through the management port: oz0 tenant list, oz0 user sessions (their own), oz0 run, oz0 approval list, oz0 apikey list where they may. A call their roles do not allow is refused with the permission it needs.
  • A session lasts seven days, as a console session does: an access token of 15 minutes, which the CLI refreshes by itself, and a refresh token that is swapped at every refresh, so a stolen copy of an old one ends the session.
    Both live in a file beside the CLI context (session.json, mode 0600; the context itself is 0600 too).

The CLI refuses a session file, or an operator's key file, that other users of the machine may read, and says the chmod 600 that fixes it; writing a context replaces an older key file with one of mode 0600.

The session is listed with the console's under Sessions (method cli+oidc:<provider>), and ends with oz0 logout, oz0 user signout, a disabled or removed account, or the provider turned off.

A refresh checks the account before it swaps the tokens: when management cannot check it for a moment (its database does not answer), the refresh answers 503 and the session and its refresh token stay as they were, and the CLI says to try again.

  • A disabled operator's certificate is refused at once, everywhere. The console's sign-in check (GET /api/auth/me) answers it as nobody signed in, with no role and no tenant; Temporal's UI and its codec refuse it rather than treat it as someone signed out; the admin API, the runtime API and the edges refuse it too (disabling an operator). An expired certificate is refused the same way.
  • Some commands still need an operator certificate: oz0 job run (the edge's Temporal port, which knows no sessions), oz0 operator renew, oz0 mcp (the operators' MCP server takes certificates and keys), oz0 dev and oz0 server .... They say so. oz0 login adds the session to the CLI context it is given (--context, $OZ0_CONTEXT or the default one): while a context holds a session, the CLI acts as the person and presents no certificate; oz0 logout hands it back to the certificate, if it has one.

MCP clients

An MCP client connects to a tenant's agents with OAuth (the MCP server): it sends the person's browser to the edge, which checks the client and sends the browser on to the console's Connect an MCP client page. There the person signs in as they always do, through the identity provider (or with a password where the cluster allows them), and approves the client or denies it.

The edge has no sign-in of its own, so nothing about the provider changes: no new callback URL to register, no new client. When management is reached by another name than its advertised address, set --public-url, which the edge sends the browser to.

The client then acts as the person, with their membership in that tenant (a cluster role does not count), for that tenant's MCP endpoint alone. A grant lasts until it is revoked, at most 90 days; disabling or removing the account, or taking the person out of the tenant, refuses its next call. People see and revoke their clients under Settings, MCP clients, or with oz0 mcp clients.

Copyright © 2026