Start device sign-in with a one-time code (RFC 8628)
const url = 'https://api.harperharbor.com/oauth/device_authorization';const options = { method: 'POST', headers: {'Content-Type': 'application/x-www-form-urlencoded'}, body: new URLSearchParams({client_id: 'example', scope: 'example', resource: '<API_BASE>/open/v1'})};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.harperharbor.com/oauth/device_authorization \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data client_id=example \ --data scope=example \ --data 'resource=<API_BASE>/open/v1'For command-line tools and devices that cannot receive a browser redirect. Accepts application/x-www-form-urlencoded (or multipart form) fields only; no client authentication (public clients). Show user_code and verification_uri to the person: they open the verification page on any device, sign in, type the code the tool shows and approve. Meanwhile poll POST /oauth/token with grant_type=urn:ietf:params:oauth:grant-type:device_code, device_code and client_id, waiting at least interval seconds between polls, until it returns tokens or a final error. Both codes expire after 15 minutes. Device sign-in is off by default: the administrator of the application that owns the client turns it on per client. Other clients get unauthorized_client and should use /oauth/authorize.
Request Bodyrequired
Section titled “Request Bodyrequired”object
A client with device sign-in turned on.
Optional, space-separated. Defaults to every scope the client is allowed; each requested scope must be one of them. Device sign-in never grants console: asking for it, or a default that includes it, is invalid_scope.
Resource indicator (RFC 8707), same values as /oauth/authorize. The issued token is only valid on this resource.
object
A client with device sign-in turned on.
Optional, space-separated. Defaults to every scope the client is allowed; each requested scope must be one of them. Device sign-in never grants console: asking for it, or a default that includes it, is invalid_scope.
Resource indicator (RFC 8707), same values as /oauth/authorize. The issued token is only valid on this resource.
Responses
Section titled “Responses”Codes for the person and for polling. Sent with Cache-Control: no-store.
object
Opaque secret for polling /oauth/token. Keep it in the client; never show it.
Eight letters from BCDFGHJKLMNPQRSTVWXZ, formatted XXXX-XXXX. The verification page ignores case and any character that is not a letter.
Verification page. Show it next to user_code; the person opens it on any device and types the code there.
Seconds until both codes expire: 900.
Minimum seconds between polls of /oauth/token: 5. Add 5 after each slow_down.
Examplegenerated
{ "device_code": "example", "user_code": "example", "verification_uri": "https://example.com", "expires_in": 1, "interval": 1}unauthorized_client — device sign-in is not turned on for this client (use /oauth/authorize); invalid_client; client_not_active; invalid_scope; invalid_resource.
object
OAuth error code.
Only on the internal consent endpoints when the request expired.
Seconds to wait before trying again; only with rate_limited.
Examplegenerated
{ "error": "example", "redirect_url": "example", "retry_after": 1}rate_limited, with retry_after in seconds — too many codes requested from one address in the past hour, or too many pending requests for this client.
object
OAuth error code.
Only on the internal consent endpoints when the request expired.
Seconds to wait before trying again; only with rate_limited.
Examplegenerated
{ "error": "example", "redirect_url": "example", "retry_after": 1}