Skip to main content
The CLI uses the OAuth 2.0 device authorization flow to authenticate against an Ekanos deployment. Your credentials are stored locally in a mode-restricted file keyed by host.

Quick start

No browser port binding, no loopback redirect needed — the flow works over SSH, in containers, and from CI.

Login flow

  1. Run ekanos login --host <url>
  2. The CLI prints a short code and a browser URL to stderr
  3. Open the URL in any browser on any device
  4. Approve the request
  5. The CLI polls and confirms when approved
The device code and URL go to stderr so they’re visible even when stdout is piped. There is nothing to configure on your side: the CLI asks the host for its login configuration, so one binary works against any deployment. If the code expires before you approve it, login exits 4 with The login code expired before it was approved. — run ekanos login again.

Host resolution

logout, whoami, status, sources, use, publish, and upgrade resolve the host in this order:
  1. --host flag
  2. EKANOS_HOST environment variable
  3. host field in ekanos.json (the project’s deployment)
  4. Sole stored host (if your credentials file holds exactly one)
The first source that has an answer wins. When the host comes from ekanos.json or the sole stored login, the CLI names it on stderr. login is special: it resolves from --host, else EKANOS_HOST, else the sole stored host — never from ekanos.json. Login is the one verb that creates credentials, and ekanos.json is committed to git; if login honored it, anyone could point your device flow at their own tenant just by editing a file.

Example: single-deployment workflow

Example: multi-deployment workflow

ekanos use and a successful ekanos publish write host to ekanos.json only when it has no host yet; an existing value is never overwritten by a one-off --host. After that, verbs in the project resolve the host from ekanos.json.

No host specified, multiple stored

This is a usage error (exit 2). The CLI never picks a host silently.

Credential storage

Credentials are stored in ~/.ekanos/credentials.json with mode 0600, inside a ~/.ekanos directory forced to 0700. Writes go to a temporary file that is renamed into place.

File structure

Each entry is keyed by the normalized host origin (scheme and host, lowercased, no trailing slash). accessToken is the short-lived Ekanos JWT; auth0RefreshToken is the rotating refresh token. A file that is not valid JSON or not a recognized credentials file is a precondition_failed error (exit 9) rather than a silent logout. It holds only credentials, so deleting it and running ekanos login again is safe.

Relocation

Set EKANOS_HOME to use a different home directory (useful in containers, CI):
Credentials are then stored in $EKANOS_HOME/.ekanos/credentials.json.

Permissions

If the file or directory is group- or world-accessible, the CLI tightens the permissions and warns on stderr, for example:
The CLI does not refuse to run. If the machine is shared, assume the token was exposed and re-authenticate.

No token in output

Tokens are never printed — not by whoami, not in error messages, not in --json envelopes, not at any log level.

Idempotence

Login

Running ekanos login with a session that still works verifies it against the server and exits 0 without opening a browser:
In JSON mode, data.status is already-authenticated (versus authenticated after a fresh login). Use --force to start a fresh login regardless:

Logout

Logging out twice exits 0 both times:
In JSON mode data is { host, cleared, revoked }; the second run reports cleared: false. --all signs out of every stored host and reports per-host revoked results. Revocation is attempted but never blocks the local delete: try to revoke, always delete, report both.

Rotation safety

Auth0 rotates the refresh token the moment the server’s exchange succeeds, so from that instant the replacement is the only copy in existence — and /api/auth/cli-refresh can still fail afterwards. It therefore returns the rotated token on its error responses too, and the CLI persists it the moment it is seen, before surfacing any error.

Single process: rotate, then fail

  1. The CLI refreshes the session
  2. The refresh token rotates and is saved immediately
  3. A later step fails
  4. Retry the command — the saved token is used
A transient blip costs you a retry, not your session. If the host renewed the session but could not verify the identity, the CLI exits 8 with a hint saying you do not need to log in again.

Two processes: concurrent rotation

Two CLIs sharing one credentials file both present the same token. Auth0 honors the first; the second gets a clean exit 4 (auth_required). There is no file lock — re-run ekanos login.

Exit codes

  • 0 — Success
  • 2 — No host could be resolved
  • 4 — Auth required: no session, an expired one that could not be renewed, or a revoked one. Run ekanos login
  • 8 — Network: the host was unreachable, or the refresh rotated but could not complete. Retry; do not log in again
  • 9 — Precondition: an unreadable credentials file, an invalid --host URL, or a host without CLI login configured

Troubleshooting

Not logged in to a host

You haven’t authenticated against that host yet. Exit 4. Fix: Run ekanos login --host <url>.

Several hosts stored and none chosen

See No host specified, multiple stored. Fix: Use --host or set EKANOS_HOST:

Revocation failed during logout

The local delete succeeded; only revocation did not. logout still exits 0 and reports revoked: false. Fix: Nothing urgent — the token is off your machine. If the machine is compromised, ask your Ekanos operator to revoke the session.

Session expired and could not be renewed

The refresh token expired, was revoked, or was already spent by another process sharing the credentials file. Exit 4. A related message is The session for https://your-ekanos-host could not be renewed. Fix: Re-authenticate:

Plaintext HTTP warning

http:// is allowed (local development needs it), but a non-loopback plaintext host gets this warning. Use https://.