Epsitec.Auth.Cli
5.11.3.2629
Prefix Reserved
dotnet tool install --global Epsitec.Auth.Cli --version 5.11.3.2629
dotnet new tool-manifest
dotnet tool install --local Epsitec.Auth.Cli --version 5.11.3.2629
#tool dotnet:?package=Epsitec.Auth.Cli&version=5.11.3.2629
nuke :add-package Epsitec.Auth.Cli --version 5.11.3.2629
auth-cli
Operator command-line tool for the Epsitec auth service. It manages the
public key registry end to end — generates hybrid key material (ECDSA P-256,
ML-DSA-65, X25519, ML-KEM-1024), registers, reads, and revokes keysets — and
covers the token flows: user login (browser or credentials, with optional
TOTP), refresh, MFA step-up, audience-bound tokens (RFC 8707), OAuth 2.0
client-credentials service tokens, and service-client administration.
Installation
The tool ships as a .NET tool package (Epsitec.Auth.Cli):
dotnet tool install --global Epsitec.Auth.Cli
auth-cli --help
Quick Start
# Configure the target service and credentials
auth-cli configure authUrl=https://auth.example.com
auth-cli configure password=my-password
auth-cli configure apiKey=my-api-key # only for service/admin commands
# Login via browser (Passport) — derives UID from JWT sub claim
auth-cli login
# Generate keys for the logged-in user
auth-cli generate --uid uid.a1b2c
# Register the keyset (start + complete in one step)
auth-cli register --uid uid.a1b2c
# Read back
auth-cli get latest --uid uid.a1b2c
auth-cli get by-hkid --uid uid.a1b2c --hkid <hkid>
auth-cli get range --uid uid.a1b2c # all time
auth-cli get range --uid uid.a1b2c --from 2024-01-01 # from date
auth-cli get range --uid uid.a1b2c --from 1700000000 --to 1800000000 # Unix seconds
# Service API reads (no user JWT needed — API key or client credentials)
auth-cli service get latest --uid uid.a1b2c
auth-cli service get by-hkid --uid uid.a1b2c --hkid <hkid>
auth-cli service get range --uid uid.a1b2c --from 2024-01-01
# Revoke
auth-cli revoke --uid uid.a1b2c --keyset-id 1
# Inspect local state
auth-cli dump keys --uid uid.a1b2c
auth-cli dump keyset --uid uid.a1b2c
auth-cli dump private-keys --uid uid.a1b2c
# Refresh token manually (by uid, or by stored login)
auth-cli refresh --uid uid.a1b2c
auth-cli refresh --login user@example.com
# Capture just the bare access token for scripting (--jwt)
TOKEN=$(auth-cli login --login user@example.com --pwd s3cr3t --jwt)
TOKEN=$(auth-cli refresh --uid uid.a1b2c --jwt)
# Upgrade a stored 1FA refresh token to a 2FA AT/RT pair
auth-cli mfa step-up --uid uid.a1b2c # interactive TOTP prompt
auth-cli mfa step-up --uid uid.a1b2c --totp 123456 # non-interactive
Global Options
| Option | Default | Description |
|---|---|---|
--root |
./.auth-cli/ |
Root directory for settings and state |
--json |
false |
Emit machine-readable JSON output |
Partial UID
All commands that accept --uid resolve it against existing keyset files. You
may pass a prefix as long as it is unambiguous:
# Full uid
auth-cli get latest --uid uid.a1b2c3d4e5
# Unambiguous prefix — resolves automatically
auth-cli get latest --uid uid.a1b
If the prefix matches no uid, or matches more than one, the command fails with a descriptive error.
Exact matches always win: if uid.a1b and uid.a1b2 both exist, passing
uid.a1b resolves unambiguously to uid.a1b.
JSON Output
With --json, every command emits a single JSON object on stdout:
{ "status": "ok", "command": "get latest", "data": { ... } }
{ "status": "error", "command": "get latest", "error": "<message>" }
The status field is always either "ok" or "error".
Without --json (text mode), commands write human-readable summaries to stdout
and errors to stderr.
Commands
| Command | Description |
|---|---|
configure [k=v...] |
Store or display global settings |
login |
Authenticate via Passport (browser) or with --login/--pwd (credentials, optional TOTP) |
generate --uid |
Generate a fresh random hybrid keyset |
refresh |
Exchange stored refresh token for a new access token (by --uid or --login) |
register --uid |
Full start + complete registration |
register start |
Start keyset registration only |
register complete |
Complete a pending registration |
get latest |
Get latest valid keyset (JWT auth) |
get range |
Get keysets in a time range (JWT auth); --from/--to optional |
get by-hkid |
Get keyset by hkid (JWT auth) |
service get latest |
Get latest valid keyset (API key or client credentials) |
service get range |
Get keysets in a time range (API key or client credentials); --from/--to optional |
service get by-hkid |
Get keyset by hkid (API key or client credentials) |
service token |
Obtain a service access token via the OAuth 2.0 client-credentials grant |
service client ... |
Administer the service-client registry (see Service-Client Administration) |
revoke --uid |
Revoke an existing keyset |
dump keys |
Export public keys as SPKI PEM, with kids and hkid |
dump keyset |
Print the last server keyset |
dump private-keys |
Export private keys as PKCS#8 PEM to stdout |
mfa step-up |
Upgrade a stored 1FA refresh token to a 2FA AT/RT pair |
Credential Login
The login command also supports direct credential-based authentication,
bypassing the browser. Add --login <email> to enable this path. When
--pwd is omitted, the CLI prompts interactively on stderr.
| Option | Description |
|---|---|
--login |
Email to authenticate with; enables the credential path |
--pwd |
Password; prompted interactively when --login is set but --pwd is omitted |
--totp |
6-digit TOTP code to verify an existing enrolment (upgrades to ["pwd","otp"]) |
--totp-setup |
Runs the interactive 3-step TOTP enrolment flow after credential login |
--resource |
RFC 8707 resource indicator; binds the minted token's aud to this absolute URI (see Audience Binding) |
--expected-audience |
Audience the returned token is validated against; defaults to --resource, else the default audience |
--jwt |
Print only the bare access token to stdout (for scripting); mutually exclusive with --json (see Bare Token Output) |
Option rules (all validated before any network call):
--pwd,--totp,--totp-setup, and--resourcerequire--login.--totpand--totp-setupare mutually exclusive.--jwtand--jsonare mutually exclusive.
When --totp or --totp-setup is requested, no tokens are persisted unless
the full requested flow succeeds; the existing {uid}.keyset.json file is
left untouched on failure.
# Simple credential login (password prompted)
auth-cli login --login user@example.com
# Credential login with inline password
auth-cli login --login user@example.com --pwd s3cr3t
# Credential login + TOTP verification (upgraded ["pwd","otp"] token)
auth-cli login --login user@example.com --pwd s3cr3t --totp 123456
# Credential login + interactive TOTP enrolment
auth-cli login --login user@example.com --pwd s3cr3t --totp-setup
Refresh
refresh exchanges a stored refresh token for a new access token. Identify the
target keyset by either --uid or --login (the stored sign-in email) —
supplying both, or neither, is a validation error:
auth-cli refresh --uid uid.a1b2c
auth-cli refresh --login user@example.com
--login matches the login value persisted in {uid}.keyset.json at login
time, case-insensitively. It resolves for both credential and browser logins,
since the email is read from the access token's login claim.
Bare Token Output (--jwt)
Both login and refresh accept --jwt, which prints only the bare access
token as a single line on stdout and routes the human-readable status line to
stderr. This makes the token trivial to capture in a shell:
TOKEN=$(auth-cli login --login user@example.com --pwd s3cr3t --jwt)
TOKEN=$(auth-cli refresh --login user@example.com --jwt)
--jwt and --json both own stdout, so they are mutually exclusive; combining
them fails with a validation error before any network call.
Audience Binding (RFC 8707)
The login, refresh, and mfa step-up commands accept --resource <uri>, an
RFC 8707 resource indicator. When supplied, the minted access token's aud
claim is bound to that value, so a token issued for one service cannot be
replayed against another. Without --resource, the token targets the default
audience (unchanged behaviour).
- The value must be an absolute URI without a fragment (
https:URLs andurn:URIs both work); anything else fails withinvalid_targetand no token. - On
login,--resourcealso drives the post-login validation, so a resource-bound token round-trips cleanly. Pass--expected-audienceto override that (for example, to assert a deliberate mismatch). - On
login,--resourcerequires--login: the browser/Passport path cannot bind an audience (the token is minted by Passport).
# Mint a token bound to a specific service
auth-cli login --login user@example.com --pwd s3cr3t --resource https://briefcase.example
# Bind a fresh access token from a stored refresh session
auth-cli refresh --uid uid.a1b2c --resource https://briefcase.example
# Step up to 2FA, bound to a specific service
auth-cli mfa step-up --uid uid.a1b2c --totp 123456 --resource https://briefcase.example
Service Tokens (Client Credentials)
Machine-to-machine callers authenticate with the OAuth 2.0 client-credentials
grant: a registered service client exchanges its client_id/client_secret
for a short-lived, scoped, audience-bound access token — the long-lived secret
is only ever presented to the token endpoint, never to resource endpoints.
# Obtain a service token (bare token on stdout in text mode, like --jwt)
TOKEN=$(auth-cli service token --client-id bsrv0001 --client-secret <secret>)
# Restrict the requested scope and/or bind an audience
auth-cli service token --client-id bsrv0001 --client-secret <secret> \
--scope keysets:read --resource https://auth.example.com --json
| Option | Description |
|---|---|
--client-id |
Registered service-client identifier |
--client-secret |
The client's secret |
--scope |
Requested scopes; must be within the client's allowed set (default: the full allowed set) |
--resource |
RFC 8707 resource indicator; binds the token's aud |
The keyset service reads accept client credentials directly and handle the token acquisition internally:
auth-cli service get latest --uid uid.a1b2c --client-id bsrv0001 --client-secret <secret>
Without --client-id/--client-secret, the service get commands fall back to
the configured API key (configure apiKey=...).
Service-Client Administration
The service client subcommands administer the service-client registry.
They require the operator API key (configure apiKey=...).
| Command | Description |
|---|---|
service client register |
Register a client; prints the generated secret once |
service client secret add |
Issue a second secret for zero-downtime rotation; prints it once |
service client secret retire |
Retire one secret (--secret-id) |
service client disable |
Disable a client; its next token request fails |
service client enable |
Re-enable a disabled client |
service client delete |
Delete a client entirely; prefer disable for offboarding (keeps the audit witness) |
service client list |
List registered clients (never shows secret material) |
service client show |
Show one client (never shows secret material) |
# Onboard a new consumer — the secret is printed ONCE, store it immediately
auth-cli service client register --client-id bsrv0001 \
--name "Briefcase server 1" --scope keysets:read
# Optional per-client default audience and absolute expiry
auth-cli service client register --client-id bsrv0002 --scope keysets:read \
--audience https://auth.example.com --expiry 2027-01-01
# Zero-downtime secret rotation
auth-cli service client secret add --client-id bsrv0001
auth-cli service client secret retire --client-id bsrv0001 --secret-id <old-secret-id>
# Offboarding / incident response
auth-cli service client disable --client-id bsrv0001
# Inspect
auth-cli service client list
auth-cli service client show --client-id bsrv0001
Registered secrets are stored server-side as salted hashes only; they cannot
be recovered after registration. Losing a secret means rotating: secret add
a new one, then secret retire the old.
Time Range Arguments
The --from and --to options on get range and service get range are
optional and accept two formats:
| Format | Example | Interpretation |
|---|---|---|
| Unix seconds | 1700000000 |
Exact Unix UTC timestamp |
| Date | 2024-01-15 |
Midnight UTC on that day (yyyy-MM-dd) |
Defaults: --from 0 (epoch), --to end of 2199-12-31 UTC.
Terminology
- kid — key identifier, derived from a key's public SPKI bytes.
- hkid — hybrid key identifier, derived from the two signing kids (ECDSA + ML-DSA). Uniquely identifies a hybrid keyset.
Storage
All state is stored under the --root directory (default .auth-cli/):
settings.json— global settings (authUrl, passportUrl, apiKey, password){uid}.keyset.json— per-user keys, tokens, stored login, pending registration, last server keyset
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 5.11.3.2629 | 86 | 7/16/2026 |
| 5.11.2.2629 | 73 | 7/16/2026 |
| 5.11.1.2629 | 74 | 7/16/2026 |
| 5.11.0.2629 | 90 | 7/16/2026 |
| 5.10.3.2629 | 118 | 7/14/2026 |
| 5.10.2.2628 | 106 | 7/12/2026 |
| 5.10.0.2628 | 107 | 7/12/2026 |
| 5.9.1.2626 | 120 | 6/23/2026 |
| 5.8.2.2623 | 123 | 6/6/2026 |