--- title: "CLI Authentication" canonical: "https://admiral.io/docs/reference/cli-authentication" description: "How the Admiral CLI authenticates. Browser sign-in with a session that refreshes itself, API keys for CI from the environment or stored once, 1Password references, and where credentials live." --- # CLI Authentication The Admiral CLI authenticates in one of two ways. Pick the one that fits how the command is being run. | You are | Use | Command | | ------------------------------------- | ----------------------------------------- | ----------------------------------------------------------------- | | A person at a terminal with a browser | Browser sign-in | `admiral auth login` | | A person on a box with no browser | An API key, stored once | `admiral auth login --with-token` | | A CI job, script, or other automation | An API key, from the environment | `ADMIRAL_API_KEY= admiral ...` | | Anyone who keeps secrets in 1Password | An API key, referenced rather than copied | `echo "op://Vault/Item/field" \| admiral auth login --with-token` | If both are present, the environment variable wins. See [Precedence](#precedence). ## Browser sign-in ```bash admiral auth login ``` The CLI prints the sign-in URL and opens it in your browser: ``` Your browser has been opened to visit: https://auth.admiral.io/oauth2/authorize?client_id=admiral-cli&... ``` Sign in as you would on the web. When you finish, the browser shows a confirmation page and the terminal reports who you are signed in as: ``` Logged in as you@example.com. ``` The browser tab does not close itself. Browsers do not let a page close a tab that the CLI opened, so close it by hand. Behind the scenes the CLI listens on a random port on `127.0.0.1` for the sign-in redirect, and exchanges the result for a session using OAuth 2.0 authorization code with PKCE. Nothing listens outside your machine, and no client secret is involved. ### When the browser does not open Over SSH, in a container, or on a machine with no default browser, the URL is still printed. Paste it into any browser on any device that can reach `auth.admiral.io`; the sign-in completes when the browser on the same machine as the CLI receives the redirect. To skip the launch attempt entirely: ```bash admiral auth login --no-browser ``` To choose a browser, set `BROWSER` to the command to run, arguments included: ```bash BROWSER="firefox --private-window" admiral auth login ``` ### Limiting a session A browser session normally carries everything your account can do. To hand a machine less than that, ask for specific scopes at sign-in: ```bash admiral auth login --scope app:read,env:read,run:read ``` The server enforces the narrowed set on every call, so a command outside it fails with a permission error even though you could run it from another session. Use this on shared or long-lived machines, or when you want a read-only default and to sign in again for changes. Scopes are fixed for the life of the session. `admiral auth status` shows what the current session is limited to, and the flag tab-completes the valid names. API keys work the same way, but their scopes are chosen when the key is created rather than at sign-in. ### Session lifetime A browser sign-in stores a session that the CLI keeps alive for you. | Token | Lifetime | Behavior | | ------------- | -------- | --------------------------------------------------------------------------------------------------------- | | Access token | 15 min | Refreshed automatically shortly before it expires. You never see this happen. | | Refresh token | 30 days | Rotated on every refresh, and the 30 days restart each time. Active users are not asked to sign in again. | If you do not use the CLI for 30 days, or your account is deactivated, the next command asks you to run `admiral auth login` again. `admiral auth logout` revokes the refresh token immediately. ## API keys An API key is a long-lived opaque credential that starts with `admp_` and acts as you. Create one in the console or with the CLI, naming the scopes it carries: ```bash admiral apikey create ci-read --scope app:read,env:read ``` The secret is printed once. A key can never do more than your own account can. Changes to a key, including revoking it with `admiral apikey revoke`, take effect within 5 minutes. An agent does not use an API key, see [Agents](https://admiral.io/docs/agents.md). ### In the environment (CI and automation) ```bash export ADMIRAL_API_KEY="admp_..." admiral app list ``` This is the right choice for CI. Store the key in your CI system's secret store and expose it as `ADMIRAL_API_KEY`. Nothing is written to disk, and the CLI refuses to store a different credential while it is set, so a runner cannot end up with two. ### Stored on the machine ```bash admiral auth login --with-token ``` At a terminal this prompts for the key without echoing it. From a script, pipe it in: ```bash echo "$MY_KEY" | admiral auth login --with-token ``` The key's format is checked before it is stored. Use this on a machine you sign in to regularly but where a browser is impractical, such as a jump host. ### From 1Password Instead of the key, give `--with-token` a 1Password secret reference: ```bash echo "op://Engineering/admiral/api-key" | admiral auth login --with-token ``` The CLI resolves the reference once to check it, then stores only the reference. On every run it fetches the key through the 1Password CLI (`op read`), so the secret never lands on disk. This requires the [1Password CLI](https://developer.1password.com/docs/cli/) to be installed and signed in, with the desktop app integration or a service account. If the vault is locked or `op` is missing, the command fails with a message saying so. > **Note:** `op://` is the only external store today. Others will follow the same shape: > a reference stored locally, resolved at run time. ## Precedence When more than one credential is available, the CLI picks in this order: 1. `ADMIRAL_API_KEY` in the environment. 2. Whatever `admiral auth login` stored, of either kind. There is only ever one stored credential. Signing in with the browser after storing an API key replaces the key, and vice versa. While `ADMIRAL_API_KEY` is set, `admiral auth login` refuses to run rather than store something that would be ignored. ## Checking what is in use ```bash admiral auth status ``` Shows which credential the CLI will use, where it is stored, and the user the server resolves it to, so it also confirms that a key works. For a browser session it adds the account, the identity provider, when the current access token expires, and the scopes the session is limited to, or "full access". `-o json` gives the same as structured output. The command exits with status 4 when there is no usable credential or the server rejects it, so a script can gate on it. To see only what is stored, without contacting the server or opening 1Password: ```bash admiral auth status --no-verify ``` ## Signing out ```bash admiral auth logout ``` Removes the stored credential. For a browser session the refresh token is also revoked at the identity provider. For a stored API key or 1Password reference, only the local copy or pointer is removed; the key itself stays valid until you revoke it, and for up to 5 minutes after. `ADMIRAL_API_KEY` in the environment is not affected. ## Where credentials live The CLI keeps its files in one directory, chosen in this order: 1. `$ADMIRAL_CONFIG_DIR`, or the `--config-dir` flag. 2. `$XDG_CONFIG_HOME/admiral`. 3. `~/.config/admiral`. | File | Contents | Sensitive | | ------------------ | ------------------------------------------------------------ | --------- | | `credentials.json` | The stored credential: a session, an API key, or a reference | Yes | | `config.json` | Non-secret settings such as the default output format | No | `credentials.json` is written with owner-only permissions (`0600`). If the CLI finds it readable by others it prints a warning with the `chmod` to fix it. `config.json` never holds a secret, so it is safe to share when reporting a problem. ## Timeouts and retries Every request has a 60 second deadline, so a stalled connection fails with "request timed out" rather than hanging. For slow operations, raise it with `--timeout` or `ADMIRAL_TIMEOUT`, for example `ADMIRAL_TIMEOUT=5m`. Read-only requests are retried a couple of times if the API is briefly unreachable; anything that changes state is never retried automatically, so a create or delete that might have reached the server does not run twice. Ctrl+C cancels the in-flight request and exits with status 130. ## Proxies The CLI honors the standard `HTTPS_PROXY`, `HTTP_PROXY`, and `NO_PROXY` environment variables for both API calls and browser sign-in. If your proxy intercepts TLS, install its CA certificate in the operating system trust store, as you would for a browser. ## Where to go next * [Authentication](https://admiral.io/docs/access.md): How people and machines authenticate to Admiral * [CLI](https://admiral.io/docs/reference/cli.md): Install and configure the CLI * [Agents & Execution](https://admiral.io/docs/agents.md): How an agent proves who it is without an API key