🎯 Problématique
Dans cet article, je vous propose de découvrir rapidement une solution sur laquelle je suis tombé lors d’un petit projet interne chez Clever Tech Ware.
Pour mettre un peu de contexte, cela fait plus de 10 ans que j’utilise Keycloak en production quand j’ai besoin d’une solution OIDC. Mais en ce début d’année, je me suis demandé si des alternatives existaient.
À l’aide de ChatGPT, j’ai découvert une liste assez vaste (mais non exhaustive) de solutions de serveurs OpenID Connect (OIDC) open-source que vous pouvez installer en on-premise (sur votre infrastructure) 👇
📊 Comparaison rapide (haut-niveau)
| Solution | OIDC support | IAM complet | Langage | Origine / Société |
|---|---|---|---|---|
| Keycloak | ✅ | ✅ | Java | Projet CNCF (ex Red Hat) |
| ORY Hydra | ✅ | Partiel | Go | ORY (Allemagne) |
| Authentik | ✅ | ✅ | Python | Authentik Security (US/EU) |
| Authelia | ✅ | ✅ | Go | Communaute OSS |
| ZITADEL | ✅ | ✅ | Go | ZITADEL AG (Suisse) |
| Dex | ✅ | Partiel | Go | OSS community |
| Kanidm | ✅ | ✅ | Rust | OSS community |
| Gluu Server | ✅ | ✅ | Python/Java | Gluu Inc |
| LemonLDAP::NG | ✅ (via modules) | ✅ | Perl | France / OSS |
| Logto (OSS) | ✅ | ✅ | TypeScript | OSS project |
Si vous souhaitez voir le détail des résultats 👇, sinon vous pouvez directement aller ici
🔐 1. Keycloak
- Type : Serveur d’identité IAM / IdP OpenID Connect
- Technologie : Java / WildFly / Quarkus
- Origine / Société : Projet initialement géré par Red Hat (États-Un), maintenant incubé par la CNCF (Cloud Native Computing Foundation) avec contributions globales.
🌐 2. ORY Hydra
- Type : Serveur OAuth2 + OIDC
- Technologie : GoLang
- Origine / Société : ORY (société d’Allemagne) — Projet open-source industriel
🧠 3. Authentik
- Type : IdP / IAM supportant OIDC, OAuth2, SAML, LDAP
- Technologie : Python / Django
- Origine / Société : Authentik Security Inc — projet open-source avec contributions internationales (forte communauté US/EU). (cerbos.dev)
🪶 4. Authelia
- Type : IAM / Identity provider / OIDC Provider
- Technologie : GoLang + React (interface)
- Origine / Société : Projet open-source indépendant (communauté globale). (Authelia)
🧱 5. ZITADEL
- Type : IAM / Identity provider
- Technologie : GoLang
- Origine / Société : ZITADEL AG (Suisse).
- Note : Supporte OIDC, OAuth2, SAML, multi-tenancy et SCIM. (AIMultiple)
🐧 6. Dex
- Type : OIDC / fédérateur d’identité
- Technologie : GoLang
- Origine / Société : Projet open-source (Community) — souvent utilisé comme IdP léger, notamment avec Kubernetes. (tencentcloud.com)
🦀 7. Kanidm
- Type : Gestion d’identité / OIDC provider
- Technologie : Rust
- Origine / Société : Projet Open Source indépendant (Global). (GitHub)
☁️ 8. Gluu Server
- Type : IAM / IdP complet (OIDC, OAuth2, SAML2, LDAP)
- Technologie : Python / Java
- Origine / Société : Gluu — IAM enterprise, largement utilisé en on-premise et cloud. (tencentcloud.com)
🗃️ 9. LemonLDAP::NG
- Type : AAA WebSSO / IdP (support OIDC via modules/extensions)
- Technologie : Perl + modules
- Origine / Société : Communauté Open-Source avec adoption forte en France (gouvernement, opérateurs télécoms). (arXiv)
📎 10. Logto (OSS)
- Type : IAM / OIDC provider (open-source)
- Technologie : TypeScript / Node
- Origine / Société : Projet open-source (Communauté / Logto maintainer). (Medium)
🪶 12. (Projets émergents)
🟡 Oak – IdP headless minimaliste, OIDC support (open-source, jeune communauté). (Reddit)
🟡 VigiloAuth – Projet expérimental écrit en Go (certification en cours, encore jeune). (Reddit)
🟡 TRusTY – Financial Grade Authentication in Rust, projet expérimental écrit en Rust par un français (certification en cours, encore jeune). (Blog)
🧩 Bonus
- ClientFedID – outil pour tester OIDC IdP (open-source) — utile pour validation de flux. (Aduneo)
🎯 Zitadel
Cette solution m’a plu, car :
- Je l’avais testée assez positivement en début d’année 2025,
- Écrite en Go,
- Assez mature (une petite dizaine d’années d’existence).
📕 Prérequis
Pour suivre ce tutoriel, assurez-vous d’avoir installé les outils suivants sur votre machine :
🧩 Tutoriel
Dans ce tutoriel, nous allons repartir du projet Hello World présenté dans cet article. Nous changerons uniquement le serveur OIDC : ❌ Keycloak => ✅ Zitadel.
1️⃣ Récupération du projet
Commencez par créer un nouveau projet :
git clone https://github.com/clevertechware/simple-demo-oidc-app.git
cd simple-demo-oidc-app
docker compose up -d
cd backend && cargo run
On démarre le projet pour vérifier qu’il fonctionne toujours 😊.
Normalement, vous devriez voir l’écran suivant :
Avec la redirection sur l’écran de login de Keycloak :

