Skip to content

JWT Provideři

Konfigurace

JWT provideři se konfigurují v config/default.yaml (nebo production.yaml) pod klíčem token.jwt:

yaml
token:
  keyRefreshIntervalMinutes: 60   # Interval refreshe JWKS klíčů
  jwt:
    - provider: zitadel
      baseUrl: http://zitadel:8080
      jwk: /oauth/v2/keys
      issuer: http://localhost:8080
      hostOverride: localhost       # Volitelné: přepíše host při fetch klíčů

    - provider: amotion
      baseUrl: https://auth-dev.am-space.cz
      jwk: /oauth/keys

    - provider: amotion-dev
      baseUrl: https://atrea-auth.uxf.dev
      jwk: /oauth/keys

Google / Microsoft přihlášení

Google a Microsoft nejsou samostatní JWT provideři. Federovaný login přes tyto účty se konfiguruje uvnitř Zitadelu jako externí Identity Provider (IdP). Token, který nakonec dorazí na API, vždy podepisuje Zitadel.

Zitadel (primární provider)

Zitadel je self-hosted OIDC provider, který zajišťuje primární autentizaci pro všechny Atrea aplikace.

Speciální claims

Zitadel přidává do JWT tokenu navíc dynamické claims, kde je část identifikátoru zakódovaná přímo v názvu klíče:

Vzor claimuPopis
urn:zitadel:iam:org:id:{orgId}ID organizace uživatele — z názvu klíče se extrahuje {orgId}
urn:zitadel:iam:org:project:{projectId}:rolesRole uživatele v daném Zitadel projektu

Extrakce se provádí regexem v JWTService — orgId i projectId nejsou hodnoty, ale součást názvu claimu.

Organizace

Při přihlášení přes Zitadel je z tokenu extrahováno orgId. To umožňuje mapování Zitadel organizací na aplikace v Atrea User API (viz config.zitadel.orgToApp).

Login flow (PKCE)

Dev-only endpoint

Endpointy /api/zitadel/login a /api/zitadel/callback jsou určené pro lokální vývoj a testování. Callback vrací tokeny jako JSON odpověď (nikoliv redirect na frontend). V produkci provádí OIDC flow přímo frontend aplikace přes Zitadel.

1. GET /api/zitadel/login?client_id=<clientId>
   → Redirect na Zitadel login stránku (s PKCE)

2. Uživatel se přihlásí v Zitadel

3. GET /api/zitadel/callback?code=<authCode>&state=<state>
   → Výměna auth code za tokeny
   → JSON response: { access_token, id_token, id_token_claims, ... }

Webhoky

Zitadel posílá webhooky při událostech uživatele:

UdálostAkce v API
user.createdVytvoří uživatele v DB (pokud neexistuje)
user.deactivatedDeaktivuje uživatele (active = false)
user.reactivatedAktivuje uživatele (active = true)
user.removedDeaktivuje uživatele (active = false) — záznam se zachovává pro audit trail

Webhook endpoint: POST /api/zitadel/webhook
Autentizace: X-Webhook-Secret header

Tělo webhooku

json
{
  "eventType": "user.created",
  "orgId": "org_abc123",
  "user": {
    "email": "novy.uzivatel@firma.cz",
    "firstName": "Jan",
    "lastName": "Novák"
  }
}

Amotion

Alternativní OAuth2/OIDC server. JWKS endpoint je /oauth/keys. Email se extrahuje z claimu email nebo preferred_username.

V default.yaml jsou dvě varianty: amotion (produkční auth-dev.am-space.cz) a amotion-dev (atrea-auth.uxf.dev) — obě validují tokeny stejným způsobem, liší se pouze JWKS URL.

Google / Microsoft (federovaní přes Zitadel)

Login přes Google nebo Microsoft není konfigurován v Atrea User API. Tito poskytovatelé jsou nastaveni jako externí Identity Provideři uvnitř Zitadelu (Console → Default Settings → Identity Providers). Při přihlášení:

  1. Uživatel klikne v Zitadel login UI na "Sign in with Google/Microsoft"
  2. Zitadel provede OAuth flow proti Google/Microsoftu
  3. Zitadel vytvoří/aktualizuje lokálního uživatele a vydá vlastní JWT
  4. API přijme Zitadel JWT a verifikuje ho proti Zitadel JWKS

Z pohledu API tedy existuje vždy jediný provider — Zitadel. upn claim zůstává v emailové extrakci pro případy, kdy Zitadel propaguje původní Microsoft UPN do tokenu.

Jak probíhá verifikace

typescript
// JWTService — zjednodušeně
async verifyToken(token: string): Promise<DecodedToken> {
  for (const provider of this.providers) {
    try {
      const decoded = jwt.verify(token, provider.keys, {
        algorithms: ['RS256', 'RS384', 'RS512'],
        issuer: provider.issuer,
      });
      return { ...decoded, provider: provider.name };
    } catch {
      // Zkusí další provider
    }
  }
  throw new ApiException(401, 'Invalid token');
}

Tokenem projdou všichni provideři v pořadí konfigurace. První úspěšná verifikace vyhrává.

Přidání nového providera

  1. Přidejte konfiguraci do config/default.yaml:
yaml
token:
  jwt:
    - provider: muj-provider
      baseUrl: https://auth.moje-firma.cz
      jwk: /oauth/keys
      issuer: https://auth.moje-firma.cz
  1. Ujistěte se, že provider vydává JWT s email claimem nebo jiným, ze kterého lze email extrahovat.

  2. Restartujte API — klíče se načtou při startu.

Troubleshooting

Token is invalid

  • Ověřte, že issuer v konfiguraci odpovídá iss claimu v tokenu
  • Ověřte, že JWKS endpoint je dostupný ze serveru
  • Zkontrolujte expiraci tokenu (exp claim)

JWKS fetch failed

  • Zkontrolujte dostupnost baseUrl + jwk endpointu
  • Pro Zitadel v Dockeru: ujistěte se, že zitadel hostname je resolvovatelný
  • Použijte hostOverride pokud se liší interní a externí hostname

Email extraction failed

  • Zkontrolujte, které claims váš provider vydává
  • Přidejte logiku extrakce do JWTService.extractEmail() pokud používáte nestandartní claim

Atrea User API — interní dokumentace