Start an OAuth Device Authorization Grant.
curl --request POST \ --url https://auth.example.com/device_authorization \ --header 'Content-Type: application/x-www-form-urlencoded' \ --data client_id=client_123 \ --data 'scope=openid profile email'With tenant assurance enabled and a default FAL of FAL3 (with fal3_requires_par), which needs a pushed, signed authorization request, every request is refused with unauthorized_client. Assurance settings that cannot be read return 503 temporarily_unavailable. A user code another live device code already holds is not reused: a new one is generated, up to 5 attempts. When no unique user code could be stored, the response is 503 temporarily_unavailable with Retry-After: 1. The expires_in and interval of the response come from the device flow settings of the tenant and, for a client that has its own, of the client (the client’s value wins, held between the tenant’s bounds): device_flow.expires_in kept between device_flow.min_expires_in and device_flow.max_expires_in (never above one hour), and device_flow.poll_interval kept between device_flow.min_interval and device_flow.max_interval. With nothing saved they are 600 and 5. The settings are read only for a registered client that may use the grant (an unknown client or one that may not is refused first). Device flow settings that cannot be read return 503 temporarily_unavailable and no code is issued. The code keeps device_flow.slow_down_increment, device_flow.max_poll_count and device_flow.max_interval as they were when it was issued; the token endpoint applies them while the device polls. The request must be application/x-www-form-urlencoded, and client_id, client_secret, client_assertion, client_assertion_type and scope may each appear once (a repeated, non-string or oversized parameter is 400 invalid_request; client_id is up to 256 characters, scope up to 2048); the body is limited to 64 KiB as it is read, whatever Content-Length says (a larger one is 400 invalid_request). A public client (token_endpoint_auth_method none, the only kind the token endpoint’s device_code grant treats as public) sends its client_id only; a client with no registered method and no secret authenticates as a confidential one, and so is refused. A confidential client authenticates as at the token endpoint (RFC 8628 section 3.1): client_secret_basic (client_id may then come from the Authorization header only), client_secret_post or private_key_jwt (the assertion audience may be this endpoint, the token endpoint or the issuer). A client that does not exist and a client that fails to authenticate get the same 401 invalid_client (with WWW-Authenticate: Basic when the client sent a Basic Authorization header); only an authenticated client learns that it may not use the grant (400 unauthorized_client). A scope that is malformed, or that the client may not request (its requestable_scopes, else allowed_scopes, else its registered scope, else openid profile email; the same rule as /authorize), is 400 invalid_scope; openid is not required. With no scope (or a blank one) the code is issued for openid profile email narrowed to what the client may request, and 400 invalid_scope when that is nothing. The scope is stored once per scope, separated by single spaces. Requests are limited per IP address (the moderate rate limit profile, 60 per minute by default) and, once the client is authenticated, per client (the lenient profile, 300 per minute by default); both follow rate_limit.moderate, rate_limit.lenient and their _window_seconds in the platform rate limit settings. Over a limit the answer is 429 rate_limit_exceeded with Retry-After and X-RateLimit-* headers; a rate limiter that cannot answer is 503 temporarily_unavailable (no code is issued). Every answer, the early refusals included, carries Cache-Control: no-store and Pragma: no-cache. Known limit: whether a client exists may be told from the response time (an unregistered client skips the secret check, and a private_key_jwt client with a jwks_uri has its key set fetched before the signature fails), as at /bc-authorize; evening it out belongs to the shared client authentication code.
Request Body
Section titled “Request Body ”object
Required unless the client sends it in the Authorization header (client_secret_basic) or as the subject of its client_assertion.
For a client registered with client_secret_post.
For a client registered with private_key_jwt.
Example
client_id=client_123&scope=openid+profile+emailResponses
Section titled “ Responses ”Successful JSON response.
object
The code the user types on the verification page, in groups of 4 characters separated by a hyphen. Its alphabet and length come from the tenant’s device_flow.user_code_charset (BASE31, BASE20 or NUMERIC) and device_flow.user_code_length (4 to 16 characters, at least 34 bits of entropy), so the format varies by tenant. A tenant with no setting issues 8 characters of BASE31, for example WDJB-MJHT; 11 digits look like 1234-5678-901.
Example
{ "device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS", "user_code": "WDJB-MJHT", "verification_uri": "https://auth.example.com/device", "verification_uri_complete": "https://auth.example.com/device?user_code=WDJB-MJHT&tenant_hint=tenant_123", "expires_in": 600, "interval": 5}OAuth error response.
object
Example generated
{ "error": "example", "error_description": "example"}OAuth error response.
object
Example generated
{ "error": "example", "error_description": "example"}OAuth error response.
object
Example generated
{ "error": "example", "error_description": "example"}OAuth error response.
object
Example generated
{ "error": "example", "error_description": "example"}