CLI Auth
Signing the CLI in with the browser (RFC 8628 device authorization grant).
| Method | Path | Summary |
|---|---|---|
GET | /auth/cli/device | Preview CLI Sign-In |
POST | /auth/cli/device/approve | Approve CLI Sign-In |
POST | /auth/cli/device/code | Start CLI Sign-In |
POST | /auth/cli/device/deny | Deny CLI Sign-In |
POST | /auth/cli/device/token | Poll CLI Sign-In |
Preview CLI Sign-In
Called by the dashboard /cli page for a signed-in human before approving. Returns what the CLI reported (client, hostname; self-reported) and the key approval would create; never the device code. 404 for an unknown, decided or expired code. Dashboard session only: API keys are not accepted. Every call counts against a per-user and per-IP limit on code lookups (brute-force brake): 429 with Retry-After.
Authentication: the dashboard mm_session cookie.
Query parameters
user_codestringRequiredResponse
200 The pending sign-in (application/json)
user_codestringRequireddevice_idstringRequiredclient_idstringRequiredclient_namestring | nullRequiredhostnamestring | nullRequiredkey_namestringRequiredpermissionsstring[]Requiredcreated_atstring (date-time)Requiredexpires_atstring (date-time)RequiredErrors
| Status | Meaning |
|---|---|
400 | Invalid request: error.type is validation and error.param names the field. |
401 | Missing, invalid, expired or revoked credential. |
429 | Rate limited. |
500 | Unexpected server error. |
Error bodies use the error envelope.
Example
Approve CLI Sign-In
Approves a pending code for the signed-in user. The CLI’s next poll receives a new API key named CLI on <hostname> in the user’s organization (every permission except inbound_raw), listed under API keys and revocable there. Dashboard session only. Every call counts against a per-user and per-IP limit on code lookups (brute-force brake): 429 with Retry-After.
Authentication: the dashboard mm_session cookie.
Request body
Content type: application/json.
user_codestringRequiredResponse
200 Approved (application/json)
status"approved" | "denied"Requiredkey_namestringRequiredErrors
| Status | Meaning |
|---|---|
400 | Invalid request: error.type is validation and error.param names the field. |
401 | Missing, invalid, expired or revoked credential. |
429 | Rate limited. |
500 | Unexpected server error. |
Error bodies use the error envelope.
Example
Start CLI Sign-In
RFC 8628 device authorization request, made by mm login. Returns a device_code for the CLI to poll with and a user_code (XXXX-XXXX) for the human to approve at verification_uri (<PUBLIC_URL>/cli) while signed in to the dashboard. Both expire after 10 minutes.
Form-encoded or JSON body. client_id must be machinemail-cli (401 invalid_client otherwise). Rate limited per client IP: 429 rate_limited with Retry-After.
Authentication: None.
Request body
Content type: application/x-www-form-urlencoded or application/json. Required.
client_idstringRequiredclient_namestringhostnamestringResponse
200 Codes issued (application/json)
Headers:
Cache-Controlstringdevice_codestringRequireduser_codestringRequiredverification_uristringRequiredverification_uri_completestringRequiredexpires_inintegerRequiredintervalintegerRequiredErrors
| Status | Meaning |
|---|---|
400 | OAuth error invalid_request. |
401 | OAuth error invalid_client. |
429 | OAuth error rate_limited. |
500 | Unexpected server error. |
Example
Deny CLI Sign-In
Denies a pending code: the CLI’s next poll gets access_denied and no key is created. Dashboard session only. Every call counts against a per-user and per-IP limit on code lookups (brute-force brake): 429 with Retry-After.
Authentication: the dashboard mm_session cookie.
Request body
Content type: application/json.
user_codestringRequiredResponse
200 Denied (application/json)
status"approved" | "denied"Requiredkey_namestringRequiredErrors
| Status | Meaning |
|---|---|
400 | Invalid request: error.type is validation and error.param names the field. |
401 | Missing, invalid, expired or revoked credential. |
429 | Rate limited. |
500 | Unexpected server error. |
Error bodies use the error envelope.
Example
Poll CLI Sign-In
RFC 8628 token request with grant_type=urn:ietf:params:oauth:grant-type:device_code. Poll no faster than interval seconds until the human decides.
After approval the next poll returns a new organization API key (CLI on <hostname>, every permission except inbound_raw, attributed to the approving user) as access_token, once: the device code is then spent.
Errors (RFC 6749 section 5.2 bodies, status 400): authorization_pending (keep polling), slow_down (polled faster than the interval; add 5 seconds), expired_token (start again), access_denied (denied in the browser), invalid_grant (unknown or already used device code), unsupported_grant_type, invalid_request.
Authentication: None.
Request body
Content type: application/x-www-form-urlencoded or application/json. Required.
grant_typestringRequireddevice_codestringRequiredclient_idstringRequiredResponse
200 The new API key, returned once (application/json)
Headers:
Cache-ControlstringPragmastringaccess_tokenstringRequiredtoken_type"Bearer"Requiredapi_key_idstringRequiredkey_namestringRequiredorganization is a Organization:
organization_idstringRequirednamestringRequiredslugstringRequiredplan"free" | "pro" | "enterprise"Requiredinbox_countintegerRequireddomain_countintegerRequiredusageobjectshared_domainstringupdated_atstring (date-time)Requiredcreated_atstring (date-time)Requireduser is a User:
user_idstringRequiredemailstringRequirednamestring | nullorganization_idstringRequiredrole"owner" | "admin" | "member"Requiredcreated_atstring (date-time)RequiredErrors
| Status | Meaning |
|---|---|
400 | OAuth error: authorization_pending, slow_down, expired_token, access_denied, invalid_grant, unsupported_grant_type, invalid_request. |
500 | Unexpected server error. |