Contrat auth OIDC Nexus
contrat technique claims, sessions, JWKS, RBAC, step-up et tests d'acceptation
Objectif
Ce document fixe le contrat technique entre authentik et Nexus pour les lots NX-AUTH-002 a NX-AUTH-008.
Il complete l'ADR 04_Securite/23-ADR-Authentik-OIDC-MFA.md.
Variables cible
Ces variables sont le contrat cible. Elles seront ajoutees ou alignees dans .env.example par le lot qui implemente le comportement correspondant.
# OIDC / authentik
OIDC_ENABLED=false
OIDC_ISSUER_URL=https://auth.example.com/application/o/nexus/
OIDC_CLIENT_ID=nexus-ui
OIDC_CLIENT_SECRET=
OIDC_REDIRECT_URI=https://nexus.example.com/auth/callback
OIDC_POST_LOGOUT_REDIRECT_URI=https://nexus.example.com/
OIDC_SCOPES=openid email profile groups nexus.roles
OIDC_AUDIENCE=nexus-api
OIDC_ALLOWED_ALGORITHMS=RS256
OIDC_JWKS_CACHE_TTL_SECONDS=3600
# Sessions Nexus
SESSION_COOKIE_NAME=nexus_session
SESSION_COOKIE_SECURE=true
SESSION_COOKIE_SAMESITE=lax
SESSION_TTL_SECONDS=28800
STEP_UP_MAX_AGE_SECONDS=900
# Migration auth locale
LOCAL_PASSWORD_LOGIN_ENABLED=false
BREAK_GLASS_LOGIN_ENABLED=false
BREAK_GLASS_EMAILS=srey@auroramind.fr
LOCAL_USER_PASSWORD_CREATE_ENABLED=false
LOCAL_PASSWORD_ADMIN_RESET_ENABLED=false
NEXT_PUBLIC_BREAK_GLASS_EMAILS=srey@auroramind.fr
# Machine-to-machine
M2M_REQUIRED_AUDIENCE=nexus-api
M2M_DEFAULT_TOKEN_TTL_SECONDS=3600
# Webhooks
WEBHOOK_SIGNATURE_TOLERANCE_SECONDS=300
WEBHOOK_HMAC_ALGORITHM=sha256Flux humain
Login
- L'utilisateur ouvre Nexus sans session valide.
- Nexus genere
state,nonce,code_verifieretcode_challenge. - Nexus redirige vers l'authorization endpoint authentik.
- authentik authentifie l'utilisateur et applique les politiques MFA.
- authentik redirige vers
/auth/callback. - Nexus echange le code cote serveur, valide
state,nonce, token response et ID/access token. - Nexus cree une session locale
httpOnly.
Stockage tokens
Les tokens OIDC ne doivent pas etre stockes durablement dans le navigateur.
V1 recommandee :
- pas de refresh token cote navigateur;
- session Nexus bornee par
SESSION_TTL_SECONDS; - renouvellement via nouveau login authentik quand necessaire;
- si
offline_accessdevient necessaire, le refresh token doit rester cote serveur et etre chiffre ou reference par session.
Logout
Le logout doit :
- revoquer la session Nexus locale;
- supprimer le cookie;
- rediriger vers l'end session endpoint authentik si configure;
- rester robuste si authentik est temporairement indisponible.
Discovery et JWKS
Nexus charge la configuration depuis :
{OIDC_ISSUER_URL}/.well-known/openid-configurationEn mode issuer authentik par provider, l'issuer inclut le chemin /application/o/<slug>/.
Le discovery document doit fournir :
issuer;authorization_endpoint;token_endpoint;userinfo_endpointsi utilise;jwks_uri;end_session_endpointsi disponible;grant_types_supported;code_challenge_methods_supported.
Nexus doit refuser la configuration si issuer ne correspond pas exactement a OIDC_ISSUER_URL normalise.
Validation JWT
Nexus valide au minimum :
| Element | Regle |
|---|---|
| Signature | verification via JWKS |
| Algorithme | present dans OIDC_ALLOWED_ALGORITHMS; HS256 interdit pour OIDC |
| Issuer | egal a OIDC_ISSUER_URL |
| Audience | contient OIDC_AUDIENCE ou l'OIDC_CLIENT_ID Authentik |
| Expiration | exp futur |
| Not before | nbf respecte si present |
| Issued at | iat raisonnable |
| Subject | sub non vide |
| Scope | scope ou scp parse |
| Tenant | tenant_id ou mapping Nexus valide |
Claims requis
Humain
{
"iss": "https://auth.example.com/application/o/nexus/",
"aud": ["nexus-api"],
"sub": "authentik-user-id",
"email": "user@example.com",
"name": "User Name",
"groups": ["tenant-a-nexus-admin"],
"scope": "openid email profile nexus.query nexus.search",
"tenant_id": "tenant-a",
"auth_time": 1781540000,
"amr": ["pwd", "mfa", "webauthn"]
}Machine
{
"iss": "https://auth.example.com/application/o/nexus-m2m/",
"aud": ["nexus-api"],
"sub": "service-account-or-client-subject",
"client_id": "nexus-n8n-worker",
"scope": "nexus.ingest",
"tenant_id": "tenant-a"
}Machine-to-machine Authentik
Le mode M2M retenu pour Nexus est le flux OAuth2 client_credentials fourni par Authentik.
Contrat Nexus :
- le token est valide par discovery/JWKS comme les autres tokens OIDC;
auddoit contenirOIDC_AUDIENCEou l'OIDC_CLIENT_IDdu provider Authentik;tenant_idest obligatoire;scopeouscpporte les droits Nexus minimaux;client_idouazpidentifie le client machine;grant_type=client_credentials,gty=client_credentialsou l'absence de claims humains avecclient_idclasse le principal comme machine.
Les flux machine ne passent jamais par une MFA interactive. La securite repose sur :
- client/service account dedie par integration;
- TTL court des access tokens;
- scopes minimaux (
nexus.ingestsansnexus.exportsi l'integration n'exporte pas); - rotation du secret/app password token dans Authentik;
- absence de secret brut dans le depot Nexus.
Note Authentik : la documentation officielle M2M indique que les clients machine utilisent le grant client_credentials; l'identification se fait cote Authentik par client/service account et l'authentification par token/app password selon la configuration du provider. La configuration exacte reste a valider dans l'interface admin Authentik du tenant cible.
Note audience Authentik : les JWT emis par le provider OAuth2/OIDC Authentik portent l'audience du client_id du provider. Nexus accepte donc OIDC_CLIENT_ID en plus de OIDC_AUDIENCE pour les bearers API.
Exemples de profils :
| Client | Scopes Nexus | Usage |
|---|---|---|
nexus-n8n-worker | nexus.ingest | Deposer des documents et lancer l'ingestion. |
nexus-intelligence-reader | nexus.query | Lire des context packs / requetes RAG. |
nexus-exporter | nexus.query nexus.export | Export controle, a eviter par defaut. |
Rotation recommandee :
- Creer un nouveau token/app password cote Authentik.
- Mettre a jour le secret dans le coffre runtime de l'integration cliente.
- Verifier l'obtention d'un nouveau token
client_credentials. - Revoquer l'ancien token/app password.
- Verifier qu'aucune valeur brute n'a ete journalisee ni commitee.
Principal Nexus
Le backend normalise les claims vers ce modele logique :
class AuthPrincipal:
subject: str
email: str | None
name: str | None
tenant_id: str
groups: list[str]
scopes: set[str]
roles: set[str]
auth_time: int | None
amr: list[str]
is_machine: bool
client_id: str | Noneis_machine vaut true si le token vient d'un flux M2M valide ou si client_id/grant type et policy Nexus le classent explicitement comme machine.
Scopes API Nexus
Scopes cibles :
nexus.query
nexus.search
nexus.ingest
nexus.export
nexus.delete
nexus.admin
nexus.users.manage
nexus.api_keys.manage
nexus.connectors.manage
nexus.audit.readRegle : l'absence de scope requis refuse l'appel avant toute logique metier.
Roles Nexus
Roles cibles :
tenant_owner
tenant_admin
corpus_manager
analyst
reader
external_app
ingestion_workerMapping groupe recommande pour POC :
<tenant>-nexus-owner -> tenant_owner
<tenant>-nexus-admin -> tenant_admin
<tenant>-nexus-corpus-manager -> corpus_manager
<tenant>-nexus-analyst -> analyst
<tenant>-nexus-reader -> reader
<tenant>-nexus-n8n-worker -> ingestion_worker
<tenant>-nexus-external-app -> external_appPour production, Nexus doit verifier le mapping via une regle ou une table interne. Le prefixe de groupe seul ne suffit pas comme preuve tenant.
Endpoints attendus
| Endpoint | Lot | Regle |
|---|---|---|
GET /auth/login | NX-AUTH-002 | redirection authentik |
GET /auth/callback | NX-AUTH-002 | echange code server-side |
POST /auth/logout ou GET /auth/logout | NX-AUTH-002 | logout local + IdP |
GET /auth/me | NX-AUTH-002/003 | principal Nexus courant |
| dependencies FastAPI | NX-AUTH-003/004 | get_current_principal, require_scope, require_role |
| step-up dependency | NX-AUTH-008 | require_recent_mfa |
Migration depuis l'auth locale
Les lots doivent conserver un chemin de rollback tant que l'OIDC n'est pas valide en staging.
Plan cible :
NX-AUTH-002ajoute OIDC sans supprimer brutalement l'ancien code.NX-AUTH-005masque et borne le login password local.NX-AUTH-005desactive reset password en flux normal.- Les champs DB existants restent tant qu'une migration destructive n'est pas explicitement validee.
Etat NX-AUTH-005:
- le login local password est refuse si
LOCAL_PASSWORD_LOGIN_ENABLED=false, sauf siBREAK_GLASS_LOGIN_ENABLED=trueet que l'e-mail appartient aBREAK_GLASS_EMAILS; - les evenements d'authentification distinguent
oidc,password_legacyetbreak_glass; - la creation admin d'un utilisateur Nexus en mode OIDC peut generer un hash aleatoire non connu plutot que demander un mot de passe utilisateur;
- le reset password admin est bloque hors break-glass si
LOCAL_PASSWORD_ADMIN_RESET_ENABLED=false; - l'UI login affiche
Auroramind Secure Logincomme action principale quandNEXT_PUBLIC_OIDC_ENABLED=true, avec le formulaire local comme secours visible.
Tests d'acceptation
OIDC/JWT
- token valide accepte;
- token expire refuse;
- issuer incorrect refuse;
- audience incorrecte refusee;
- algorithme non autorise refuse;
- JWKS cache utilise puis rafraichi;
- scope manquant refuse.
RBAC tenant
- utilisateur sans
nexus.queryrefuse sur query; - tenant A ne lit pas tenant B;
- role admin tenant ne devient pas admin global sans mapping Nexus;
- refus audite.
M2M
- client avec
nexus.ingestautorise sur ingestion; - client sans scope requis refuse;
- logs affichent machine/client distinctement d'un utilisateur humain;
- aucune MFA interactive.
Step-up
- action sensible refusee si
auth_timetrop ancien; - admin avec e-mail OTP seul refuse si
amr/acrpermet la distinction; - action sensible auditee.
Webhooks
- signature valide acceptee;
- signature invalide refusee;
- timestamp trop ancien refuse;
key_idinconnu refuse;- secret jamais logue.
Stop conditions pour implementation
- authentik ne fournit pas une cle de signature asymetrique/JWKS;
issuerouaudiencenon stabilises;- claims
tenant_id,groups,scope/scpimpossibles a obtenir ou mapper; - besoin d'exposer un secret client au navigateur;
- absence de strategie break-glass;
- impossibilite de tester avec JWKS fake local.