Zitadel TUI
A Rust terminal UI and headless CLI for managing Zitadel applications, users, identity providers, and runtime configuration.
Status
The migration is complete: the project is now Rust-only.
Current status:
- Rust crate, TUI, CLI, and release automation are the only supported runtime path
- runtime config is TOML-only in the XDG config directory
- PAT, service-account, and OAuth Device Flow (OIDC) authentication are supported
- app and user templates remain YAML-based
Features
-
Applications
- list OIDC applications
- create applications from flags or templates
- delete applications
- regenerate confidential client secrets
- quick setup from templates YAML
-
Users
- list users
- create human users
- create imported local admin users
- grant
IAM_OWNER - quick setup from templates YAML
-
Identity Providers
- list IDPs
- configure Google manually
-
Configuration and Auth
- TOML config in XDG config space
- auth precedence
CLI > env > config > session token - PAT precedence over service-account credentials within each source
- PAT, service-account file, and OAuth Device Flow (
auth login) support - session tokens cached in
~/.config/zitadel-tui/tokens.jsonwith auto-refresh
Installation
Build locally
Run the binary:
Install from crates.io
Usage
Interactive TUI
Headless mode
Supplying a subcommand runs the existing one-shot command path. The deprecated
--once flag is still accepted for compatibility, but is no longer required.
--once on its own is invalid because there is no subcommand to run.
Use --json for machine-readable output.
Global options
--host <HOST>
: Override the Zitadel base URL. Also available as ZITADEL_URL.
Example: zitadel-tui --host https://zitadel.example.com
--project-id <PROJECT_ID>
: Use a specific project for app operations. Also available as
ZITADEL_PROJECT_ID. In headless mode this is optional because the CLI can
resolve the default project when omitted.
Example: zitadel-tui --project-id 123456789 apps list
--token <TOKEN>
: Authenticate with a PAT. Also available as ZITADEL_TOKEN.
Example: zitadel-tui --token "$ZITADEL_PAT" auth status
--service-account-file <SERVICE_ACCOUNT_FILE>
: Authenticate with a Zitadel service-account JSON key file. Also available as
ZITADEL_SERVICE_ACCOUNT_FILE.
Example: zitadel-tui --service-account-file ./service-account.json auth status
--config <CONFIG>
: Read runtime configuration from a non-default TOML file instead of the
canonical XDG path.
Example: zitadel-tui --config ./config.toml
--json
: Print JSON envelopes for headless commands.
Example: zitadel-tui --json config show
--once
: Deprecated compatibility flag for one-shot subcommand execution. Subcommands
now run one-shot without it.
Example: zitadel-tui --once users list
Command reference
apps
apps list
: List OIDC applications for the active project.
Example: zitadel-tui apps list
apps create
: Create an OIDC application. Use either --template <TEMPLATE> or the manual
combination of --name <NAME> plus at least one --redirect-uris <URI>.
Example: zitadel-tui apps create --template grafana
Example: zitadel-tui apps create --name grafana --redirect-uris https://grafana.example.com/login/generic_oauth,https://grafana.example.com/oauth2/callback --public
--name <NAME>
: App name when creating manually. Ignored when --template is used.
--redirect-uris <REDIRECT_URIS>
: Comma-delimited redirect URI list for manual app creation.
--public
: Create the app as a public client for manual app creation.
--template <TEMPLATE>
: Create the app from a named entry in apps_config_file.
apps create-native
: Create a native OIDC application. With --device-code, the CLI configures JWT access tokens and saves the returned client ID as device_client_id so the app can be used for auth login.
Example: zitadel-tui apps create-native --name zitadel-tui --device-code
--name <NAME>
: Display name for the native application.
--device-code
: Enable the Device Code grant for CLI login sessions. This also switches the generated client to JWT access tokens.
apps delete
: Delete an application by Zitadel app ID.
Example: zitadel-tui apps delete --app-id 123456789012345678
--app-id <APP_ID>
: Target application ID for apps delete and apps regenerate-secret.
apps regenerate-secret
: Regenerate a confidential client's secret.
Example: zitadel-tui apps regenerate-secret --app-id 123456789012345678
--client-id <CLIENT_ID>
: Optional client ID annotation included in the command result.
apps quick-setup
: Create apps from all configured templates, or only the comma-delimited names
passed with --names.
Example: zitadel-tui apps quick-setup
Example: zitadel-tui apps quick-setup --names grafana,mealie
--names <NAMES>
: Comma-delimited subset of app template names to create.
users
users list
: List users.
Example: zitadel-tui users list
users create
: Create a human user.
Example: zitadel-tui users create --email alice@example.com --first-name Alice --last-name Admin --username alice
--email <EMAIL>
: Email address for users create and users create-admin.
--first-name <FIRST_NAME>
: First name for users create and users create-admin.
--last-name <LAST_NAME>
: Last name for users create and users create-admin.
--username <USERNAME>
: Optional login name for users create; required for users create-admin.
users create-admin
: Import a local admin user and grant admin access. In headless mode
--password <PASSWORD> is required.
Example: zitadel-tui users create-admin --username admin --first-name Admin --last-name User --email admin@example.com --password 'change-me-now'
--password <PASSWORD>
: Password for users create-admin in headless mode.
users grant-iam-owner
: Grant the IAM_OWNER role to an existing user.
Example: zitadel-tui users grant-iam-owner --user-id 123456789012345678
--user-id <USER_ID>
: Target user ID for users grant-iam-owner.
users quick-setup
: Create every user from the YAML templates file. This command has no
command-specific flags.
Example: zitadel-tui users quick-setup
idps
idps list
: List configured identity providers.
Example: zitadel-tui idps list
idps configure-google
: Create a Google identity provider. In headless mode --client-secret is
required.
Example: zitadel-tui idps configure-google --client-id google-client-id --client-secret google-client-secret
--client-id <CLIENT_ID>
: Google OAuth client ID.
--client-secret <CLIENT_SECRET>
: Google OAuth client secret. Required in headless mode.
--name <NAME>
: Display name for the provider. Defaults to Google.
auth
auth login
: Authenticate via the OAuth 2.0 Device Authorization Grant. Prints a URL and
short code, waits for browser approval, then saves the access and refresh tokens
to ~/.config/zitadel-tui/tokens.json. Requires a Zitadel native app with the
Device Code grant enabled and JWT access tokens configured for API access.
The apps create-native --device-code path is intended for CLI login sessions
and saves the returned client ID for future logins.
Example: zitadel-tui --host https://zitadel.example.com auth login
--client-id <CLIENT_ID>
: The Zitadel native app client ID. If omitted and not set in config, the
command prompts interactively and saves the value to config for future use.
Also available as device_client_id in config.
auth logout
: Remove the stored session token. Subsequent commands will require explicit
credentials or a new auth login.
Example: zitadel-tui auth logout
auth status
: Resolve credentials, authenticate, and report the active auth source plus the
current user identity. Works with any credential source including a cached session token.
Example: zitadel-tui --json auth status
config
config show
: Print the active runtime configuration with secrets redacted. This command
has no command-specific flags.
Example: zitadel-tui config show
Configuration
Canonical config lives at:
~/.config/zitadel-tui/config.toml
Example:
= "https://zitadel.example.com"
= "123456789"
= "/path/to/apps.yml"
= "zitadel-pat"
= "/path/to/service-account.json"
= "your-native-app-client-id"
Templates File
The apps/users templates file remains YAML for compatibility during the migration.
apps:
grafana:
redirect_uris:
- https://grafana.example.com/oauth2/callback
- https://grafana.example.com/login/generic_oauth
public: false
mealie:
redirect_uris:
- https://mealie.example.com/login
- https://mealie.example.com/api/auth/oauth/callback
public: true
users:
- email: admin@example.com
first_name: Admin
last_name: User
admin: true
- email: user@example.com
first_name: Regular
last_name: User
admin: false
Authentication
Authentication is resolved in this order:
--token/ZITADEL_TOKEN/patin config (PAT)--service-account-file/ZITADEL_SERVICE_ACCOUNT_FILE/service_account_filein config- Cached session token from
auth login(with automatic refresh)
OAuth Device Flow (recommended for interactive use)
Register a native app in your Zitadel instance with the Device Code grant type enabled and JWT access tokens enabled, then log in once:
The command prints a URL and a short code. Open the URL in your browser,
enter the code, and approve the request. The CLI polls in the background and
saves the access and refresh tokens to
~/.config/zitadel-tui/tokens.json (mode 0600).
After login, subsequent commands use the cached token automatically:
Tokens are silently refreshed when they expire. Log out with:
Token cache
The session token cache lives at:
~/.config/zitadel-tui/tokens.json
It is created with mode 0600. The cache stores the access token, refresh
token, expiry timestamp, client ID, and host. The device_client_id config
field remembers your client ID so you only need --client-id once.
Docker
Development
Git hooks
This repo uses lefthook for local guardrails:
Configured hooks:
pre-commit:cargo fmt --checkcommit-msg: enforce Conventional Commitspre-push:cargo build
Release
The release workflow is tag-driven through release-please and publishes:
- GitHub release artifacts
- GHCR container images
- the Rust crate to
crates.io
The publish job expects CARGO_REGISTRY_TOKEN in GitHub Actions secrets.
If a GitHub outage or transient runner failure interrupts publishing after a
tag is created, run the release workflow manually with the existing tag name
to retry the release jobs.
License
MIT