On s’arrête donc ici :
docker compose down --volumes
rm docker-compose.yml
2️⃣ Quick Start avec Zitadel
Pour cela, on va suivre le tutoriel de Zitadel pour le lancer en local en mode dev via docker-compose:
- Récupérez le fichier proposé par Zitadel :
curl -L https://raw.githubusercontent.com/zitadel/zitadel/main/docs/docs/self-hosting/deploy/docker-compose.yaml -o docker-compose.yaml
- Lancez Zitadel :
docker compose up --detach --wait
- Lancez la console Zitadel : http://localhost:8080/ui/console?login_hint=zitadel-admin@zitadel.localhost
Remarque: le mot de passe vaut
Password1!
- Créer le projet Demo sur l’organisation ZITADEL
- Créer l’application
web-app
type: WEB
méthode: PKCE
redirect uri: http://localhost:4200
Relevez bien le client ID, car on va devoir le configurer dans notre application frontend 👇.
Éditez le fichier frontend/src/app/app.config.ts et remplacez :
clientId: 'angular-client', // Your Keycloak client ID
par :
clientId: 'zitadel-client-web-app-id', // Your zitadel client ID
Remplacez l’ issuerUri dans les fichiers suivant :
frontend/src/environments/environment.ts,frontend/src/environments/environment.development.ts,
export const environment = {
production: false,
userApiUrl: 'http://localhost:8000',
issuerUrl: 'http://localhost:8080',
};
Désormais, quand vous cliquerez sur “Se connecter”, vous verrez la page de login de Zitadel 😀.

