---
title: agent-login
description: The v1 reference for the RFC 8628 device-authorization flow behind shebang-mcp login.
---

# agent-login

Base path `/api/agent-login`. See [device login](/getting-started/device-flow-login)
for the narrative walkthrough this page is the terse reference for — that
page covers what a caller sees; this one covers exact fields and error
codes.

### POST /api/agent-login/device_authorization

RFC 8628 §3.1 — starts a device-authorization request.

- **Auth** — none.
- **Request body** (form-encoded or JSON) — `client_name` (string,
  optional, defaults to `"agent"`).
- **Response** — `200 { "device_code", "user_code", "verification_uri",
  "verification_uri_complete", "expires_in": 600, "interval": 3 }`.
  `Cache-Control: no-store`.
- **Errors** — `400 invalid_request` (malformed body, or an invalid
  `client_name`), `429 rate_limited` (10 requests / 15 minutes per
  client IP).

### POST /api/agent-login/token

RFC 8628 §3.4/§3.5 — polls for the outcome of a device-authorization
request. Looks up by `device_code` alone — a caller can never claim the
key by leaking or guessing the short `user_code` a human reads off the
approval screen.

- **Auth** — none.
- **Request body** (form-encoded or JSON) — `grant_type` (must be
  `"urn:ietf:params:oauth:grant-type:device_code"`, required),
  `device_code` (string, required).
- **Response** — `200 { "access_token", "token_type": "shb", "scope":
  "master", "expires_in": null }` once approved. `Cache-Control:
  no-store`.
- **Errors** — `400 unsupported_grant_type`, `400 invalid_request`
  (missing `device_code`, or a malformed body), `400 invalid_grant`
  (unrecognized or already-claimed `device_code`), `400 access_denied`,
  `400 expired_token`, `400 authorization_pending` (still waiting — poll
  again), `400 slow_down` (with a larger `interval` — back off), `429
  rate_limited` (600 requests / 15 minutes per client IP).

### POST /api/agent-login/decision

Backs the `/authorize-agent` consent screen's Approve/Deny buttons — not
an API a caller ever calls directly; documented here because it lives
under `/api/agent-login/**`.

- **Auth** — a signed-in dashboard session cookie, with the second
  factor already satisfied if the account has one enrolled.
- **Request body** (form-encoded) — `code` (string, required — the
  `user_code`), `decision` (`"approve"` or `"deny"`, required).
- **Response** — `303` redirect back to `/authorize-agent`.
- **Errors** — `403 invalid origin` (cross-site form submission), `400
  invalid request` (malformed `code` or `decision`), `401 not signed in`,
  `403 mfa_required` (second factor not yet satisfied this session).
