v2.1.0
Added
-
Added the
replcommand: a persistent session bound to one account that reads the secret store once and answerstokenandauthcommands over stdin/stdout.One-shot commands re-read the secret store on every run, so a keyring that confirms disclosure per process prompts again and again. The REPL resolves the token once, holds it in memory for the life of the process, and reuses it, collapsing those prompts into a single unlock (plus one per refresh, which must persist a rotated refresh token). It shows a prompt on a terminal and uses a plain line protocol when piped (one flushed result per command on stdout, errors on stderr), so an application can drive it without reimplementing the OAuth flow.
auth getandauth resumerun against the same in-memory account, so a token they issue is immediately served by a followingtoken show. -
Added the device authorization grant (RFC 8628).
grant = "device"withendpoints.device-authorization. Interactiveauth getpolls; non-interactive /--jsonhands off toauth resume <DEVICE_CODE>. -
Added the headless client credentials grants, so OAuth-ignorant tools (a sync daemon, a cron job) can exec
ortie token show --auto-refreshand always read a valid bearer token.grant = "client-credentials"(RFC 6749 section 4.4) authenticates with the existingclient-secret;grant = "client-credentials-jwt"(RFC 7523 section 2.2, the Microsoft certificate credentials flow) authenticates with a JWT assertion signed by the newclient-key(PKCS#8 or PKCS#1 PEM path), carrying thex5tthumbprint of the newclient-certificate(PEM or DER path). Both runauth getheadlessly in one shot;auth resumehas nothing to resume and says so.Neither grant issues a refresh token, so auto-refresh (
token show --auto-refreshandtoken refresh) branches per grant: refresh-token exchange where one exists, silent re-acquisition (a re-run of the grant) for the client credentials kinds, including when the stored token is missing, so the very first run needs no priorauth get. Each JWT re-acquisition mints a fresh 10 minute assertion (uniquejti, key and certificate re-read from disk); assertions are never stored.A provider
invalid_clienton the JWT kind now hints that the certificate credential may be expired and need renewal. -
Added a welcome banner to the wizard, on stderr, framing what ortie is and where every field is documented.
-
Added a keyring entry prompt to the wizard's storage step, seeded with the account name and used verbatim, matching the Himalaya wizard, instead of being namespaced under
ortie/on your behalf. -
Offered to save the wizard's account to a config file, defaulting to
$XDG_CONFIG_HOME/ortie/config.toml.The account is printed first and the save comes after it, so the prompt decides one thing only and declining leaves you the printed fragment. An existing file is appended to, never rewritten: the fragment is one
[accounts.<name>]table, so the accounts and comments already in it are untouched. Appending to a file that already holds something is confirmed first, naming the path. A redirected stdout (or--json) prints without prompting at all, soortie >> <config>is unchanged. -
Resolved issuers into concrete grants: a typed issuer URL, and a discovered OAuth issuer, are read through their RFC 8414 metadata instead of being emitted as a bare issuer comment.
Every grant the metadata advertises is offered, so a server publishing both an authorization endpoint and a device authorization endpoint yields both flows, as RFC 8414 and RFC 8628 allow, and a machine with no browser can pick the device grant where a redirect is also possible.
-
Offered the authorization server's
scopes_supportedin the scope multi-select, for an application not bound to a registered set of scopes.
Changed
-
Bumped io-oauth to 0.2.1, for the RFC 7523 support behind its
jwt-bearerfeature, and io-pim-discovery to 0.5, for the time-bounded discovery the wizard now runs. -
A refreshed or issued token now stamps its issuance time from the local clock (instead of relying on the server
Dateheader), and a missingexpires_indefaults to one hour, so auto-refresh stays reliable across a long-lived session. -
Emitted keyring read commands as an exec-style array instead of a shell string, so no shell reinterprets an entry name.
Write commands stay shell lines, since some rely on shell features (
$(cat)on macOS), as do commands typed by hand. -
Ordered the wizard's storage strategies by what is installed, the credential provider CLIs found on your
PATHleading.The ones that are not found are still offered, and say so: each is one package install away, and the commands written for it are correct either way.
-
Bounded the wizard's discovery with a 6 second deadline, so one unreachable endpoint cannot stall the prompt.
-
Reduced discovered grants by authorization server rather than by endpoint URL, so one server described by two mechanisms is offered once instead of twice.
Gmail no longer asks you to choose between Mozilla autoconfig's legacy
accounts.google.com/o/oauth2/auth+www.googleapis.com/oauth2/v3/tokenpair and the current one: the most authoritative mechanism wins, and an entry is labelled by its flow and services instead of its token endpoint. A pick list left with a single grant is no longer prompted for. -
Asked for the application before the scopes, since a registration is what decides which scopes can be requested.
A public application now offers exactly the scopes it is registered for (Thunderbird on Google: Gmail, CardDAV and CalDAV), so a scope its client id was never verified for can no longer reach the authorization request and fail at consent. Dynamic registration picks its scopes before it registers, since they travel in the registration request.
-
Derived the wizard's account name from the input (the first label of the domain or issuer host) instead of prompting for it; rename the
[accounts.<name>]key by hand. -
Moved the wizard's guidance from the printed fragment into the stderr banner, so stdout now carries bare TOML.
-
Probed the authorization server metadata once per wizard run, shared by the scope options and the dynamic registration decision, instead of only before the application step.
-
Serialized the client id under
--jsoneven when left empty, matching theclient-id = ""placeholder the TOML fragment already carried.
Fixed
-
Fired on-issue error hooks when the local device poll deadline expires (
DeviceCodeExpiredasexpired_token). -
Made the manual
auth resumecommand printed byauth getrunnable as printed.Its state and PKCE verifier are single quoted and attached to their flag with
=, so a value starting with-is not read as a flag and one starting with~is not expanded by your shell. -
Trimmed auth-code resume input; omitted redirect/state/PKCE bodies from resume errors.
Removed
-
Removed the
auth discoversubcommand: bareortiealready runs the same wizard. Runortie(it prompts for the email, server or issuer input). -
Removed hand-entry of OAuth 2.0 endpoints from the wizard, along with the "Enter OAuth 2.0 details manually" pick-list entry.
The wizard configures only what it can discover; when nothing is found it stops and points at the sample configuration.
-
Removed the prompts behind the wizard's custom application entry (client id, secret, scopes, redirection).
If you registered an application yourself you are already editing the config, so the wizard emits the account with everything it resolved, leaves
client-idempty, and explains what to fill in by hand. The storage step still runs, being independent of the application.