Keycloak SSO client-only
Depuis NFZ 6.5.30, le modèle recommandé est simple : Keycloak reste côté client Nuxt.
NFZ ne doit pas orchestrer le callback OAuth/OIDC, ne doit pas gérer #state=..., et ne doit pas exposer de proxy Nitro pour LDAP. NFZ reste le client Feathers remote.
Keycloak = identité SSO navigateur
NFZ = client Feathers remote
LDAP/AD = enrichissement côté backend FeathersConfiguration recommandée
export default defineNuxtConfig({
ssr: false,
modules: [
'@pinia/nuxt',
'nuxt-feathers-zod',
],
runtimeConfig: {
public: {
keycloak: {
serverUrl: process.env.KEYCLOAK_SERVER_URL || 'https://keycloak.example.local',
realm: process.env.KEYCLOAK_REALM || 'EXAMPLE',
clientId: process.env.KEYCLOAK_CLIENT_ID || 'nuxt4app',
onLoad: process.env.KEYCLOAK_ON_LOAD || 'check-sso',
},
},
},
feathers: {
client: {
mode: 'remote',
remote: {
url: process.env.NFZ_REMOTE_URL || 'https://api.example.local',
transport: 'rest',
restPath: process.env.NFZ_REMOTE_REST_PATH ?? '',
services: [
{ path: 'authentication', methods: ['create', 'remove'] },
{ path: 'users', methods: ['find', 'get'] },
],
},
pinia: true,
},
keycloak: false,
auth: false,
server: {
enabled: false,
},
},
})Plugin client Keycloak
L'application initialise keycloak-js dans app/plugins/keycloak.client.ts, puis stocke token et tokenParsed dans un store Pinia. Le nettoyage de l'URL doit être fait après keycloak.init().
const authenticated = await keycloak.init({
onLoad: 'check-sso',
pkceMethod: 'S256',
checkLoginIframe: false,
responseMode: 'fragment',
silentCheckSsoRedirectUri: `${window.location.origin}/silent-check-sso.html`,
})
cleanupOidcCallbackUrl()Ne nettoie pas #state=... avant keycloak.init(), sinon Keycloak ne pourra pas finaliser le callback.
Bridge LDAP explicite
Quand le backend Feathers expose une stratégie keycloak-ldap, l'application appelle directement NFZ remote :
const { $api } = useNuxtApp()
const sso = useSsoSessionStore()
const result = await $api.service('authentication').create({
strategy: 'keycloak-ldap',
username: sso.username,
authenticated: true,
access_token: sso.token,
tokenParsed: sso.tokenParsed,
ssoUser: sso.tokenParsed,
})La réponse backend devient la session applicative enrichie :
const ldapUser = result.user
const feathersToken = result.accessTokenRègles de stabilisation
- garde
ssr: falsepour les applications Keycloak SPA ; - garde Keycloak dans un plugin client Nuxt ;
- configure
feathers.keycloak: false; - ne crée pas de proxy Nitro
/api/keycloak-ldapsi le backend CORS est corrigé ; - sépare
sso-sessionetldap-session; - le backend doit accepter
OPTIONS /authenticationetPOST /authentication.
Guide complet : Nuxt 4 SPA + Keycloak client-only + LDAP backend.
