Zitadel Integration
Zitadel is the recommended identity provider for Shoehorn. It handles authentication via OIDC, provides group claims for team mapping, and supports server-to-server team synchronization via a service user PAT.
Prerequisites
Section titled “Prerequisites”- A running Zitadel instance (self-hosted or cloud)
- Admin access to create projects, applications, and service users
- Shoehorn deployed with Helm
1. Create a Project
Section titled “1. Create a Project”- Log in to the Zitadel console
- Navigate to Projects > Create Project
- Name it (e.g., “Shoehorn”)
- Note the Project ID from the project details page
2. Create a Web Application
Section titled “2. Create a Web Application”- In the project, click New Application
- Select Web as the application type
- Set the Redirect URI:
https://shoehorn.example.com/auth/callback - Set the Post-Logout Redirect URI:
https://shoehorn.example.com - Note the Client ID
3. Create a Service User
Section titled “3. Create a Service User”A service user enables server-to-server communication for team and group synchronization.
- Navigate to Users > Service Users > New
- Create a service user (e.g., “shoehorn-sync”)
- Generate a Personal Access Token (PAT)
- Grant the service user access to the project:
- Go to the project
- Under Authorizations, add the service user
4. Configure Group Claims
Section titled “4. Configure Group Claims”Zitadel includes groups in the groups JWT claim by default. No additional configuration is required.
To verify, decode a JWT token and check for the groups field.
5. Configure Shoehorn
Section titled “5. Configure Shoehorn”Set these environment variables:
AUTH_PROVIDER=zitadelZITADEL_URL=http://zitadel:8080 # Internal URL (cluster-internal)ZITADEL_EXTERNAL_URL=https://auth.example.com # Browser-accessible URLZITADEL_PROJECT_ID=349308689758290610ZITADEL_CLIENT_ID=349310449335993010ZITADEL_SERVICE_USER_PAT=your-pat-here # For team syncHelm Values
Section titled “Helm Values”auth: provider: zitadel zitadel: projectId: "349308689758290610" clientId: "349310449335993010" externalUrl: "https://auth.example.com" insecure: false serviceUserPatSecret: name: zitadel-credentials key: service-user-patCreate the Kubernetes secret:
kubectl create secret generic zitadel-credentials \ --from-literal=service-user-pat="your-pat-here"Team Sync
Section titled “Team Sync”With the service user PAT configured, Shoehorn can synchronize groups from Zitadel into teams.
How It Works
Section titled “How It Works”- Shoehorn queries the Zitadel API for organization groups
- Groups are matched to Shoehorn teams via group mappings
- When a user logs in, their group memberships update their Shoehorn team assignments
Creating Group Mappings
Section titled “Creating Group Mappings”Map a Zitadel group to a Shoehorn team:
curl -X POST https://shoehorn.example.com/api/v1/admin/teams/<team-id>/group-mappings \ -H "Authorization: Bearer <token>" \ -H "Content-Type: application/json" \ -d '{ "group_id": "engineering-platform", "idp_provider": "zitadel" }'Or via the UI: navigate to Organization > Teams, select a team, go to the Group Mappings tab, and click Add Mapping.
Multi-Provider Sync
Section titled “Multi-Provider Sync”If you use Zitadel alongside other identity providers, enable OrgData sync:
auth: orgdata: enabled: true providers: ["zitadel", "okta"] primaryProvider: "zitadel" # Conflict resolution priorityWhen multiple providers are enabled:
- Users are deduplicated by email
- Teams are deduplicated by name
- The primary provider wins conflicts
Session Configuration
Section titled “Session Configuration”AUTH_ENCRYPTION_KEY=$(openssl rand -hex 32) # Required in productionSESSION_MAX_AGE=8h # Session validity (default: 8h)CSRF_ENABLED=true # CSRF protectionTenant ID Strategy
Section titled “Tenant ID Strategy”Configure how Shoehorn extracts the tenant from Zitadel JWT claims:
| Strategy | Configuration | Use Case |
|---|---|---|
provider_claim | TENANT_ID_CLAIM_KEY=azp | Single tenant (default) |
urn_claim | TENANT_ID_CLAIM_KEY=urn:zitadel:iam:org:id | Multi-org Zitadel |
env_var | DEFAULT_TENANT_ID=default | Fixed tenant |
Troubleshooting
Section titled “Troubleshooting”Login redirects to a blank page
- Verify
ZITADEL_EXTERNAL_URLis browser-accessible (not an internal-only URL) - Check the redirect URI matches exactly in both Zitadel and Shoehorn
Groups not appearing in JWT
- Confirm the user is a member of the group in Zitadel
- Check the service user has project access
- Decode the JWT at the
/auth/debugendpoint to inspect claims
Team sync not working
- Verify the service user PAT is valid and not expired
- Check that group mappings exist for the relevant groups
- Review API logs for sync errors
See Also
Section titled “See Also”- Identity Providers - Overview of all supported providers
- Group Mappings - Map IdP groups to teams
- Teams - Team creation and management
- Team Sync - Multi-provider synchronization