Skip to content

Commands & Recipes

Runnable commands, Helm snippets, API calls, and SDK integration patterns for Zitadel.

Docker Commands

Run Zitadel Locally

# Generate a master key (32 bytes hex)
ZITADEL_MASTERKEY=$(openssl rand -hex 16)

# Run with PostgreSQL
docker compose up -d

Run Without Docker Compose

# Start PostgreSQL
docker run -d --name zitadel-db \
  -e POSTGRES_USER=zitadel \
  -e POSTGRES_PASSWORD=zitadel \
  -e POSTGRES_DB=zitadel \
  -p 5432:5432 \
  postgres:17-alpine

# Start Zitadel
docker run -d --name zitadel \
  --link zitadel-db:db \
  -p 8080:8080 \
  -e ZITADEL_MASTERKEY="$(openssl rand -hex 16)" \
  ghcr.io/zitadel/zitadel:v4.13.0 \
  start-from-init \
  --config /example-zitadel-config.yaml \
  --config /example-zitadel-secrets.yaml \
  --steps /example-zitadel-init-steps.yaml \
  --masterkey "${ZITADEL_MASTERKEY}" \
  --tlsMode disabled

Helm Commands

Install

helm repo add zitadel https://charts.zitadel.com
helm repo update zitadel

helm install zitadel zitadel/zitadel \
  --namespace zitadel --create-namespace \
  --set zitadel.masterkey="$(openssl rand -hex 16)" \
  --set zitadel.configmapConfig.ExternalDomain=auth.example.com \
  --set zitadel.configmapConfig.ExternalPort=443 \
  --set zitadel.configmapConfig.TLS.Enabled=false

Upgrade

helm repo update zitadel

helm upgrade zitadel zitadel/zitadel \
  --namespace zitadel \
  --values values.yaml

Uninstall

helm uninstall zitadel --namespace zitadel
kubectl delete namespace zitadel

Kubernetes Operations

Port Forward for Debugging

# Forward Zitadel API
kubectl port-forward -n zitadel svc/zitadel 8080:8080

# Forward PostgreSQL
kubectl port-forward -n zitadel svc/zitadel-postgresql 5432:5432

Check Health

# Check pod status
kubectl get pods -n zitadel

# Check Zitadel CR status (if using operator)
kubectl get coroot -n zitadel

# REST healthz
kubectl exec -n zitadel deploy/zitadel -- \
  curl -sf http://localhost:8080/admin/v1/healthz

# View setup job logs
kubectl logs -n zitadel job/zitadel-setup

Scale Replicas

# Manual scaling
kubectl scale deployment zitadel --replicas=3 -n zitadel

# HPA
kubectl autoscale deployment zitadel \
  --min=3 --max=10 \
  --cpu-percent=70 \
  -n zitadel

API Calls

OIDC Discovery

curl -s https://auth.example.com/.well-known/openid-configuration | jq .

Create a User (V2 API)

curl -X POST https://auth.example.com/v2/users/human/_import \
  -H "Authorization: Bearer ${PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "user_name": "jdoe",
    "profile": {
      "first_name": "John",
      "last_name": "Doe",
      "display_name": "John Doe",
      "email": "[email protected]"
    },
    "email": {
      "email": "[email protected]",
      "is_email_verified": true
    },
    "phone": {
      "phone": "+1234567890"
    }
  }'

Create a Project

curl -X POST https://auth.example.com/v2/projects \
  -H "Authorization: Bearer ${PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "billing-api",
    "project_role_assertion": true,
    "project_role_check": true,
    "has_project_check": true,
    "private_labeling_setting": "PRIVATE_LABELING_SETTING_UNSPECIFIED"
  }'

Create an OIDC Application

curl -X POST https://auth.example.com/v2/projects/${PROJECT_ID}/apps/oidc \
  -H "Authorization: Bearer ${PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "billing-web",
    "redirect_uris": ["https://billing.example.com/auth/callback"],
    "post_logout_redirect_uris": ["https://billing.example.com/"],
    "response_types": ["OIDC_RESPONSE_TYPE_CODE"],
    "grant_types": ["OIDC_GRANT_TYPE_AUTHORIZATION_CODE", "OIDC_GRANT_TYPE_REFRESH_TOKEN"],
    "app_type": "OIDC_APP_TYPE_WEB",
    "auth_method_type": "OIDC_AUTH_METHOD_TYPE_PKCE",
    "version": "OIDC_VERSION_1_0"
  }'

Create a Service Account (Machine User)

