AUTH4D-16 native device authorization
The device flow follows RFC 8628. A native client is identified by both the tenant and client IDs; all one-time state is held in the tenant’s SQLite-backed Durable Object. Device codes are opaque and user codes are hashed before storage.
Start a device authorization
POST /device/authorization?tenant_id={tenantId} uses
application/x-www-form-urlencoded with client_id and scope. The client must be enabled, have
the native type, and allow the device-code grant. openid is required. offline_access is accepted
only when the client also allows the refresh-token grant.
The response is DeviceAuthorizationResponse. Its verification URL is a confirmation page that
shows the registered application, the requested scopes, and the user code. Opening the URL never
approves the device. It includes tenant_id, client_id, and user_code in the complete URL so a
browser can show the exact application and code.
Verify, approve, or deny
GET /device/verify?tenant_id={tenantId}&client_id={clientId}&user_code={userCode} displays the
application and code and asks the user to approve or deny. Approval and denial are explicit button
actions. Both require an authenticated browser session, an exact same-origin Origin, and the
page’s per-flow CSRF cookie and X-CSRF-Token header.
POST /device/approval?tenant_id={tenantId} accepts a JSON DeviceApprovalRequest and returns
{"status":"approved"}. POST /device/denial?tenant_id={tenantId} accepts the same request shape
and returns {"status":"denied"}. The browser flow ID binds the request to the verification page.
The caller cannot change scopes: approval grants exactly the scopes stored when the device request
was created. Approval persists consent, including offline_access when requested.
Poll and exchange
POST /oauth/token?tenant_id={tenantId} accepts an
application/x-www-form-urlencoded DeviceCodeTokenRequest and returns TokenResponse on success.
Pending requests return authorization_pending; polling before the required interval returns
slow_down and increases the required interval by five seconds. A denial returns access_denied,
expiry returns expired_token, and an approved device code can be exchanged once. Tenant and client
identity are part of every device-state lookup, so another tenant or client cannot approve or redeem
the code.
The token response is issued by the shared session service. It includes a refresh token only when
offline_access was explicitly approved and stored in consent.
Source: docs/api-spec/auth4d-16.md