# Přihlášení účtem Forendors – integrace pro vývojáře

Umožní podporovatelům tvůrce přihlásit se do jeho webu nebo aplikace účtem Forendors. Aplikace se dozví stabilní identitu uživatele a to, zda a v jakém předplatném tvůrce podporuje. Protokol: OAuth 2.1, authorization code + PKCE (S256), API base `https://api.forendors.cz`.

## 1. Registrace aplikace

Tvůrce ji provede sám v aplikaci Forendors: **Profil → Zabezpečení → Přihlášení účtem Forendors → Přidat aplikaci**.

| Pole | Pravidla |
| --- | --- |
| Název | zobrazí se podporovateli na obrazovce souhlasu |
| Typ | **Web nebo aplikace s vlastním serverem** (confidential): dostane `client_secret`, který smí znát jen server. **Mobilní nebo desktopová aplikace bez serveru** (public): bez secretu, chrání ji jen PKCE. Typ nejde později změnit. |
| Návratové adresy | až 5 adres, porovnávají se přesně. Jen `https://`, pro vývoj `http://localhost` (i s portem) nebo `http://127.0.0.1`. Bez fragmentu. |

- `client_secret` se zobrazí **jen jednou** při vytvoření. Ztracený secret nejde obnovit: aplikaci smažte a založte znovu.
- Ve stejné sekci najdete **ID předplatných a sérií**. Jsou stabilní i při změně ceny a porovnáváte s nimi odpověď `/partner/v1/me/subscription`.

## 2. Endpointy

| Účel | Endpoint |
| --- | --- |
| Autorizace (prohlížeč) | `GET /oauth/authorize` |
| Výměna kódu, obnova tokenu | `POST /oauth/token` |
| Identita podporovatele | `GET /partner/v1/me` |
| Stav podpory u tvůrce | `GET /partner/v1/me/subscription` |

Tokeny platí jen pro `/partner/v1/*`.

## 3. Scopes

| Scope | Co zpřístupní |
| --- | --- |
| *(bez scope)* | `sub` – stabilní UUID uživatele, vždy |
| `profile` | `handle`, `name`, `avatar_url` |
| `email` | `email` (není důkaz vlastnictví, ověřte si ho sami) |
| `subscription:read` | zda uživatel podporuje tvůrce, který aplikaci vlastní, a v jakém předplatném |

Žádejte jen scopes, které potřebujete; web, který pouze odemyká obsah, vystačí se `subscription:read`.

## 4. Průběh přihlášení

1. **PKCE**: vygenerujte `code_verifier`, `code_challenge = BASE64URL(SHA256(code_verifier))`.
2. **Přesměrujte** uživatele na:

```
GET https://api.forendors.cz/oauth/authorize
  ?response_type=code
  &client_id={client_id}
  &redirect_uri={přesně registrovaná adresa}
  &scope=profile%20subscription:read
  &state={náhodná hodnota}
  &code_challenge={code_challenge}
  &code_challenge_method=S256
```

3. Uživatel se přihlásí a potvrdí souhlas.
4. Forendors vrátí na `redirect_uri` s `code` a `state` (při odmítnutí s `error=access_denied`). **Ověřte `state`.**
5. **Vyměňte kód za tokeny** (ze serveru; u aplikace bez serveru z aplikace):

```
POST https://api.forendors.cz/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code
&client_id=…
&client_secret=…            (jen aplikace s vlastním serverem)
&redirect_uri=…
&code=…
&code_verifier=…
```

Odpověď: `token_type: Bearer`, `access_token`, `expires_in`, `refresh_token`.

6. **Obnova**: `grant_type=refresh_token`, `refresh_token`, `client_id` (+ `client_secret`). Refresh token rotuje, starý přestane platit.
7. **Volání API** s hlavičkou `Authorization: Bearer {access_token}`.

## 5. Odpovědi partnerského API

`GET /partner/v1/me`

```json
{ "sub": "8b1e2b7e-…", "handle": "jan_novak", "name": "Jan Novák", "avatar_url": "https://…", "email": "jan@example.com" }
```

`GET /partner/v1/me/subscription` (scope `subscription:read`; tvůrce je vždy vlastník aplikace, žádný parametr)

```json
{
  "creator": { "sub": "…", "handle": "tvurce" },
  "subscribed": true,
  "subscription": {
    "tier": { "id": "3f2a8c…", "title": "Podporovatel", "is_free": false },
    "entitled_tier_ids": ["3f2a8c…", "9b71c4…"],
    "since": "2026-05-01T10:00:00+00:00"
  },
  "series": [{ "id": "c0de55…", "title": "Kurz X", "type": "course" }]
}
```

- Uživatele párujte podle `sub`, ne podle e-mailu; e-mail si může změnit.
- `tier.id` a `series[].id` jsou ID z nastavení tvůrce; bezplatné sledování má `id: null` a `is_free: true`.
- `entitled_tier_ids` obsahuje všechna předplatná, ke kterým má uživatel přístup (i levnější než to, které platí), bez bezplatného.
- Nepodporovatel dostane `subscribed: false`, `subscription: null`, `series: []`.
- Počítá se živě; výsledek si cachujte.

## 6. Platnosti, limity, chyby

| Co | Hodnota |
| --- | --- |
| Access token | 1 hodina |
| Refresh token | 30 dní |
| `/oauth/token` | 120/min na klienta a IP, 600/min na IP |
| `/partner/v1/*` | 120/min na grant (klient + uživatel) |

| Kód | Význam |
| --- | --- |
| `400` na authorize | chybí PKCE S256 |
| `invalid_scope` (redirect) | scope mimo povolený seznam |
| `401` | token chybí, vypršel nebo byl odvolán → obnovte, jinak znovu autorizujte |
| `403` na `/me/subscription` | token nemá `subscription:read` |
| `429` | překročený limit, viz `Retry-After` |

Přístup může kdykoli odvolat uživatel (Profil → Zabezpečení → Propojené aplikace) nebo tvůrce smazáním aplikace; tokeny přestanou platit okamžitě.