curl -X POST https://auth.example.com/v2/users/machine \
  -H "Authorization: Bearer ${PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "user_name": "billing-api-sa",
    "name": "Billing API Service Account",
    "description": "Service account for billing API M2M auth",
    "access_token_type": "ACCESS_TOKEN_TYPE_JWT"
  }'

Generate a Personal Access Token

curl -X POST https://auth.example.com/v2/users/${USER_ID}/pats \
  -H "Authorization: Bearer ${PAT}" \
  -H "Content-Type: application/json" \
  -d '{
    "expiration_date": "2027-01-01T00:00:00Z",
    "scopes": ["openid", "profile", "email", "urn:zitadel:iam:org:project:id:billing-api:aud"]
  }'

Token Introspection

curl -X POST https://auth.example.com/oauth/v2/introspect \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=${CLIENT_ID}&client_secret=${CLIENT_SECRET}&token=${ACCESS_TOKEN}"

SDK Integration Patterns

Go — JWT Profile Authentication

package main

import (
    "context"
    "fmt"
    "log"

    "github.com/zitadel/zitadel-go/v3/pkg/client"
    "github.com/zitadel/zitadel-go/v3/pkg/client/management"
)

func main() {
    // Initialize management client with JWT Profile auth
    mgmt, err := management.NewClient(
        context.Background(),
        "https://auth.example.com",
        "audience",
        client.WithJWTProfileAuth(
            "service-account-id",
            "key.json", // path to private key file
        ),
    )
    if err != nil {
        log.Fatal(err)
    }

    // Get my organization
    resp, err := mgmt.GetMyOrg(context.Background(), &management.GetMyOrgRequest{})
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("Org: %s\n", resp.GetOrg().GetName())
}

Python — Client Credentials

from zitadel_client import ZitadelClient

client = ZitadelClient(
    domain="https://auth.example.com",
    client_id="service-account-id",
    client_secret="service-account-secret",
)

# Add a human user
response = client.users.add_human_user(
    user_name="jdoe",
    profile={
        "first_name": "John",
        "last_name": "Doe",
        "display_name": "John Doe",
    },
    email={
        "email": "[email protected]",
        "is_email_verified": True,
    },
)
print(f"Created user: {response.user_id}")

React — OIDC Login

import { AuthProvider, useAuth } from "@zitadel/react";

function App() {
  return (
    <AuthProvider
      authority="https://auth.example.com"
      client_id="billing-web"
      redirect_uri="https://billing.example.com/auth/callback"
      post_logout_redirect_uri="https://billing.example.com/"
    >
      <Dashboard />
    </AuthProvider>
  );
}

function Dashboard() {
  const { user, signinRedirect, signoutRedirect, isAuthenticated } = useAuth();

  if (!isAuthenticated) {
    return <button onClick={signinRedirect}>Login</button>;
  }

  return (
    <div>
      <p>Welcome, {user?.profile.name}</p>
      <button onClick={signoutRedirect}>Logout</button>
    </div>
  );
}

Terraform

Provider Configuration

terraform {
  required_providers {
    zitadel = {
      source  = "zitadel/zitadel"
      version = "~> 2.0"
    }
  }
}

provider "zitadel" {
  domain           = "auth.example.com"
  port             = "443"
  token            = var.zitadel_pat
  insecure         = false
}

Create Organization, Project, and Application

resource "zitadel_org" "billing" {
  name = "Billing Team"
}

resource "zitadel_project" "billing_api" {
  name                      = "billing-api"
  org_id                    = zitadel_org.billing.id
  project_role_assertion    = true
  project_role_check        = true
}

resource "zitadel_project_role" "admin" {
  project_id   = zitadel_project.billing_api.id
  org_id       = zitadel_org.billing.id
  role_key     = "admin"
  display_name = "Administrator"
  group        = "billing"
}

resource "zitadel_project_role" "viewer" {
  project_id   = zitadel_project.billing_api.id
  org_id       = zitadel_org.billing.id
  role_key     = "viewer"
  display_name = "Viewer"
  group        = "billing"
}

resource "zitadel_application_oidc" "web" {
  project_id    = zitadel_project.billing_api.id
  org_id        = zitadel_org.billing.id
  name          = "billing-web"

  redirect_uris = ["https://billing.example.com/auth/callback"]
  post_logout_redirect_uris = ["https://billing.example.com/"]

  response_types = ["OIDC_RESPONSE_TYPE_CODE"]
  grant_types    = ["OIDC_GRANT_TYPE_AUTHORIZATION_CODE", "OIDC_GRANT_TYPE_REFRESH_TOKEN"]
  app_type       = "OIDC_APP_TYPE_WEB"
  auth_method_type = "OIDC_AUTH_METHOD_TYPE_PKCE"
}

Sources