Plus qu’à vous logger avec le compte zitadel-admin@zitadel.localhost et voilà, nous avons changé de server OIDC.
Ok c’est sympa Zitadel, en mode dev, mais perso, quand j’ai voulu réaliser une installation type prod, j’ai eu beaucoup de mal
à trouver du contenu exemple. C’est pourquoi, je vais vous montrer une installation docker-compose exemple type prod.
3️⃣ Installation Zitadel type production
Ici, c’est une compilation de ce que j’ai pu trouver dans leur documentation pour une installation type production :
Quand on veut réaliser une installation type production, la base de données est souvent provisionnée. La configuration diffère donc de celle du “Getting Started”, et elle n’est pas toujours bien documentée, à mon sens.
Je recommande de créer une configuration au format YAML pour les paramètres statiques (ex : reverse proxy externe).
Pour ma part, je place ces fichiers dans le répertoire /etc/zitadel, donc vous trouverez un exemple ici.
A noter que j’ai du adapter la configuration pour donner un exemple qui se lance en local. Sur une instance type prod, je changerai les paramètres suivants 👇
# if reverse proxy handles tls termination
ExternalSecure: true
ExternalPort: 443
ExternalDomain: zitadel.mydomain.com
WebAuthNName: zitadel.mydomain.com
# If not using the docker compose example, adjust these values for connecting ZITADEL to your PostgreSQL
Database:
postgres:
Host: 'postgres'
Port: 5432
Database: zitadel
MaxOpenConns: 10
MaxIdleConns: 5
MaxConnLifetime: 30m
MaxConnIdleTime: 5m
User:
SSL:
Mode: 'require' # ou si vous avez des politiques très strict "verify-full"
Admin:
ExistingDatabase: zitadel
SSL:
Mode: 'require' # ou si vous avez des politiques très strict "verify-full"
DefaultInstance:
Features:
LoginV2:
BaseURI: https://zidatel.mydomain.com/ui/v2/login
Pour les identifiants de la base de données, il est recommandé de passer par un fichier séparé.
Dans la documentation officielle, il s’appelle secret.yaml. Dans mon setup, je l’ai nommé db.yaml :
Database:
postgres:
# Admin credentials should be the same as the application user credentials
Admin:
Username: zitadel
Password: 'zitadel-password'
User:
Username: zitadel
Password: 'zitadel-password'
🧩J’aurais aimé utiliser des secrets, mais le support n’est pas encore disponible. Une PR existe, en attendant, le fichier reste la voix la plus adaptée.
Enfin, on doit configurer la première instance liée à Zitadel. Celle-ci sera utilisée pour se connecter en super admin. Voici un exemple de fichier de configuration :
# All possible options and their defaults: https://github.com/zitadel/zitadel/blob/main/cmd/setup/steps.yaml
FirstInstance:
InstanceName: zitadel
LoginClientPatPath: /current-dir/login-client.pat
Org:
Name: demo
LoginClient:
Machine:
Username: login-client
Name: Automatically Initialized IAM_LOGIN_CLIENT
Pat:
ExpirationDate: '2029-01-01T00:00:00Z'
Human:
# In case that UserLoginMustBeDomain is false (default) and if you don't overwrite the username with an email,
# it will be suffixed by the org domain (org-name + domain from config).
# for example zitadel-admin in org `My Org` on domain.tld -> zitadel-admin@my-org.domain.tld
Username: bob.bobby@test.com # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_USERNAME
FirstName: Bob # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_FIRSTNAME
LastName: Bobby # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_LASTNAME
DisplayName: Administrator # ZITADEL_DEFAULTINSTANCE_ORG_HUMAN_DISPLAYNAME
Password: 'Password01!'
PasswordChangeRequired: true
🧩 Ce fichier est séparé de la configuration statique car il décrit le paramètre de configuration
--steps
Une fois toutes ces configurations prêtes, il suffit de suivre ces étapes :
- Initialiser la base de données de Zitadel.
- Configurer le backend de Zitadel.
- Configurer le frontend UI v2 de Zitadel.
- Configurer leur exposition publique via le reverse proxy (non réalisé ici pour cette démo).
Si, comme moi, vous utilisez docker-compose, voici un exemple de fichier résumé :
services:
# 1. Initialisation de la base existante pour zitadel
zitadel-init:
image: ghcr.io/zitadel/zitadel:v4.8.1
user: "${UID_GID}"
command: 'init zitadel --config /app/config.yaml --config /app/secrets.yaml'
## .. Autres options, voir le fichier sur github.
# 2. Paramétrer le backend de zitadel
zitadel:
image: ghcr.io/zitadel/zitadel:v4.8.1
container_name: zitadel
restart: unless-stopped
user: "${UID_GID}"
# ⚠️Faites bien attention de lancer la commande start-from-setup
# NOTE: using a reverse proxy like Traefik that terminates TLS, you need to use --tlsMode external
command: 'start-from-setup --config /app/config.yaml --config /app/secrets.yaml --steps /app/init-steps.yaml --masterkeyFile /app/masterkey --tlsMode disabled'
## .. Autres options, voir le fichier sur github.
# 3. Paramétrer le front v2 UI de zitadel
zitadel-login:
image: 'ghcr.io/zitadel/zitadel-login:latest'
container_name: zitadel-login
restart: unless-stopped
environment:
# Ici on note qu'on appel le service backend
ZITADEL_API_URL: http://zitadel:8080
NEXT_PUBLIC_BASE_PATH: /ui/v2/login
ZITADEL_SERVICE_USER_TOKEN_FILE: /current-dir/login-client.pat
# On transmets le header qui indique le nom de l'hôte associé à ZITADEL pour le backend
CUSTOM_REQUEST_HEADERS: Host:localhost
## .. Autres options, voir le fichier sur github.
Au lancement, vous devriez voir le workflow suivant:
zitadel-init —> zitadel —> zitadel-login
Avec les logs suivantes :
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify zitadel" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:80" database=zitadel
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify system" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:46"
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify encryption keys" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:51"
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify projections" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:56"
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify eventstore" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:61"
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify events tables" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:66"
zitadel-init | time="2026-01-17T08:26:48Z" level=info msg="verify unique constraints" caller="/home/runner/work/zitadel/zitadel/cmd/initialise/verify_zitadel.go:71"
zitadel-init exited with code 0
zitadel | time="2026-01-17T08:26:49Z" level=info msg="setup started" caller="/home/runner/work/zitadel/zitadel/cmd/setup/setup.go:108"
zitadel | time="2026-01-17T08:26:49Z" level=info msg="verify migration" caller="/home/runner/work/zitadel/zitadel/internal/migration/migration.go:46" name=14_events_push
zitadel | time="2026-01-17T08:26:49Z" level=info msg="verify migration" caller="/home/runner/work/zitadel/zitadel/internal/migration/migration.go:46" name=40_init_push_func_v4
zitadel | time=2026-01-17T08:26:49.349Z level=INFO msg="registered route" endpoint=/oauth/v2/keys
zitadel | time="2026-01-17T08:26:49Z" level=info msg="server is listening on [::]:8080" caller="/home/runner/work/zitadel/zitadel/cmd/start/start.go:729"
zitadel-login | ZITADEL_SERVICE_USER_TOKEN_FILE=/current-dir/login-client.pat is set. Awaiting file and reading token.
zitadel-login | token file found, reading token
zitadel-login | ▲ Next.js 15.5.9
zitadel-login | - Local: http://[::1]:3000
zitadel-login | - Network: http://[::]:3000
zitadel-login |
zitadel-login | ✓ Starting...
zitadel-login | ✓ Ready in 162ms
Conclusion
À travers cet article, nous avons découvert Zitadel, une alternative au service OIDC le plus utilisé sur le marché, Keycloak. Cette solution est très complète et différente de Keycloak.
Points positifs :
- Énormément de fonctionnalités (multi-tenancy, multi-projet),
- Rapide (le fait qu’elle soit écrite en Go y contribue, je pense),
- Une communauté très réactive,
Points faibles :
- Jeune, donc quelques problèmes lors des mises à jour (retours sur leurs issues GitHub),
- Documentation encore un peu éparse,
Pour finir, j’ai sincèrement apprécié découvrir cette solution open-source qu’est Zitadel.
N’hésitez pas à l’essayer vous-même 😎.
NOTE : le code source de ce tutoriel est disponible sur GitHub.