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¶
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¶
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"
}