Skip to content

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/json

Podporované události

UdálostAkce
user.createdVytvoří uživatele v DB (pokud neexistuje)
user.deactivatedNastaví active = false
user.reactivatedNastaví active = true
user.removedDeaktivuje 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:

  1. Přejděte do Actions → Flows → External Authentication
  2. Přidejte Action pro každou událost
  3. Nastavte Target URL: https://api.atrea.eu/api/zitadel/webhook
  4. Nastavte X-Webhook-Secret na hodnotu z config.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í:

  1. args.orgID se vyhledá v brands.zitadel_org_id.
  2. Použije se vzhled, adresa emailFrom a SMTP nalezeného brandu. Pokud má typ auth_zitadel vyplněné emailFromName, přepíše se pouze zobrazované jméno.
  3. Podle contextInfo.eventType se vyhledá výchozí šablona v aplikaci zitadel.notificationAppCode (výchozí auth).
  4. Pokud panelová šablona existuje, má jazykovou variantu a všechny povinné proměnné, vyrenderuje se její obsah.
  5. Pokud šablona chybí nebo ji nelze bezpečně vyrenderovat, použije se hotový templateData obsah ze ZITADELu.
  6. Ú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.sql

Mapová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_zitadelZITADEL událost
account_activationuser.human.initialization.code.added
email_verificationuser.human.email.code.added
password_resetuser.human.password.code.added
user_invitationuser.human.invite.code.added
passwordless_registrationuser.human.passwordless.initialization.code.requested
otp_emailuser.human.mfa.otp.email.code.added, session.otp.email.challenged
password_changeduser.human.password.changed
domain_claimeduser.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-CZcs) 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/json

Pro 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/health

Response

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/discovery

OIDC 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
ParametrPovinnéPopis
client_idOIDC 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ědi

Sprá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 → appCode

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

Atrea User API — interní dokumentace