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: /.well-known/jwks.json
      issuer: https://auth-dev.am-space.cz

    - provider: microsoft
      baseUrl: https://login.microsoftonline.com
      jwk: /common/discovery/v2.0/keys
      issuer: https://login.microsoftonline.com/{tenantId}/v2.0

    - provider: google
      baseUrl: https://accounts.google.com
      jwk: /oauth/v2/certs
      issuer: https://accounts.google.com

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:

ClaimPopis
urn:zitadel:iam:user:resourceowner:idID organizace uživatele
urn:zitadel:iam:org:project:rolesRole uživatele v projektech

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)

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

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

3. GET /api/zitadel/callback?code=<authCode>&state=<state>
   → Výměna auth code za access token
   → Redirect s tokenem

4. Frontend uloží token a používá ho v Bearer headeru

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.removedSmaže uživatele z DB

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

Amotion

Alternativní OAuth2/OIDC server. Konfigurace je standardní JWKS endpoint.

Email extrahován z claimu email nebo preferred_username.

Microsoft (Azure AD)

Podporuje Microsoft pracovní/školní účty (Azure Active Directory).

Email je extrahován z:

  1. email claim
  2. preferred_username claim
  3. upn claim (User Principal Name)

Tenant

Použijte /common/ pro multi-tenant nebo specifický tenant ID pro single-tenant nasazení.

Google

Podporuje Google účty (Gmail, Workspace).

Email extrahován ze standardního email claimu.

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: /.well-known/jwks.json
      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