# Vytvoření OAuth aplikace

> Umožněte uživatelům připojit vaši aplikaci k jejich workspace v Emailitu přes OAuth 2.1 a PKCE, včetně registrace klienta, obnovy tokenů, odvolání a chyb.

Emailit provozuje autorizační server OAuth 2.1 na `https://api.emailit.com`. Použijte ho, když vytváříte integraci, například CRM, no-code nástroj nebo AI klienta, která jedná jménem uživatelů Emailitu. Uživatelé se přihlásí a schválí přístup v prohlížeči a vy dostanete tokeny pro workspace, které vyberou, aniž byste kdy pracovali s jejich API klíči. Stejný postup používá [MCP server](/cs/docs/mcp/).

## Jak to funguje

1. **Zaregistrujte klienta** dynamickou registrací klienta, nebo hostujte dokument s metadaty klienta.

2. **Pošlete uživatele na autorizační URL** s výzvou PKCE (code challenge).

3. **Uživatel se přihlásí do Emailitu**, vybere workspace, které může vaše aplikace používat, a schválí požadovaný rozsah oprávnění.

4. **Emailit přesměruje zpět** na vaše URI pro přesměrování s jednorázovým autorizačním kódem.

5. **Vyměňte kód** za přístupový token platný 15 minut a obnovovací token.

6. **Volejte API** s přístupovým tokenem a po vypršení ho obnovte.

## Endpointy

| Metoda | Cesta | Účel |
| --- | --- | --- |
| `GET` | `/.well-known/oauth-authorization-server` | Metadata autorizačního serveru (RFC 8414) |
| `GET` | `/.well-known/oauth-protected-resource` | Metadata chráněného zdroje pro REST API |
| `GET` | `/.well-known/oauth-protected-resource/mcp` | Metadata chráněného zdroje pro MCP server |
| `POST` | `/oauth/register` | Dynamická registrace klienta (RFC 7591) |
| `GET` | `/oauth/authorize` | Přihlášení a souhlas v prohlížeči |
| `POST` | `/oauth/token` | Výměna kódu nebo obnovovacího tokenu |
| `POST` | `/oauth/revoke` | Odvolání uděleného přístupu jeho obnovovacím tokenem (RFC 7009) |
| `GET` | `/oauth/grants` | Výpis udělených přístupů (přihlášeného uživatele, nebo s API klíčem jednoho workspace) |
| `POST` | `/oauth/grants/:id/revoke` | Odvolání uděleného přístupu |
| `PUT` | `/oauth/grants/:id/workspaces` | Změna workspace, které smí udělený přístup používat (uživatel, který aplikaci připojil) |

Všechny cesty jsou na `https://api.emailit.com`.

## Zjistěte metadata serveru

```bash
curl https://api.emailit.com/.well-known/oauth-authorization-server
```

```json
{
  "issuer": "https://api.emailit.com",
  "authorization_endpoint": "https://api.emailit.com/oauth/authorize",
  "token_endpoint": "https://api.emailit.com/oauth/token",
  "registration_endpoint": "https://api.emailit.com/oauth/register",
  "revocation_endpoint": "https://api.emailit.com/oauth/revoke",
  "jwks_uri": "https://api.emailit.com/.well-known/jwks.json",
  "code_challenge_methods_supported": ["S256"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "response_types_supported": ["code"],
  "token_endpoint_auth_methods_supported": ["none", "client_secret_basic", "client_secret_post"],
  "client_id_metadata_document_supported": true,
  "authorization_response_iss_parameter_supported": true,
  "scopes_supported": ["sending", "full"]
}
```

MCP klienti místo toho začínají u metadat chráněného zdroje. Neautentizovaný požadavek na `https://api.emailit.com/mcp` vrací `401` s `WWW-Authenticate: Bearer resource_metadata="https://api.emailit.com/.well-known/oauth-protected-resource/mcp"` a tento dokument odkazuje na autorizační server:

