🎯 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)

SolutionOIDC supportIAM completLangageOrigine / Société
KeycloakJavaProjet CNCF (ex Red Hat)
ORY HydraPartielGoORY (Allemagne)
AuthentikPythonAuthentik Security (US/EU)
AutheliaGoCommunaute OSS
ZITADELGoZITADEL AG (Suisse)
DexPartielGoOSS community
KanidmRustOSS community
Gluu ServerPython/JavaGluu Inc
LemonLDAP::NG✅ (via modules)PerlFrance / OSS
Logto (OSS)TypeScriptOSS 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 : Ecran d'accueil Avec la redirection sur l’écran de login de Keycloak : Login

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

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 😀.

Login 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 :

  1. Initialiser la base de données de Zitadel.
  2. Configurer le backend de Zitadel.
  3. Configurer le frontend UI v2 de Zitadel.
  4. 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.

Crédits & Ressources