AgentSkillsCN

zitadel-identity

Zitadel 身份提供商的搭建、配置与 OIDC 集成。当您遇到以下场景时,可优先选用此技能: (1) 将 Zitadel 配置为 OIDC/OAuth2 身份提供商; (2) 通过 Caddy 反向代理配置 Zitadel; (3) 为各类服务创建 OAuth2/OIDC 应用程序; (4) 管理用户、组织与服务账号; (5) 将各应用程序与 Zitadel SSO 集成(如 Nextcloud、Windmill 等); (6) 排查身份验证、令牌或连接性问题; (7) 利用 Zitadel API 实现自动化操作。

SKILL.md
--- frontmatter
name: zitadel-identity
description: |
  Zitadel identity provider setup, configuration, and OIDC integration. Use when:
  (1) Setting up Zitadel as OIDC/OAuth2 identity provider
  (2) Configuring Zitadel with Caddy reverse proxy
  (3) Creating OAuth2/OIDC applications for services
  (4) Managing users, organizations, and service accounts
  (5) Integrating applications with Zitadel SSO (Nextcloud, Windmill, etc.)
  (6) Troubleshooting authentication, token, or connectivity issues
  (7) Using Zitadel APIs for automation

Zitadel Identity Provider

Zitadel is a modern identity management platform providing OIDC, OAuth2, and SAML authentication. This skill covers Docker deployment with Caddy reverse proxy.

Quick Reference

TaskCommand/Location
Console UIhttps://auth.example.com/ui/console
OIDC Discoveryhttps://auth.example.com/.well-known/openid-configuration
Health checkcurl https://auth.example.com/healthz
View logsdocker compose logs -f zitadel zitadel-login
Restartdocker compose restart zitadel zitadel-login

Architecture

code
Internet → Caddy (80/443) → Zitadel API (h2c://zitadel:8080)
                          → Login UI (http://zitadel-login:3000)

PostgreSQL ← zitadel-init (runs once)
           ← zitadel (API server)

Three containers:

  • zitadel-init - Database initialization (runs once, exits)
  • zitadel - API server (gRPC/REST on port 8080)
  • zitadel-login - Login UI (port 3000)

Essential Environment Variables

bash
# Required
ZITADEL_MASTERKEY=<32-char-random-string>
ZITADEL_DATABASE_POSTGRES_HOST=postgres
ZITADEL_DATABASE_POSTGRES_USER_PASSWORD=<password>
ZITADEL_EXTERNALDOMAIN=auth.example.com
ZITADEL_EXTERNALPORT=443
ZITADEL_EXTERNALSECURE=true
ZITADEL_TLS_ENABLED=false  # Caddy handles TLS

Generate masterkey: tr -dc A-Za-z0-9 </dev/urandom | head -c 32

Caddy Configuration

Critical: Use h2c:// for HTTP/2 cleartext (required for gRPC):

caddyfile
auth.example.com {
    handle /ui/v2/login/* {
        reverse_proxy http://zitadel-login:3000
    }
    handle {
        reverse_proxy h2c://zitadel:8080
    }
}

Deployment Steps

  1. Start PostgreSQL:

    bash
    docker compose up -d postgres
    
  2. Initialize database:

    bash
    docker compose run zitadel-init
    
  3. Start services:

    bash
    docker compose up -d zitadel zitadel-login caddy
    
  4. Verify health:

    bash
    curl https://auth.example.com/healthz
    
  5. Access console:

    code
    https://auth.example.com/ui/console
    

Creating OIDC Applications

  1. Console → Organization → Projects → Applications → + New
  2. Select application type (Web, Native, API)
  3. Configure redirect URIs
  4. Save and copy Client ID and Client Secret

Common redirect URIs:

  • Nextcloud: https://files.example.com/apps/user_oidc/code
  • Windmill: https://windmill.example.com/user/login_callback/zitadel

Service Users (API Access)

  1. Console → Users → Service Users → + New
  2. Create Personal Access Token (PAT)
  3. Assign roles (Org Owner, Project Owner)
  4. Use in API calls:
    bash
    curl -H "Authorization: Bearer <PAT>" \
      https://auth.example.com/management/v1/orgs/me
    

Reference Files

FileWhen to Read
configuration.mdEnvironment variables, config file options
caddy-integration.mdReverse proxy setup, h2c configuration
oidc-applications.mdCreating apps, Nextcloud integration
api-reference.mdREST/gRPC endpoints, authentication
troubleshooting.mdCommon issues and diagnostics

Official Documentation

Troubleshooting Quick Guide

IssueCheck
Container won't startdocker compose logs zitadel - check masterkey (32 chars)
Login page blankdocker compose ps zitadel-login - check Caddy routes
gRPC errorsEnsure h2c:// in Caddyfile, not http://
OIDC 404curl https://auth.example.com/healthz - check external domain
Token invalidCheck issuer URL matches, token not expired