Skip to content
Masko logomasko
Docs
Documentation

CLI browser login

For server-side REST integrations, start with API keys and workspaces. This guide covers the first-party CLI login and its authorization endpoints. Install the CLI using the terminal quickstart.

Sign in from the terminal

The CLI browser flow is implemented in the developer preview. Production requires the matching backend deployment. If the server does not support browser sign-in, the CLI explains the error. It never silently changes to API-key login.

masko login                         # Open browser, approve, return automatically
masko login --no-browser            # Open the printed URL yourself on this computer
masko login --device --no-browser   # Device code for SSH or a remote terminal
masko login --scope read            # Request read-only access
masko whoami --json                 # Account, workspace, permissions, credits
masko logout                       # End this CLI session

Sign in on Masko, choose the workspace, and click Connect. The browser returns a one-time code to the CLI, which completes sign-in using PKCE. No API key needs to be created or pasted. Press Control+C to cancel. Team authorization requires an owner or admin. Access tokens expire after 15 minutes; refresh tokens rotate automatically and are stored in macOS Keychain. Sessions expire after 90 days. Manage individual installations from CLI sessions.

Choosing a workspace

Choose Personal workspace or a team in the browser when running masko login. That choice determines which projects, collections, mascots, assets and jobs the session can access, and which credit balance pays for generation. Run masko login again and select another workspace to change the terminal's saved login. Team authorization requires an owner or admin. Account membership and project access restrictions still apply after login.

A resource ID from another workspace returns 404, even if your account belongs to both workspaces. API keys follow the same rule: use a key issued for the target workspace. Public mascot releases remain publicly accessible. Unattached uploads, user templates, creator profiles/listings and webhook registrations retain their account-level ownership. Source assets for collection creation, reference attachments and template extraction must pass the workspace access checks.

The legacy /api/auth/cli callback flow has been retired and returns 410 with instructions to update Masko and run masko login. Existing API keys remain valid. The current browser flow never sends a reusable credential in a redirect URL.

MASKO_API_KEY takes precedence over a saved browser session. An invalid explicit key fails instead of falling back to a different account. To save a key explicitly, use masko login --api-key or masko login --api-key-stdin.

Browser authorization (PKCE)

GET /v1/auth/config returns the browser authorization_endpoint and supported grants. The registered client masko-cli opens that endpoint with:

  • client_id=masko-cli, response_type=code, device_name, and scope=read|write.
  • redirect_uri=http://127.0.0.1:PORT/oauth/callback, using a temporary local port between 1024 and 65535. Other hosts, paths, query strings and fragments are rejected.
  • Independent random state and code_verifier values generated from 32 random bytes, base64url encoded. Send only state, code_challenge=BASE64URL(SHA256(code_verifier)), and code_challenge_method=S256 in the browser URL. Keep the verifier in memory.

After browser approval, check the exact callback path and state, then exchange code at POST /v1/auth/token with a JSON body containing client_id, grant_type: "authorization_code", code, the same redirect_uri, and code_verifier. Authorization codes expire after 120 seconds and can be used once. The callback contains no access token, refresh token, or API key. Cancellation returns error=access_denied with the original state. The CLI closes its listener on completion, cancellation, or timeout (at most 10 minutes).

Device-login REST contract

Use this flow for masko login --device when the browser runs on another computer.

  • POST /v1/auth/device: { "client_id": "masko-cli", "device_name": "My Mac", "scope": "write" }. Returns device_code, user_code, verification_uri, verification_uri_complete, expires_in (600 seconds), and interval (5 seconds) under data.
  • POST /v1/auth/token: send client_id, grant_type: "urn:ietf:params:oauth:grant-type:device_code", and device_code. Poll only at the returned interval. authorization_pending means keep waiting; slow_down means add 5 seconds to all subsequent intervals. Stop on access_denied, expired_token, or invalid_grant.
  • On success, data contains access_token, refresh_token, token_type: "Bearer", expires_in, session_id, and session_expires_at. Never log these tokens.
  • Refresh through the same endpoint with client_id, grant_type: "refresh_token", and refresh_token. Serialize refreshes and securely replace the pair. Reusing a consumed refresh token revokes that session. If a refresh response is lost, log in again.
  • GET /v1/auth/session identifies the current API key or session without returning secrets.
  • POST /v1/auth/revoke with { "refresh_token": "..." } ends that session immediately. This operation is idempotent and does not revoke other sessions or API keys.

These endpoints use Masko's JSON request bodies and {data} / {error} envelopes, with authorization-code/PKCE and device-grant semantics. They are not a general third-party OAuth authorization server or a form-encoded OAuth token endpoint. All auth responses use no-store. The only registered client is masko-cli; never embed a developer key in an app.