> ## 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.

# OAuth flow (AUTH V1)

> AUTH V1 — authorize a user, get a code, exchange it for an access token.

<Warning>
  **A V2 `client_id` cannot use this flow.** It is refused with `400` [`unauthorized_client`](/conventions/errors#unauthorized-client) and a message naming the V2 endpoint to use instead. A registration is V1 or V2, never both — see [AUTH V2](/api-reference/auth-v2).
</Warning>

<Note>
  **This is the AUTH V1 flow, and V1 is being retired** — apps on it are expected to stop working around April 2027. It still works today, but new integrations should use [AUTH V2](/api-reference/auth-v2) and existing ones should plan to move. The V2 equivalent of this page is the [authorization code flow](/api-reference/oauth2-authorization-code); the path across is [Migrating from V1 to V2](/guides/migrating-v1-to-v2).
</Note>

There's no reinventing the wheel here — the API uses OAuth 2.0.

Requesting user-associated information requires a `token` that needs to be included in all request headers made to the API.

To obtain the `client_id` and `client_secret`, please [create an app first](https://simkl.com/settings/developer/).

<Warning>
  **Two domains, two roles.** OAuth uses **two different hosts** — easy to mix up, and the most common cause of "404 Not Found" during integration:

  | Endpoint | Host | What it does |
  | - | - | - |
  | `/oauth/authorize` — **browser URL, not an API call** | **`simkl.com`** | Browser-facing consent page. The user lands here, signs in, and approves your app. |
  | `POST /oauth/token` | **`api.simkl.com`** | Server-to-server code exchange. Your backend posts the `code` here and gets back an `access_token`. |

  If your authorize URL points at `api.simkl.com` you'll get a 404 — it has to be `simkl.com`.
</Warning>

To make calls on behalf of a user you have to obtain an `access_token`. To do this, first send the user to **`https://simkl.com/oauth/authorize`** to receive a `code`, then post it in JSON format to **`https://api.simkl.com/oauth/token`**. The response contains the `access_token`.

## STEP 1 — Authorize (`simkl.com`)

Open a URL like the one below in the user's browser or a Custom Tab (do **not** use a WebView on mobile):

```
https://simkl.com/oauth/authorize?response_type=code&client_id=YOUR_CLIENT_ID&redirect_uri=http://yourdomain.com/oauth.html&state=RANDOM_CSRF_TOKEN&app-name=my-app-name&app-version=1.0
```

Simkl will redirect back to your `redirect_uri` with `?code=...` appended (and `&state=...` if you sent one).

<Note>
  Build this URL against `https://simkl.com` — **not** `https://api.simkl.com`. The API host has no `/oauth/authorize` page.
</Note>

<Tip>
  **Use `state` for CSRF protection.** Generate a random string before redirecting and store it on your session. When the redirect arrives, verify the `state` echoed back matches what you sent. If it doesn't, reject the request — someone else may have started a flow on your behalf.
</Tip>

<Warning>
  **User denial doesn't return an `error=` parameter.** If the user clicks "No" on the consent screen, Simkl redirects to `/` on simkl.com — **not** back to your `redirect_uri` with `error=access_denied`. Treat any flow where the redirect never lands within a sensible timeout (e.g. 5 minutes) as a denial / cancellation and let the user retry.
</Warning>

## STEP 2 — Exchange code for token (`api.simkl.com`)

POST the `code` to `https://api.simkl.com/oauth/token` with your `client_id`, `client_secret`, `redirect_uri`, and `grant_type=authorization_code`.

<Note>
  **Both content-types and both credential locations work.** Simkl's `POST /oauth/token` accepts:

  * `Content-Type: application/x-www-form-urlencoded` (the RFC 6749 §3.2 default) **or** `Content-Type: application/json` — pick whichever your HTTP client prefers
  * Client credentials in the request body (`client_id` + `client_secret` parameters) **or** in the `Authorization: Basic` header (RFC 6749 §2.3.1) — both paths are honored

  That means **off-the-shelf OAuth libraries work out-of-the-box** with no custom encoding or auth-method config. The two equivalent ways to call the token endpoint:

  <CodeGroup>
    ```bash form-encoded (RFC 6749 §3.2 default) theme={"theme":{"light":"github-light","dark":"vesper"}}
    curl -X POST https://api.simkl.com/oauth/token \
      -H "Content-Type: application/x-www-form-urlencoded" \
      -H "User-Agent: my-app-name/1.0" \
      --data-urlencode "client_id=YOUR_CLIENT_ID" \
      --data-urlencode "client_secret=YOUR_CLIENT_SECRET" \
      --data-urlencode "code=AUTHORIZATION_CODE" \
      --data-urlencode "redirect_uri=YOUR_REDIRECT_URI" \
      --data-urlencode "grant_type=authorization_code"
    ```

    ```bash JSON body theme={"theme":{"light":"github-light","dark":"vesper"}}
    curl -X POST https://api.simkl.com/oauth/token \
      -H "Content-Type: application/json" \
      -H "User-Agent: my-app-name/1.0" \
      -d '{
        "client_id":     "YOUR_CLIENT_ID",
        "client_secret": "YOUR_CLIENT_SECRET",
        "code":          "AUTHORIZATION_CODE",
        "redirect_uri":  "YOUR_REDIRECT_URI",
        "grant_type":    "authorization_code"
      }'
    ```
  </CodeGroup>

  For library-specific examples (Python, Node, Java, Go, PHP), see [OAuth client libraries](/api-reference/oauth-libraries) — most are zero-config.
</Note>

The successful response contains your `access_token`:

```json theme={"theme":{"light":"github-light","dark":"vesper"}}
{
  "access_token": "...",
  "token_type":   "bearer",
  "scope":        "public",
  "expires_in":   157680000
}
```

`expires_in` is **5 years in seconds** — effectively infinite for any realistic session. There's no `refresh_token`; Simkl tokens are long-lived and the API has no refresh-token grant. If a 401 arrives before that lifetime elapses, the user revoked your app at [Connected Apps settings](https://simkl.com/settings/connected-apps/) — restart the flow from STEP 1.

<Note>
  **The authorization `code` is single-use.** As soon as you POST it to `/oauth/token`, the server deletes it — even if the exchange fails (network error, validation mismatch, etc.). If your exchange fails for any reason, don't retry with the same `code` — restart from STEP 1.
</Note>

<Note>
  **Same user, same token.** If the same user runs the OAuth flow twice for your app — whether via the standard flow, PKCE, or PIN — Simkl returns the **same `access_token`** both times (it increments an internal usage counter but doesn't rotate the token). Storing the latest response is safe; you don't need to invalidate older tokens of your own because there aren't multiple ones.
</Note>

<Warning>
  **Public clients (mobile, SPA, browser extensions, desktop binaries) must not embed `client_secret`.** Anything compiled into the user's app should be considered leaked. Use the [Public PKCE flow](/api-reference/oauth-pkce) (`code_verifier` + `code_challenge`) instead — same browser-based UX, no secret required.
</Warning>

## See also

<CardGroup cols={2}>
  <Card title="Set up authentication" icon="shield-halved" href="/api-reference/auth">
    The V2 equivalent of this page's setup: client type, secret, flow and scope.
  </Card>

  <Card title="Public PKCE" icon="shield-keyhole" href="/api-reference/oauth-pkce">
    The variant for mobile, SPA, browser extensions, and desktop binaries — same browser UX, no `client_secret` required.
  </Card>

  <Card title="PIN flow" icon="key" href="/api-reference/pin">
    The alternative for TVs, consoles, watches, CLIs, and media-server plugins — no `client_secret` and no redirect required.
  </Card>

  <Card title="GET /oauth/authorize" icon="arrow-right" href="/api-reference/simkl/authorize">
    Endpoint reference — every accepted query parameter, including PKCE.
  </Card>

  <Card title="POST /oauth/token" icon="key" href="/api-reference/simkl/exchange-token">
    Endpoint reference — body fields, response shape, error codes, interactive playground.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.