Authentication
The CLI generator is in early access. Reach out to get started.
Each generated CLI reads authentication credentials from the security schemes declared in your OpenAPI spec. Credentials can come from environment variables, CLI flags, files, or a combination of these through fallback chains.
Without a credential, the CLI still works — you can explore the command tree, view help, and use --dry-run.
Credential sources
The CLI supports several ways to supply credentials, configured at build time.
A typical fallback chain lets the CLI flag override the env var, which in turn overrides a file:
Supported auth schemes
The CLI supports every scheme type that OpenAPI’s securitySchemes defines:
OAuth flows
Declaring an oauth scheme under auth-schemes in generators.yml makes the CLI acquire tokens on its own instead of reading a pre-issued token from the environment. Three flows are supported through the type field:
The interactive flows are public-client only: they use PKCE rather than a client secret. They require CLI generator 0.29.0 or later.
Log in and out
Every generated CLI exposes an auth command group:
Tokens are stored in the OS keyring, refreshed automatically when they expire, and sent as Authorization: Bearer <token> on every request. Pass --no-browser to auth login to print the authorization URL instead of opening a browser, and --with-token to skip the flow and read a token from stdin.
Authorization code with PKCE
Omitting redirect-uri binds an OS-assigned loopback port at login (recommended, no port registration needed). To pin a port, set redirect-uri to a loopback URL, and list ports to add fallbacks tried in order when the primary port is busy:
The host must be 127.0.0.1 or localhost over http, the port is required, and the path is arbitrary. Register every redirect URI the CLI can produce, including each backup port, with the authorization server.
Hosted callback pages
Once login finishes, the loopback listener renders a built-in page for the success and failure states. success-redirect-url and error-redirect-url hand that last screen off to pages you host instead:
Both take an absolute http or https URL. The success redirect forwards no query parameters, since the credential is already captured on the loopback. The error redirect appends error and, when the authorization server sent one, error_description, so the hosted page can explain the failure:
Neither URL is the OAuth redirect_uri, so neither needs registering with the authorization server. Omitting both keeps the built-in pages.
Device code
auth login prints a user code and verification URL, then polls the token endpoint until the user approves. redirect-uri and pkce are rejected for this flow.
Extra request parameters
Authorization servers that require additional literal parameters, such as an Auth0 audience, accept them through per-request maps.
The device-code flow uses device-authorization-parameters in place of authorization-parameters.
Auth strategies
When a spec declares multiple security schemes, the CLI composes them according to one of these strategies:
Operations that declare security: [] (an empty list) opt out of authentication entirely — no credentials are sent regardless of what’s configured.
Configure the any strategy
When an API accepts more than one credential under the any strategy, the CLI authenticates with whichever source is populated, using the first scheme that has a credential. Declaring the schemes requires two steps:
-
In your OpenAPI spec, define the schemes under
securitySchemesand list them as multiple auth schemes in thesecurityarray.openapi.yml -
In
generators.yml, define the same schemes underauth-schemesand compose them withapi.authset toany.generators.yml
The scheme names must match across both files.
A scheme that’s missing from the spec is ignored without warning, even when its environment variable is set. With both declared, set either variable and the command runs:
Named profiles
For APIs where every call carries a tenant identifier (an account SID, an org slug, a workspace), a profile stores it once instead of it being typed on every command. A profile is a named bundle of request context resolved once per invocation: a credential, parameter defaults, server URL variables, an optional base URL, a retry limit, and a default output format. Nothing else is accepted; an unknown key is rejected at write time rather than stored and ignored.
Profiles are off by default. Enable them with the profiles config option in generators.yml, which adds a profiles command group and a global --profile / -p flag to the generated CLI. A CLI generated without the option is unchanged.
Manage profiles
profiles create accepts --set <name>=<value> for API parameters (validated against the spec, so a typo is rejected), --server-var <name>=<value> or --<name> <value> for server URL variables, --base-url, --retries <N>, --default-format, --parent <name>, and --with-token to read a credential from stdin. When several auth schemes are declared, --scheme names the one the credential belongs to.
profiles set <name> KEY=VALUE ... takes any environment variable the CLI reads (a credential such as ACME_AUTH_TOKEN, or a setting such as ACME_RETRIES, ACME_BASE_URL, ACME_OUTPUT, or ACME_<SERVER_VAR>) or an API parameter by its spec name, and creates the profile if it doesn’t exist. Keys are validated before anything is written, and an unrecognized key fails with a suggestion. auth login --from-env captures the credential from the CLI’s own environment variables into the active profile.
Select a profile
A profile is selected by, in order, --profile / -p, the <PREFIX>_PROFILE environment variable, then the profile marked active by profiles use, where <PREFIX> is the binary name uppercased with - replaced by _. With no profile selected, the CLI behaves as if the feature were absent. A named profile that doesn’t exist is an error rather than a fallthrough to environment credentials, so a command never silently runs against the wrong tenant. The profiles group itself always runs unprofiled, so a stale active pointer can be repaired.
Scripts and agents should pass -p per invocation: it mutates no global state, so parallel invocations can’t race.
Precedence
With a profile selected, each value resolves as explicit flag → selected profile → environment variable → spec default. The order is the same however the profile was selected: -p, <PREFIX>_PROFILE, or profiles use. The profile’s stored values win, and environment variables fill only the values the profile leaves unset. With no profile selected, values resolve as explicit flag → environment variable → spec default. A CI pipeline that exports ACME_API_KEY or ACME_BASE_URL should therefore select no profile; if one is selected, its stored values take effect over the exported variables. Retries resolve as --retries → profile → <PREFIX>_RETRIES → x-fern-retries, and --retries 0 is equivalent to --no-retry. profiles current reports when an environment variable is supplying a credential the selected profile doesn’t store, and auth status lists the profile’s keyring credential before the environment variable.
Storage and inheritance
Non-secret settings live in ~/.config/<bin>/profiles.toml. Secrets are never written to that file: credentials go to the OS keychain under a profile-scoped account, the same store auth login uses.
--parent <name> sets single-level inheritance. A child inherits its parent’s credential, base URL, server variables, parameter defaults (child wins per key), and retries. It doesn’t inherit the default output format, since output shape belongs to the invocation rather than the tenant. Because the parent is resolved at read time, editing it propagates to its children.
Help output
Every generated CLI includes a dynamically rendered Authentication: section in its --help output listing every scheme, the expected env var or flag, and whether a credential is detected.