Skip to main content
This flow is designed for devices with limited input — media-center plugins, game consoles, smartwatches, smart TVs, command-line tools, system services. Your app shows a short alphanumeric code; the user enters it on their phone or computer; the device polls until they approve. No client_secret and no redirect URI required. After the user authorizes, the device receives an access_token and behaves identically to an OAuth client from that point on.

Steps

Request a device code

GET /oauth/pin?client_id=… returns:
Show user_code to the user. expires_in is 15 minutes; interval is 5 seconds (your polling cadence).
device_code is returned as the literal string "DEVICE_CODE" — it’s a placeholder field kept for OAuth 2.0 Device Authorization Grant response-shape compatibility. Clients only need user_code. You can ignore device_code entirely.
The response also includes a verification_url key with the same value, kept as an alias. Read verification_uri — that’s the RFC 8628 §3.2 spelling.

Display the code and instructions

Tell the user: “Go to simkl.com/pin and enter ABCDE.” Render the code in a large, easy-to-read style — it’s typed by hand on a phone.

Poll for the result

GET /oauth/pin/{USER_CODE}?client_id=… every interval seconds. Two response shapes:
Respect the returned interval (5 seconds). Polling faster won’t help — the user enters their PIN at human speed. Once expires_in (15 minutes) elapses, the user_code is dead; request a fresh one and restart.
Stop polling as soon as you receive the access_token. After successful authorization the server deletes the code; if you keep polling on the deleted (or any unknown) user_code, this endpoint falls through to the create-a-new-code branch and you’ll get back the same shape as GET /oauth/pin — including a brand-new user_code different from the one you polled. Detect any response containing device_code as “the original code is gone” and stop.

Store the token and stop polling

Save the access_token securely. From here on, the device works like any OAuth client — send Authorization: Bearer <access_token> on every authenticated request. Tokens are long-lived — the token-mint response advertises expires_in: 157680000 (about 5 years), and there’s no refresh-token grant. They only stop working when the user revokes your app from Connected Apps settings; on the next 401, restart the PIN flow.

Why PIN vs OAuth?

See Choose a flow for the full per-platform comparison and code samples.

See also

Choose a flow

Platform-by-platform recommendations, side-by-side comparison, common pitfalls.

OAuth 2.0 flow

The alternative for browsers, mobile, and desktop — token in ~5 seconds.

GET /oauth/pin

Endpoint reference — request a user_code.

GET /oauth/pin/{USER_CODE}

Endpoint reference — poll for the access token.