Skip to main content

Authentication

The CLI authenticates using the OAuth2 Device Authorization Grant (RFC 8628). This flow is designed for devices without a browser -- it lets you authenticate by opening a URL on any device and entering a short code.

Login​

achilles login

The login flow works in three steps:

  1. The CLI requests a device code from the backend
  2. You open the provided URL in a browser and enter the displayed code
  3. The CLI polls the backend until you authorize, then stores the tokens
  Authenticating with http://localhost:3000

Open this URL in your browser:
https://your-deployment.example.com/cli/verify
Enter code: ABCD-1234
Expires: 10:35:00 PM

Waiting for authorization......

✓ Logged in successfully!
info

The device code expires after 10 minutes. If you don't complete authorization in time, run achilles login again.

Profile-Aware Login​

If you have multiple profiles configured, achilles login authenticates against the active profile's server URL. Each profile maintains its own authentication state.

# Switch to production profile, then login
achilles config use production
achilles login

Token Storage​

Tokens are stored as JSON files in the ~/.achilles/ directory:

FileDescription
~/.achilles/auth.jsonTokens for the default profile
~/.achilles/auth-{profile}.jsonTokens for named profiles (e.g., auth-railway.json)

All auth files are created with 0600 permissions (owner read/write only).

The stored token contains:

FieldDescription
access_tokenJWT for API authentication
refresh_tokenToken for obtaining new access tokens
expires_atExpiration timestamp
user_idClerk user ID
org_idOrganization ID
roleUser role (admin, operator, analyst, explorer)
emailUser email address
display_nameHuman-readable name
issued_atWhen the token was issued

Automatic Token Refresh​

The CLI automatically handles token lifecycle:

  • Before each API call, the stored token is checked for expiration
  • Tokens are considered expired 5 minutes before their actual expiry time (refresh margin)
  • If expired, the HTTP client attempts a transparent refresh using the refresh_token
  • If refresh fails, you are prompted to run achilles login again
tip

You generally never need to think about token refresh -- it happens transparently. If you see an authentication error, just run achilles login.

Logout​

achilles logout

This deletes the token file for the active profile. It does not revoke the token on the server side.

  ✓ Logged out. Tokens cleared.

Checking Auth Status​

Use the status command to verify your authentication state:

achilles status
  ProjectAchilles CLI v0.1.0

Server: http://localhost:3000
User: John Doe
Org: org_default
Role: admin

● Backend connected
Fleet: 12 agents (10 online, 2 offline)

Defense Score: 73.2% ████████████████████░░░░░░░░
42 protected / 16 unprotected / 58 total

If you are not logged in, the status command shows:

  Auth:      Not logged in — run achilles login

Error Handling​

The CLI provides clear guidance when authentication issues occur:

ErrorMeaningSolution
AuthErrorToken expired or invalidRun achilles login
NetworkErrorCannot reach the backendCheck server URL with achilles config get server_url
HTTP 410 during loginDevice code expiredRun achilles login again
# If you see auth errors with any command:
✗ Authentication required
Run achilles login to authenticate.