```json
{
  "resource": "https://api.emailit.com/mcp",
  "authorization_servers": ["https://api.emailit.com"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["sending", "full"]
}
```

## Rozsahy oprávnění

| Oprávnění | Co uděluje |
| --- | --- |
| `sending` | Odesílání a přeposílání e-mailů a přeplánování, rušení a opakované odeslání. Stejný přístup jako klíč jen pro odesílání. |
| `full` | Všechny endpointy REST API a nástroje MCP. Stejný přístup jako klíč s plným přístupem. |

`full` už zahrnuje vše, co povoluje `sending`. Pokud vaše aplikace jen odesílá, žádejte o `sending`, jinak o `full`; přijímá se i `sending full` oddělené mezerou. Pokud `scope` vynecháte, Emailit použije všechna oprávnění, která klient zaregistroval.

## Zaregistrujte klienta

Klienta můžete zaregistrovat dvěma způsoby. Oba fungují se všemi postupy na této stránce.

### Dynamická registrace klienta

Pošlete požadavek na registraci. Autentizace není potřeba a z každé IP adresy lze zaregistrovat až 20 klientů za hodinu.

```bash
curl https://api.emailit.com/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "Acme CRM",
    "redirect_uris": ["https://crm.acme.com/oauth/emailit/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "scope": "full",
    "token_endpoint_auth_method": "client_secret_basic",
    "client_uri": "https://crm.acme.com",
    "logo_uri": "https://crm.acme.com/logo.png"
  }'
```

