> ## Documentation Index
> Fetch the complete documentation index at: https://api.simkl.org/llms.txt
> Use this file to discover all available pages before exploring further.

# PIN flow

> Device-friendly auth flow for TVs, consoles, CLIs, and other limited-input devices.

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

<Steps>
  <Step title="Request a device code" icon="qrcode">
    `GET /oauth/pin?client_id=…` returns:

    ```json theme={"theme":{"light":"github-light","dark":"vesper"}}
    {
      "result":           "OK",
      "device_code":      "DEVICE_CODE",
      "user_code":        "ABCDE",
      "verification_uri": "https://simkl.com/pin",
      "verification_url": "https://simkl.com/pin",
      "expires_in":       900,
      "interval":         5
    }
    ```

    Show `user_code` to the user. `expires_in` is 15 minutes; `interval` is 5 seconds (your polling cadence).

    <Note>
      `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.
    </Note>

    <Note>
      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.
    </Note>
  </Step>

  <Step title="Display the code and instructions" icon="display">
    Tell the user: *"Go to [simkl.com/pin](https://simkl.com/pin/) and enter `ABCDE`."* Render the code in a large, easy-to-read style — it's typed by hand on a phone.
  </Step>

  <Step title="Poll for the result" icon="rotate">
    `GET /oauth/pin/{USER_CODE}?client_id=…` every `interval` seconds. Two response shapes:

    ```json theme={"theme":{"light":"github-light","dark":"vesper"}}
    // Still pending — keep polling
    { "result": "KO", "message": "Authorization pending" }

    // User approved — stop polling, store access_token
    { "result": "OK", "access_token": "..." }
    ```

    <Warning>
      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.
    </Warning>

    <Note>
      **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.
    </Note>
  </Step>

  <Step title="Store the token and stop polling" icon="circle-check">
    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](https://simkl.com/settings/connected-apps/); on the next 401, restart the PIN flow.
  </Step>
</Steps>

## Why PIN vs OAuth?

|                           | PIN                                                          | OAuth 2.0                                      |
| ------------------------- | ------------------------------------------------------------ | ---------------------------------------------- |
| **Best for**              | TVs, consoles, watches, CLI tools, media-server plugins, IoT | Mobile apps, web apps, desktop apps            |
| **Needs `client_secret`** | No                                                           | Yes (or PKCE for public clients)               |
| **Needs `redirect_uri`**  | No                                                           | Yes (or PKCE-only with no registered redirect) |
| **User experience**       | App shows code → user types it on phone                      | Tap login → browser → approve → back to app    |
| **Time to token**         | 30 seconds – 2 minutes                                       | \~5 seconds                                    |

See [Choose a flow](/api-reference/auth) for the full per-platform comparison and code samples.

## See also

<CardGroup cols={2}>
  <Card title="Choose a flow" icon="shield-halved" href="/api-reference/auth">
    Platform-by-platform recommendations, side-by-side comparison, common pitfalls.
  </Card>

  <Card title="OAuth 2.0 flow" icon="lock" href="/api-reference/oauth">
    The alternative for browsers, mobile, and desktop — token in \~5 seconds.
  </Card>

  <Card title="GET /oauth/pin" icon="qrcode" href="/api-reference/simkl/get-pin">
    Endpoint reference — request a `user_code`.
  </Card>

  <Card title="GET /oauth/pin/{USER_CODE}" icon="rotate" href="/api-reference/simkl/check-pin">
    Endpoint reference — poll for the access token.
  </Card>
</CardGroup>
