Tmavý režim
Zitadel (/zitadel)
Endpointy pro integraci se Zitadel OIDC providerem — webhooky, OIDC login flow a správu organizací.
Webhooky
POST /zitadel/webhook — Zitadel Action webhook
Přijímá webhooky od Zitadelu při událostech uživatele. Autentizace pomocí X-Webhook-Secret headeru.
http
POST /api/zitadel/webhook
X-Webhook-Secret: <webhook-secret>
Content-Type: application/jsonPodporované události
| Událost | Akce |
|---|---|
user.created | Vytvoří uživatele v DB (pokud neexistuje) |
user.deactivated | Nastaví active = false |
user.reactivated | Nastaví active = true |
user.removed | Deaktivuje uživatele (active = false) — záznam se v DB zachovává pro audit trail |
Request body (od Zitadelu)
json
{
"eventType": "user.created",
"orgId": "org_abc123",
"user": {
"email": "novy.uzivatel@firma.cz",
"firstName": "Jan",
"lastName": "Novák"
}
}Konfigurace v Zitadelu
V Zitadelu nakonfigurujte Action:
- Přejděte do Actions → Flows → External Authentication
- Přidejte Action pro každou událost
- Nastavte Target URL:
https://api.atrea.eu/api/zitadel/webhook - Nastavte
X-Webhook-Secretna hodnotu zconfig.zitadel.webhookSecret
POST /zitadel/notifications/email — HTTP e-mail provider
Endpoint přijímá aktivační, ověřovací, resetovací a další systémové e-maily vygenerované ZITADELem. Podpis ZITADEL-Signature se ověřuje nad přesnými bajty request body (HMAC-SHA256, tolerance 5 minut).
Tok doručení:
args.orgIDse vyhledá vbrands.zitadel_org_id.- Použije se vzhled, adresa
emailFroma SMTP nalezeného brandu. Pokud má typauth_zitadelvyplněnéemailFromName, přepíše se pouze zobrazované jméno. - Podle
contextInfo.eventTypese vyhledá výchozí šablona v aplikacizitadel.notificationAppCode(výchozíauth). - Pokud panelová šablona existuje, má jazykovou variantu a všechny povinné proměnné, vyrenderuje se její obsah.
- Pokud šablona chybí nebo ji nelze bezpečně vyrenderovat, použije se hotový
templateDataobsah ze ZITADELu. - Úspěšný identický payload se při retry znovu neodešle.
Neznámá organizace skončí chybou; endpoint záměrně nepoužívá defaultní brand, aby nemohl odeslat e-mail přes SMTP jiné organizace. Auth e-maily také nepodléhají uživatelskému opt-out nastavení.
Auditní payload obsahuje templateSource (panel nebo zitadel) a při fallbacku také fallbackReason. Ověřovací kód ani cílová URL se do auditu neukládají.
Výchozí šablony bez ručního klikání
Idempotentní seed založí aplikaci auth, jediný systémový notification type auth_zitadel, mapovací sloupec brandu a české pojmenované šablony. Existující obsah šablon nepřepisuje, takže následné úpravy provedené v panelu zůstanou zachované.
Typ auth_zitadel má vždy nastaveno emailEnabled=true, pushEnabled=false, userCanDisable=false, selfServiceEnabled=false a system=true. První seed nastaví emailFromName='Auth', ale další spuštění seedu už jeho administrátorskou úpravu nepřepíše. Hodnota například může být Auth , ze které pro Atreu vznikne Auth Atrea <report@amotion.cloud>; adresa ani SMTP přihlašovací údaje se nemění.
bash
docker exec -i atrea-postgres \
psql -v ON_ERROR_STOP=1 -U app -d atrea-user-db \
< sql/migrations/2026-07-23_auth_notification_templates.sqlMapování organizací lze také nastavit přímo SQL bez panelu:
sql
UPDATE brands SET zitadel_org_id = '363312544930136068' WHERE slug = 'atrea';
UPDATE brands SET zitadel_org_id = '<vallox-org-id>' WHERE slug = 'vallox';
UPDATE brands SET zitadel_org_id = '<airflow-org-id>' WHERE slug = 'airflow';Klíč šablony pod typem auth_zitadel | ZITADEL událost |
|---|---|
account_activation | user.human.initialization.code.added |
email_verification | user.human.email.code.added |
password_reset | user.human.password.code.added |
user_invitation | user.human.invite.code.added |
passwordless_registration | user.human.passwordless.initialization.code.requested |
otp_email | user.human.mfa.otp.email.code.added, session.otp.email.challenged |
password_changed | user.human.password.changed |
domain_claimed | user.domain.claimed |
Při registraci login ještě před vytvořením uživatele uloží přes interní endpoint krátkodobé locale pro dvojici e-mail + ZITADEL organizace. Registrační e-maily ho použijí i tehdy, když ještě neexistuje profil, a zároveň jej uloží jako user_profiles.locale. Další auth e-maily používají toto profilové locale; výchozí jazyk je en.
http
PUT /api/internal/auth/registration-locale
x-internal-api-key: <INTERNAL_API_KEY>
Content-Type: application/json
{
"email": "user@example.com",
"orgId": "363312544930136068",
"locale": "cs"
}Locale se normalizuje (cs-CZ → cs) a musí být v platformním registru i mezi auth.supportedLanguages, jinak se uloží en. Šablona se vybírá v pořadí: přesná varianta → fallback řetězec jazykového registru → libovolná poslední dostupná varianta. Výchozí en se tedy použije přímo, když login žádné platné locale nepředá; není vložen jako skrytý mezikrok mimo nastavený fallback řetězec.
http
POST /api/zitadel/notifications/email
ZITADEL-Signature: t=1784754951,v1=<hmac>
Content-Type: application/jsonPro každý brand nastavte ZITADEL organization ID:
http
PUT /api/admin/brands/1
Authorization: Bearer <superadmin-token>
Content-Type: application/json
{ "zitadelOrgId": "363312544930136068" }HTTP provider se již nevytváří pomocným scriptem ani ručně v ZITADELu. API jeho životní cyklus spravuje samo:
http
GET /api/zitadel/admin/notification-provider
Authorization: Bearer <superadmin-token>Vrátí stav bez signing key:
json
{
"configured": false,
"providerId": null,
"endpoint": "https://api.user.kagb.cloud/api/zitadel/notifications/email",
"hasSigningKey": false,
"serviceAccountConfigured": true
}Jednorázové vytvoření/aktualizace a aktivace:
http
POST /api/zitadel/admin/notification-provider/setup
Authorization: Bearer <superadmin-token>
Content-Type: application/json
{}API zavolá ZITADEL Admin API pomocí ZITADEL_SERVICE_ACCOUNT_TOKEN, signing key zašifruje pomocí BRAND_SMTP_KEY, uloží do tabulky zitadel_notification_provider_settings a až poté provider aktivuje. Klíč se nikdy nevrací panelu a není potřeba ho nastavovat v ENV.
Existující provider lze znovu aktivovat:
http
POST /api/zitadel/admin/notification-provider/activate
Authorization: Bearer <superadmin-token>Health & Discovery
GET /zitadel/health
Ověří dostupnost Zitadel instance.
http
GET /api/zitadel/healthResponse
json
{
"success": true,
"data": {
"zitadelUrl": "https://admin.kagb.cloud",
"status": "ok"
}
}GET /zitadel/discovery
Vrátí OIDC discovery dokument ze Zitadelu.
http
GET /api/zitadel/discoveryOIDC Login Flow (PKCE) — DEV
Dev-only endpointy
Tyto endpointy slouží pro lokální vývoj a testování. Callback vrací tokeny jako JSON, neprovádí redirect na frontend. V produkci provádí OIDC flow přímo frontend aplikace proti Zitadelu.
GET /zitadel/login — start login
Přesměruje uživatele na Zitadel login stránku.
http
GET /api/zitadel/login?client_id=portal-app| Parametr | Povinné | Popis |
|---|---|---|
client_id | ✓ | OIDC client ID aplikace v Zitadelu |
Odpověď: 302 Redirect na Zitadel login stránku s PKCE parametry.
GET /zitadel/callback — OIDC callback (dev)
Zpracuje callback od Zitadelu, vymění auth code za tokeny a vrátí je jako JSON.
http
GET /api/zitadel/callback?code=<authCode>&state=<state>Response
json
{
"success": true,
"data": {
"token_type": "Bearer",
"access_token": "...",
"id_token": "...",
"id_token_claims": { "...": "..." },
"access_token_claims": { "...": "..." },
"userapi_verification": { "...": "..." }
}
}Login flow — diagram
Uživatel klikne "Přihlásit"
│
▼
GET /api/zitadel/login?client_id=portal-app
│
├─ Generuje PKCE (code_verifier + code_challenge)
├─ Uloží state + verifier do session
└─ Redirect → Zitadel login stránka
│
▼
Uživatel se přihlásí
│
▼
GET /api/zitadel/callback?code=xyz&state=abc
│
├─ Ověří state (CSRF ochrana)
├─ Vymění code za access_token (PKCE verifier)
└─ Vrátí tokeny v JSON odpovědiSpráva organizací (SuperAdmin)
Viz Admin endpointy pro detaily.
Stručný přehled:
http
# Seznam organizací
GET /api/zitadel/admin/orgs
# Vytvoření organizace
POST /api/zitadel/admin/orgs
{ "name": "Firma s.r.o.", "domain": "firma.cz" }
# Nastavení brandingu
PUT /api/zitadel/admin/orgs/:orgId/branding
{ "primaryColor": "#E91E63", "logoUrl": "..." }
# Kompletní setup (projekt + OIDC app)
POST /api/zitadel/admin/orgs/:orgId/setup
{
"projectName": "Firma Portal",
"appName": "Portal",
"redirectUris": ["https://portal.firma.cz/callback"],
"userApiAppCode": "firma-portal"
}Konfigurace
V config/default.yaml:
yaml
zitadel:
apiUrl: http://zitadel:8080 # Interní URL (Docker)
publicUrl: http://localhost:8080 # Veřejná URL (pro redirect)
serviceAccountToken: "" # Service account token pro API volání
webhookSecret: "change-me" # Secret pro ověřování webhooků
notificationEndpoint: "http://localhost:3001/api/zitadel/notifications/email"
notificationAppCode: "auth" # Aplikace pro audit auth e-mailů
orgToApp: {} # Mapování orgId → appCodeorgToApp mapování
Mapuje Zitadel organizaci na aplikaci v User API:
yaml
zitadel:
orgToApp:
"org_abc123": "crm"
"org_def456": "vallox-panel"Toto mapování se používá při webhook událostech a Zitadel setup flowu.