| Pole | Povinné | Popis |
| --- | --- | --- |
| `client_name` | Ano | Zobrazuje se na stránce se souhlasem. Nejvýše 200 znaků. |
| `redirect_uris` | Ano | 1 až 10 URI pro přesměrování. Viz [Pravidla pro URI pro přesměrování](#redirect-uri-rules). |
| `grant_types` | Ne | Musí obsahovat `authorization_code`; může obsahovat `refresh_token`. Výchozí hodnota jsou obě. |
| `response_types` | Ne | Jen `code`. |
| `scope` | Ne | Oprávnění oddělená mezerou. Výchozí hodnota je `sending full`. |
| `token_endpoint_auth_method` | Ne | `none` (výchozí) pro veřejné klienty, jako jsou desktopové, mobilní a prohlížečové aplikace; `client_secret_basic`, nebo `client_secret_post` pro aplikace na straně serveru. |
| `client_uri` | Ne | Domovská stránka vaší aplikace. |
| `logo_uri` | Ne | Logo zobrazené na stránce se souhlasem. |

Odpověď `201` zopakuje metadata a přidá `client_id`. Důvěrní klienti dostanou také `client_secret`, který se zobrazí jen jednou:

```json
{
  "client_id": "3e8a1f52-7c4b-4d29-8e6f-1a5b9c0d2e73",
  "client_id_issued_at": 1790847000,
  "client_name": "Acme CRM",
  "redirect_uris": ["https://crm.acme.com/oauth/emailit/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"],
  "scope": "full",
  "token_endpoint_auth_method": "client_secret_basic",
  "client_uri": "https://crm.acme.com",
  "logo_uri": "https://crm.acme.com/logo.png",
  "client_secret": "Ky7WI2z5HxoT6q1z19tuiIev_U1zX0_FKhIIfh0OBco",
  "client_secret_expires_at": 0
}
```

`client_secret_expires_at` je vždy `0`: tajné klíče klientů nevyprší. Každý klient, veřejný i důvěrný, musí používat PKCE.

### Dokument s metadaty klienta

Pokud vaše aplikace může hostovat statický soubor JSON, registraci můžete vynechat. Publikujte dokument na HTTPS URL a tuto URL použijte jako `client_id`:

```json title="https://crm.acme.com/oauth/client.json"
{
  "client_id": "https://crm.acme.com/oauth/client.json",
  "client_name": "Acme CRM",
  "client_uri": "https://crm.acme.com",
  "logo_uri": "https://crm.acme.com/logo.png",
  "redirect_uris": ["https://crm.acme.com/oauth/emailit/callback"],
  "grant_types": ["authorization_code", "refresh_token"],
  "token_endpoint_auth_method": "none",
  "scope": "full"
}
```

- `client_id` v dokumentu se musí přesně shodovat s URL dokumentu.
- `token_endpoint_auth_method` musí být `none`. Jde o veřejné klienty, kteří se spoléhají na PKCE.
- URI pro přesměrování s HTTPS musí mít stejný název hostitele jako dokument.
- Emailit dokument stáhne během autorizace s časovým limitem 5 sekund a bez následování přesměrování a na 5 minut si ho uloží do mezipaměti.
- Stránka se souhlasem místo `client_name` zobrazuje název hostitele dokumentu, například `crm.acme.com`.

Tuto metodu používají AI klienti: ChatGPT, Claude a Grok se identifikují vlastními dokumenty s metadaty klienta, takže se připojí bez předchozí registrace. U Groku Emailit přijímá také přesměrování na `console.x.ai`.

### Pravidla pro URI pro přesměrování

- URI `https://` jsou povolená.
- `http://` je povolené jen pro loopback: `127.0.0.1`, `localhost` a `[::1]`. U loopback URI se port při autorizaci může lišit, ale hostitel, cesta a dotaz se musí shodovat. `localhost` a `127.0.0.1` jsou různí hostitelé.
- Pro nativní aplikace jsou povolená vlastní schémata, například `cursor://`, `vscode://` nebo `com.acme.crm://`.
- URI se schématy `file`, `ftp`, `data`, `javascript`, `blob`, `about` a `vbscript` a jakékoli URI s `#fragment` se odmítnou.
- Kromě portů u loopbacku se `redirect_uri`, které pošlete, musí přesně shodovat s některým zaregistrovaným.

## Pošlete uživatele do Emailitu

Pro každou autorizaci vygenerujte ověřovací kód (code verifier) a výzvu PKCE a náhodnou hodnotu `state`:

```javascript

const codeVerifier = randomBytes(32).toString('base64url');
const codeChallenge = createHash('sha256').update(codeVerifier).digest('base64url');
const state = randomBytes(16).toString('base64url');
// Store codeVerifier and state in the user's session.
```

Pak přesměrujte prohlížeč uživatele na autorizační endpoint:

```text
https://api.emailit.com/oauth/authorize
  ?response_type=code
  &client_id=3e8a1f52-7c4b-4d29-8e6f-1a5b9c0d2e73
  &redirect_uri=https%3A%2F%2Fcrm.acme.com%2Foauth%2Femailit%2Fcallback
  &scope=full
  &state=Jq3k9V0n2xR7bLm1
  &code_challenge=zsrvXVr2pbLDHbccAx_NY9osQ6nwqTnDZlIeFWKQOsg
  &code_challenge_method=S256
  &resource=https%3A%2F%2Fapi.emailit.com
```

| Parametr | Povinné | Popis |
| --- | --- | --- |
| `response_type` | Ano | `code` |
| `client_id` | Ano | ID vašeho klienta, nebo URL vašeho dokumentu s metadaty. |
| `redirect_uri` | Ano | Jedno z vašich zaregistrovaných URI pro přesměrování. |
| `code_challenge` | Ano | SHA-256 ověřovacího kódu zakódovaný v Base64url. |
| `code_challenge_method` | Doporučené | `S256`. `plain` není podporované. |
| `scope` | Doporučené | `sending`, nebo `full`. Musí jít o oprávnění, které klient zaregistroval. |
| `state` | Doporučené | Náhodná hodnota, kterou zkontrolujete při zpětném volání. |
| `resource` | Ne | Zdroj, který chcete volat (RFC 8707): `https://api.emailit.com` pro REST API, nebo `https://api.emailit.com/mcp` pro MCP. Tokeny v každém případě fungují na obou. |

Tuto URL otevřete v prohlížeči uživatele. Nestahujte ji ze svého backendu.

## Co uživatel uvidí

1. **Přihlášení do Emailitu.** Uživatel zadá e-mail a heslo. Pokud pro dvoufázové ověření používá ověřovací aplikaci, zadá potom kód z ní nebo záložní kód.
2. **Výběr workspace.** Stránka zobrazí vaše logo, název klienta (nebo název hostitele vašeho dokumentu s metadaty) a oprávnění, o která žádáte. Uživatel vybere **All my workspaces**, což zahrnuje i workspace, které vytvoří nebo ke kterým se připojí později, nebo **Only these workspaces** se zaškrtnutými workspace, a zvolí, ve kterém vaše aplikace začne.
3. **Povolení přístupu.** Uživatel vybere **Allow access**, nebo **Deny**.

Jeden udělený přístup může zahrnovat více workspace. Uživatel může seznam později změnit ve webovém rozhraní v sekci **Account > Connected apps** a vaše aplikace změnu uvidí při dalším požadavku.

Po schválení Emailit přesměruje na vaše URI pro přesměrování:

```text
https://crm.acme.com/oauth/emailit/callback?code=XvRKyG5Pkplrd3xkRNaEayKkpkebEMdF&state=Jq3k9V0n2xR7bLm1&iss=https%3A%2F%2Fapi.emailit.com
```

Zkontrolujte, že `state` odpovídá uložené hodnotě a že `iss` je `https://api.emailit.com`. Kód platí 10 minut a lze ho použít jen jednou. Pokud uživatel vybere **Deny**, obsahuje přesměrování místo kódu `error=access_denied`.

## Vyměňte kód za tokeny

Pošlete POST na tokenový endpoint jako `application/x-www-form-urlencoded` (přijímá se i JSON). Pošlete stejné `redirect_uri` a původní ověřovací kód:

**Důvěrný klient**

```bash
curl https://api.emailit.com/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=authorization_code \
  -d code="$CODE" \
  -d redirect_uri=https://crm.acme.com/oauth/emailit/callback \
  -d code_verifier="$CODE_VERIFIER"
```

  S `client_secret_basic` pošlete ID klienta a tajný klíč v hlavičce `Authorization: Basic`. S `client_secret_post` místo toho pošlete `client_id` a `client_secret` jako pole formuláře. Tajný klíč neposílejte oběma způsoby.

**Veřejný klient**

```bash
curl https://api.emailit.com/oauth/token \
  -d grant_type=authorization_code \
  -d client_id="$CLIENT_ID" \
  -d code="$CODE" \
  -d redirect_uri=http://127.0.0.1:53682/callback \
  -d code_verifier="$CODE_VERIFIER"
```

  Veřejní klienti posílají `client_id` bez tajného klíče. PKCE prokazuje, že postup zahájil stejný klient.

```json
{
  "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Im9hdXRoLWhzMjU2In0…",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "XvRKyG5Pkplrd3xkRNaEayKkpkebEMdFn0h1VIuqixAOXybMtJfK8w",
  "scope": "full"
}
```

Přístupový token platí 15 minut (`expires_in` je v sekundách). Zacházejte s ním jako s neprůhledným řetězcem: neparsujte ho a nespoléhejte na jeho obsah.

## Volejte API

Přístupový token používejte jako bearer token pro REST API i MCP server, přesně jako API klíč:

```bash
curl https://api.emailit.com/v2/domains \
  -H "Authorization: Bearer $ACCESS_TOKEN"
```

Požadavky na REST API běží ve výchozím workspace uděleného přístupu: v tom, ve kterém se uživatel rozhodl začít, nebo na který ho později změnil. Nástroje MCP mohou argumentem `workspace` cílit i na jiný povolený workspace. Každý požadavek používá udělené oprávnění a roli uživatele ve workspace, takže požadavek mimo rozsah oprávnění nebo volání cesty vyhrazené roli Admin uživatelem s rolí Member vrací `403`. Pokud uživatel workspace opustí, přijde o něj i udělený přístup.

## Obnova tokenů

Než přístupový token vyprší, nebo když požadavek vrátí `401`, získejte nový:

```bash
curl https://api.emailit.com/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d grant_type=refresh_token \
  -d refresh_token="$REFRESH_TOKEN"
```

- **Výměna.** Každá obnova vrací nový `refresh_token` platný 60 dní. Uložte ho a starý zahoďte. Dokud obnovujete do 60 dní, připojení nevyprší.
- **Detekce opakovaného použití.** Pokud se starý obnovovací token použije znovu déle než minutu poté, co byl nahrazen, Emailit vrátí `invalid_grant` (`Refresh token reuse detected`) a odvolá celý udělený přístup. Uživatel pak musí aplikaci autorizovat znovu. Obnovy provádějte postupně, aby dva workery nikdy nepoužily stejný obnovovací token.
- **Užší oprávnění.** Parametrem `scope` můžete získat přístupový token s užším rozsahem oprávnění, než má udělený přístup. O širší požádat nemůžete.

## Odvolejte udělený přístup

Když uživatel Emailit od vaší aplikace odpojí, odvolejte udělený přístup jeho obnovovacím tokenem:

```bash
curl https://api.emailit.com/oauth/revoke \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -d token="$REFRESH_TOKEN"
```

Endpoint autentizuje vašeho klienta stejně jako tokenový endpoint a vždy vrací `200` s prázdným tělem. Odvolání obnovovacího tokenu odvolá celý udělený přístup: jeho přístupové tokeny přestanou fungovat při dalším požadavku. Přístupové tokeny nelze odvolat samostatně; `token_type_hint=access_token` vrací `invalid_request`.

Uživatelé mohou přístup vaší aplikace odvolat i ze své strany na stránce [Připojené aplikace](/cs/docs/account/connected-apps/) ve webovém rozhraní, nebo přes API udělených přístupů popsané níže.

## Spravujte udělené přístupy

API udělených přístupů vypisuje a mění udělené přístupy ze strany uživatele. Přijímá relaci uživatele ve webovém rozhraní, nebo API klíč s plným přístupem:

| Volající | `GET /oauth/grants` | `POST /oauth/grants/:id/revoke` | `PUT /oauth/grants/:id/workspaces` |
| --- | --- | --- | --- |
| Uživatel, který aplikaci připojil | Jeho udělené přístupy napříč všemi workspace | Odvolá celý udělený přístup | Změní workspace uděleného přístupu |
| API klíč s plným přístupem | Udělené přístupy, které zahrnují workspace klíče | Odebere workspace klíče z uděleného přístupu; když žádný workspace nezbude, udělený přístup se odvolá | Není povoleno (`403`) |

Každý udělený přístup v seznamu má tento tvar:

```json
{
  "id": "9b1f6c2e-4d3a-4f8e-9a7b-2c5d8e1f0a3b",
  "client_id": "https://chatgpt.com/oauth/client.json",
  "client": { "name": "ChatGPT", "uri": "https://chatgpt.com", "logo_uri": null },
  "default_workspace": { "id": "w3f9a1c2e", "name": "Acme" },
  "workspace_access": "selected",
  "workspaces": [{ "id": "w3f9a1c2e", "name": "Acme" }],
  "scopes": ["sending", "full"],
  "resource": "https://api.emailit.com/mcp",
  "created_at": "2026-10-01T09:30:12Z",
  "revoked_at": null,
  "revoked_reason": null
}
```

Pokud chcete změnit workspace uděleného přístupu, pošlete `access` (`all`, nebo `selected`), u `selected` také `workspace_ids` a volitelně `default_workspace_id`, které musí patřit mezi povolené workspace:

```bash
curl -X PUT https://api.emailit.com/oauth/grants/9b1f6c2e-4d3a-4f8e-9a7b-2c5d8e1f0a3b/workspaces \
  -H "Authorization: Bearer $DASHBOARD_SESSION" \
  -H "Content-Type: application/json" \
  -d '{ "access": "selected", "workspace_ids": ["w3f9a1c2e"], "default_workspace_id": "w3f9a1c2e" }'
```

Uživatel musí být členem každého workspace, který vybere. Odvolaný udělený přístup nelze upravit (`409`); aplikace se musí připojit znovu.

## Chyby

Endpointy OAuth vracejí chyby ve formátu OAuth, ne ve [formátu chyb REST API](/cs/docs/api-reference/errors/):

```json
{
  "error": "invalid_grant",
  "error_description": "Authorization code has expired"
}
```

| Chyba | Stav | Kdy |
| --- | --- | --- |
| `invalid_request` | 400 | Parametr chybí nebo je neplatný, klient není při autorizaci známý, `redirect_uri` není zaregistrované, `code_challenge_method` není `S256`, nebo byl tajný klíč klienta poslán v hlavičce i v těle. |
| `invalid_client` | 401 | Tokenový endpoint nebo endpoint pro odvolání nedokáže klienta autentizovat: neznámý klient, chybějící nebo špatný tajný klíč. |
| `invalid_grant` | 400 | Kód je neplatný, použitý nebo vypršel; `redirect_uri` nebo ověřovací kód PKCE nesouhlasí; nebo je obnovovací token neplatný, vypršel, byl odvolán nebo použit opakovaně. |
| `invalid_scope` | 400 | Oprávnění není podporované, klient ho nezaregistroval, nebo při obnově přesahuje udělený přístup. |
| `unsupported_response_type` | 400 | `response_type` není `code`. |
| `unsupported_grant_type` | 400 | `grant_type` není `authorization_code` ani `refresh_token`. |
| `access_denied` | Přesměrování | Uživatel vybral **Deny**. |
| `too_many_requests` | 429 | Více než 20 registrací za hodinu z jedné IP adresy. |
| `server_error` | 500 | Na straně Emailitu se něco pokazilo. Zkuste to znovu. |

Dokud nejsou `client_id` a `redirect_uri` ověřené, zobrazují se chyby autorizace v prohlížeči jako JSON a nikdy se nepřesměrovávají. Potom se chyby přesměrují na vaše zpětné volání (s `error`, `error_description`, `state` a `iss`) jen u loopback URI, URI s vlastním schématem a u klientů s dokumentem s metadaty; ostatní klienti dostanou chybovou stránku v JSON. Odmítnutí uživatelem přes **Deny** se přesměruje vždy.

## Kontrolní seznam zabezpečení

- `client_secret` a obnovovací tokeny uchovávejte na serveru a ukládejte je šifrované. Nikdy nedávejte tajný klíč klienta do mobilní, desktopové ani prohlížečové aplikace; místo toho použijte veřejného klienta s PKCE.
- Pro každou autorizaci vygenerujte nový `state` a ověřovací kód a při zpětném volání zkontrolujte `state` a `iss`.
- Registrujte přesná URI pro přesměrování. Jako zpětná volání nepoužívejte otevřené přesměrovače.
- Každý udělený přístup ukládejte s workspace, ke kterému patří, a na `invalid_grant` reagujte tak, že uživatele požádáte o nové připojení.
- Pokud jen odesíláte e-maily, žádejte o `sending`.

## Související

  - [Workspace a oprávnění](/cs/docs/mcp/workspaces-and-permissions/): Udělené přístupy, platnost tokenů a odvolání.
  - [Reference API](/cs/docs/api-reference/): Endpointy, které mohou vaše tokeny volat.
  - [API klíče](/cs/docs/developers/api-keys/): Pro vlastní skripty jsou klíče jednodušší.
  - [MCP server](/cs/docs/mcp/): Postup OAuth v praxi.

---
Zdroj: https://emailit.com/cs/docs/developers/oauth-apps/
