Cette page montre comment brancher une application existante sur Keycloak en OpenID Connect. Vous n'écrivez plus de page de login : votre application redirige l'utilisateur vers Keycloak, qui l'authentifie et renvoie un token signé. Le guide couvre le choix du type de client, les redirect URIs, l'activation de PKCE, et la récupération d'un token machine-to-machine avec client_credentials. Public : développeur ou administrateur qui a déjà un realm Keycloak et veut y connecter une vraie application.
Ce guide est un how-to Keycloak. Si les notions de token, de scope ou de flow ne sont pas claires, lisez d'abord les concepts : OpenID Connect pour l'authentification et OAuth 2.x pour la délégation d'accès aux API. Ici, on configure.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Choisir le bon type de client selon votre application (SPA, backend, service)
- Créer un client OIDC dans un realm, en console et en ligne de commande
- Configurer les redirect URIs et web origins pour éviter les erreurs de redirection et de CORS
- Activer PKCE pour protéger le flow d'autorisation
- Récupérer et inspecter un token via les endpoints OIDC standard
- Sécuriser une API sans utilisateur avec le flow
client_credentials
Prérequis
Section intitulée « Prérequis »Avant de commencer, il vous faut :
- Une instance Keycloak fonctionnelle. Voir Installation de Keycloak.
- Un realm applicatif créé (jamais le realm
master) avec au moins un utilisateur de test. Voir Administrer Keycloak. Les exemples utilisent le realmlabet l'utilisateuralice. - Une application à connecter : peu importe le langage, le principe est identique. Ce qui change, c'est la bibliothèque OIDC côté application.
Étape 1 - Choisir le bon type de client
Section intitulée « Étape 1 - Choisir le bon type de client »Un client dans Keycloak représente une application autorisée à demander des tokens. Le premier choix, celui qui conditionne toute la sécurité, est public ou confidentiel. La différence tient à un seul point : l'application est-elle capable de garder un secret ?
| Type de client | Peut garder un secret | Application typique | Flow recommandé |
|---|---|---|---|
| Confidentiel | Oui (code serveur) | Application web avec backend, API | Authorization Code + PKCE |
| Public | Non (code visible) | SPA (React, Vue), application mobile, CLI | Authorization Code + PKCE |
| Confidentiel + service account | Oui | Service sans utilisateur (cron, backend-to-backend) | Client Credentials |
Une SPA (single-page application) ou une application mobile tourne entièrement chez l'utilisateur : son code JavaScript ou son binaire sont lisibles, donc elle ne peut pas stocker de secret. Elle est publique. À l'inverse, un backend Node, Django ou Spring garde son secret sur le serveur : il est confidentiel.
Étape 2 - Créer le client d'une application web
Section intitulée « Étape 2 - Créer le client d'une application web »Prenons une application web classique avec un backend, servie sur https://app.exemple.fr. Après login, Keycloak doit renvoyer l'utilisateur sur une URL de rappel : https://app.exemple.fr/callback.
-
Sélectionnez votre realm (
lab) dans le sélecteur en haut à gauche, puis Clients > Create client. -
General settings :
- Client type :
OpenID Connect - Client ID :
webapp-demo
- Client type :
-
Capability config :
- Client authentication :
On(c'est ce qui rend le client confidentiel) - Authorization :
Off(les permissions fines sont un autre sujet) - Standard flow : coché (c'est l'Authorization Code)
- Direct access grants : décoché
- Client authentication :
-
Login settings :
- Valid redirect URIs :
https://app.exemple.fr/callback - Web origins :
https://app.exemple.fr
- Valid redirect URIs :
-
Save. Le secret est disponible dans l'onglet Credentials.
Le CLI kcadm.sh permet de scripter la création, utile pour reproduire la configuration d'un environnement à l'autre. On s'authentifie une fois, puis on crée le client :
# S'authentifier sur le realm master (admin)kcadm.sh config credentials --server http://localhost:8080 \ --realm master --user admin --password 'VotreMotDePasse'
# Créer le client web confidentiel, standard flow uniquementkcadm.sh create clients -r lab \ -s clientId=webapp-demo \ -s enabled=true \ -s publicClient=false \ -s standardFlowEnabled=true \ -s directAccessGrantsEnabled=false \ -s 'redirectUris=["https://app.exemple.fr/callback"]' \ -s 'webOrigins=["https://app.exemple.fr"]'La configuration posée se relit pour vérification :
kcadm.sh get clients -r lab -q clientId=webapp-demo \ --fields clientId,publicClient,standardFlowEnabled,redirectUris,webOrigins[ { "clientId" : "webapp-demo", "publicClient" : false, "standardFlowEnabled" : true, "redirectUris" : [ "https://app.exemple.fr/callback" ], "webOrigins" : [ "https://app.exemple.fr" ]} ]Étape 3 - Activer PKCE
Section intitulée « Étape 3 - Activer PKCE »PKCE (Proof Key for Code Exchange, prononcé « pixy ») empêche l'interception du code d'autorisation. L'application génère un secret aléatoire à chaque connexion, en envoie l'empreinte à Keycloak, puis prouve qu'elle détient l'original au moment d'échanger le code contre un token. Sans le secret original, un code volé est inutilisable.
PKCE se règle par client, dans l'onglet Advanced :
-
Ouvrez le client
webapp-demo> onglet Advanced. -
Section Advanced settings > Proof Key for Code Exchange Code Challenge Method : choisissez
S256. -
Save.
Étape 4 - Comprendre les endpoints OIDC
Section intitulée « Étape 4 - Comprendre les endpoints OIDC »Votre bibliothèque OIDC (côté application) a besoin de connaître les URLs de Keycloak : où rediriger l'utilisateur, où échanger le code, où valider les tokens. Toutes ces adresses sont publiées à un seul endroit, le document de découverte :
curl -s http://localhost:8080/realms/lab/.well-known/openid-configuration{ "issuer": "http://localhost:8080/realms/lab", "authorization_endpoint": "http://localhost:8080/realms/lab/protocol/openid-connect/auth", "token_endpoint": "http://localhost:8080/realms/lab/protocol/openid-connect/token", "userinfo_endpoint": "http://localhost:8080/realms/lab/protocol/openid-connect/userinfo", "jwks_uri": "http://localhost:8080/realms/lab/protocol/openid-connect/certs", "end_session_endpoint": "http://localhost:8080/realms/lab/protocol/openid-connect/logout"}La plupart des bibliothèques (Spring Security, oidc-client-ts, authlib en Python, oauth2-proxy) ne demandent que l'issuer et découvrent le reste automatiquement. Retenez ces trois adresses :
- authorization_endpoint : où l'application envoie l'utilisateur pour se connecter.
- token_endpoint : où l'application échange le code contre un token.
- jwks_uri : les clés publiques pour vérifier la signature des tokens sans appeler Keycloak à chaque requête.
Étape 5 - Sécuriser un service sans utilisateur (Client Credentials)
Section intitulée « Étape 5 - Sécuriser un service sans utilisateur (Client Credentials) »Tous les besoins ne concernent pas un humain. Un job planifié ou un backend qui appelle une autre API n'a pas d'utilisateur à connecter : il s'authentifie lui-même. C'est le flow Client Credentials, réservé aux clients confidentiels avec service account.
-
Créez un client dédié au service, sans standard flow, avec service account activé :
Fenêtre de terminal kcadm.sh create clients -r lab \-s clientId=backend-api \-s enabled=true \-s publicClient=false \-s serviceAccountsEnabled=true \-s standardFlowEnabled=false -
Récupérez le secret généré :
Fenêtre de terminal cid=$(kcadm.sh get clients -r lab -q clientId=backend-api --fields id --format csv --noquotes)kcadm.sh get clients/$cid/client-secret -r lab -
Demandez un token avec le secret. Aucune interaction utilisateur, un simple appel serveur-à-serveur :
Fenêtre de terminal curl -s -X POST http://localhost:8080/realms/lab/protocol/openid-connect/token \-d grant_type=client_credentials \-d client_id=backend-api \-d client_secret='LE_SECRET_DU_CLIENT'
Le token reçu est un JWT (JSON Web Token). Décodé, son contenu confirme le client émetteur et sa durée de vie courte :
{ "iss": "http://localhost:8080/realms/lab", "typ": "Bearer", "azp": "backend-api", "preferred_username": "service-account-backend-api", "scope": "profile email"}La durée de vie vaut ici 300 secondes (exp - iat). C'est volontaire : un token court limite la fenêtre d'exploitation s'il fuite. Le service redemande simplement un token quand l'ancien expire. Ne cherchez pas à allonger cette durée pour éviter les renouvellements ; c'est un mauvais compromis de sécurité.
Étape 6 - Valider un token côté application
Section intitulée « Étape 6 - Valider un token côté application »Recevoir un token ne suffit pas : votre API doit le vérifier avant de faire confiance à son contenu. Deux approches, selon votre besoin.
La première, hors ligne, vérifie la signature du JWT avec les clés publiques de Keycloak (jwks_uri). C'est la méthode à privilégier pour une API : rapide, sans appel réseau à chaque requête. Keycloak expose ses clés ainsi :
curl -s http://localhost:8080/realms/lab/protocol/openid-connect/certsLe realm publie deux clés : une pour signer les tokens (RS256) et une pour le chiffrement (RSA-OAEP). Votre bibliothèque sélectionne la bonne via l'en-tête du JWT. La signature validée, vous savez que le token vient bien de Keycloak et n'a pas été modifié.
La seconde, en ligne, interroge l'endpoint userinfo avec le token. Utile pour récupérer les informations à jour de l'utilisateur :
curl -s http://localhost:8080/realms/lab/protocol/openid-connect/userinfo \ -H "Authorization: Bearer LE_TOKEN"{ "sub": "03816d65-6748-4977-8457-b3eb400a6fe4", "email_verified": true, "name": "Alice Martin", "preferred_username": "alice", "given_name": "Alice", "family_name": "Martin", "email": "alice@exemple.fr"}Sécurité
Section intitulée « Sécurité »Quelques règles non négociables pour une intégration OIDC saine :
- PKCE
S256obligatoire pour tout flow d'autorisation, public comme confidentiel. Jamaisplain. - Redirect URIs exactes, jamais de joker large ni de
localhost:*en production. - Client confidentiel dès que possible : si l'application a un backend, elle garde un secret, donc elle est confidentielle.
- Secret client traité comme un mot de passe : jamais dans le dépôt Git, jamais dans le code front. Variable d'environnement ou coffre-fort. Voir HashiCorp Vault.
- Durée de vie des tokens courte (5 minutes par défaut) et renouvellement par refresh token. Ne l'allongez pas par confort.
- HTTPS partout : un token qui transite en clair est un token volé. En production, Keycloak et vos applications sont derrière TLS.
- Validation systématique de la signature, de l'issuer et de l'audience côté API.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
Invalid parameter: redirect_uri | L'URL de rappel de l'app n'est pas dans les Valid redirect URIs | Ajouter l'URL exacte dans la config du client |
| Erreur CORS dans la console du navigateur | Web origins non renseigné pour une SPA | Ajouter l'origine (https://app.exemple.fr) dans Web origins |
invalid_client au token endpoint | Mauvais secret, ou client public appelé avec un secret | Vérifier le secret dans Credentials ; un client public n'en a pas |
unauthorized_client avec client_credentials | Service account non activé | Activer Service accounts roles sur le client |
Account is not fully set up | L'utilisateur a une action requise en attente (profil incomplet) | Renseigner firstName/lastName et lever les required actions du compte |
| Token accepté mais rôles absents | Le scope ou le mapper ne remonte pas les rôles | Vérifier les Client scopes et les mappers du client |
À retenir
Section intitulée « À retenir »- Un client Keycloak représente une application ; le premier choix est public ou confidentiel selon la capacité à garder un secret.
- Authorization Code + PKCE
S256est le standard pour toute application interactive. Le flow implicite est abandonné. - Les redirect URIs exactes protègent contre le vol de token ; les web origins débloquent les appels CORS des SPA.
- Le document
.well-known/openid-configurationdonne tous les endpoints ; la plupart des bibliothèques n'ont besoin que de l'issuer. - Le flow
client_credentialsauthentifie un service sans utilisateur, via un client confidentiel avec service account. - Une API valide toujours la signature (via
jwks_uri), l'issuer et l'audience avant de faire confiance à un token.