Auth (OTP signup & login)
codika-os authenticates via a two-step OTP flow from the terminal. No browser round-trip required.
There are two forks: signup (new email) and login (existing account on a new machine). Both forks have the same shape: a *-request command that emails a 6-digit code, then a *-complete command that consumes the code and mints a cos_… key.
Signup (new user)
Section titled “Signup (new user)”codika-os auth signup-request --email you@codika.ioOutput:
✓ OTP sent Email: you@codika.io Expires: in 10 minutes Resend: not before 30 secondsA 6-digit code arrives at you@codika.io. Then:
codika-os auth signup-complete --email you@codika.io --code 123456Output:
✓ Signup complete
Email: you@codika.io Profile: you (now active) API key: cos_xxxx... (scopes: all)
Try it: codika-os whoamicodika-os has no organization concept. The API key is owned by the worker email — there’s no --company, --brand-*, or --tone to pass.
The cos_… key is now stored in ~/.codika-os/config.json (mode 0600) as the active profile.
Login (existing user, new machine)
Section titled “Login (existing user, new machine)”Same two steps, different commands:
codika-os auth login-request --email you@codika.iocodika-os auth login-complete --email you@codika.io --code 123456Choosing the right fork
Section titled “Choosing the right fork”The /codika-os:setup-codika-os skill handles this automatically. If you’re running the CLI by hand:
- Never used codika-os? →
signup-request/signup-complete. - Used it before, just on a different machine? →
login-request/login-complete. - Not sure? → Try signup first; if the email already has dashboard access, the signup endpoint still works and reports
isNewUser: false. Use login when you only need a fresh key.
Auth always reads PROD. OTPs, API keys, and dashboard_access rows all live in PROD regardless of which mode the CLI is syncing tracking data to. Admins grant access via PROD’s dashboard_access table.
no_dashboard_access on login? Your email doesn’t have a row in PROD’s dashboard_access table. Ask an admin to invite you, then re-run login-request.
Error codes
Section titled “Error codes”Every auth … error returns a JSON shape (with --json) like:
{ "success": false, "error": { "code": "OTP_EXPIRED", "message": "The code expired. Request a new one.", "nextAction": "codika-os auth signup-request --email you@codika.io" }}| Code | What it means | nextAction |
|---|---|---|
OTP_NOT_FOUND | No active OTP for that email | Run *-request again |
OTP_EXPIRED | The code’s 10-minute window passed | Run *-request again |
OTP_CONSUMED | The code was already used | Run *-request again |
OTP_MISMATCH | Wrong code | Re-enter — counts against the 5-attempt lockout |
OTP_LOCKED | 5 failed attempts | Wait, then *-request again |
OTP_RESEND_COOLDOWN | Less than 30s since last *-request | Wait, then retry |
no_dashboard_access | Login attempted, but no dashboard_access row exists for this email in PROD | Ask an admin to invite the email, then re-run login-request |
domain_not_allowed | Non-@codika.io email | Use a Codika email |
internal_error | Server-side failure | Surface the message and retry |
The nextAction string is designed to be acted on programmatically. Pass it through to the user verbatim — it tells them (or the agent) exactly what to run next.
Whoami and verify
Section titled “Whoami and verify”After auth, sanity-check the active key:
codika-os whoamicodika-os verifywhoami reads the local config. verify round-trips the key against /api/auth/cli/verify on the app, confirming it’s still valid server-side.
Multiple profiles
Section titled “Multiple profiles”Sign in to a second org or a dev environment without overwriting the active key:
codika-os auth login-request --email you@codika.io --profile dev-localcodika-os auth login-complete --email you@codika.io --code 123456 --profile dev-localcodika-os use dev-localSee configuration for the profile resolution chain.
Source
Section titled “Source”Implementation: codika-os-cli/src/cli/commands/auth/. Server endpoints: codika-os-app/src/lib/server/cli-auth.ts.