Aurora Nexus
Aurora NexusSécurité

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_EXTRA_ISSUER_URLS=
OIDC_EXTRA_AUDIENCES=
OIDC_ALLOWED_ALGORITHMS=RS256
OIDC_JWKS_CACHE_TTL_SECONDS=3600
NEXUS_M2M_CALLER_APP_CLIENTS=

# 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=sha256

Flux humain

Login

  1. L'utilisateur ouvre Nexus sans session valide.
  2. Nexus genere state, nonce, code_verifier et code_challenge.
  3. Nexus redirige vers l'authorization endpoint authentik.
  4. authentik authentifie l'utilisateur et applique les politiques MFA.
  5. authentik redirige vers /auth/callback.
  6. Nexus echange le code cote serveur, valide state, nonce, token response et ID/access token.
  7. 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_access devient 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-configuration

En mode issuer authentik par provider, l'issuer inclut le chemin /application/o/<slug>/.

Le discovery document doit fournir :

  • issuer;
  • authorization_endpoint;
  • token_endpoint;
  • userinfo_endpoint si utilise;
  • jwks_uri;
  • end_session_endpoint si 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 :

ElementRegle
Signatureverification via JWKS
Algorithmepresent dans OIDC_ALLOWED_ALGORITHMS; HS256 interdit pour OIDC
Issueregal a OIDC_ISSUER_URL
Audiencecontient OIDC_AUDIENCE ou l'OIDC_CLIENT_ID Authentik
Expirationexp futur
Not beforenbf respecte si present
Issued atiat raisonnable
Subjectsub non vide
Scopescope ou scp parse
Tenanttenant_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;
  • aud doit contenir OIDC_AUDIENCE ou l'OIDC_CLIENT_ID du provider Authentik;
  • si un provider Authentik M2M dedie a une integration est utilise, son issuer doit etre declare explicitement dans OIDC_EXTRA_ISSUER_URLS et son client_id/audience dans OIDC_EXTRA_AUDIENCES;
  • tenant_id est obligatoire;
  • scope ou scp porte les droits Nexus minimaux;
  • client_id ou azp identifie le client machine;
  • grant_type=client_credentials, gty=client_credentials ou l'absence de claims humains avec client_id classe 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.ingest sans nexus.export si l'integration n'exporte pas);
  • binding optionnel caller_app -> client_id cote Nexus via NEXUS_M2M_CALLER_APP_CLIENTS quand une integration poste un caller_app;
  • rotation du secret/app password token dans Authentik;
  • absence de secret brut dans le depot Nexus.

Integration B DATA Studio

B DATA Studio utilise un client OAuth2 technique dedie pour exporter des rapports HTML vers Nexus. Ce flux est serveur-a-serveur : le frontend B DATA ne transmet pas de token Nexus utilisateur et le provider Authentik n'est pas rattache a un login humain.

Configuration Authentik attendue :

ChampValeur
Instancehttps://auth.auroramind.fr
Token endpointhttps://auth.auroramind.fr/application/o/token/
Application / slugbdata-nexus-m2m
ProviderB DATA Nexus M2M
client_idbdata-nexus-worker
Grant effectifclient_credentials
Issuerhttps://auth.auroramind.fr/application/o/bdata-nexus-m2m/
Audiencebdata-nexus-worker
Scopesopenid profile email nexus.ingest nexus.query nexus.search

Variables Nexus correspondantes :

OIDC_EXTRA_ISSUER_URLS=https://auth.auroramind.fr/application/o/bdata-nexus-m2m/
OIDC_EXTRA_AUDIENCES=bdata-nexus-worker
NEXUS_M2M_CALLER_APP_CLIENTS=b_data:bdata-nexus-worker

Variables serveur B DATA attendues :

BDS_NEXUS_AUTH_MODE=authentik_client_credentials
BDS_NEXUS_OIDC_CLIENT_ID=bdata-nexus-worker
BDS_NEXUS_OIDC_CLIENT_SECRET=<secret Authentik hors depot>
BDS_NEXUS_OIDC_TOKEN_URL=https://auth.auroramind.fr/application/o/token/
BDS_NEXUS_OIDC_SCOPES=openid profile email nexus.ingest nexus.query nexus.search
BDS_NEXUS_OIDC_AUDIENCE=bdata-nexus-worker
BDS_ALLOWED_NEXUS_BASES=https://nexus.auroramind.fr

Verification minimale sans publier de JWT brut :

  1. Obtenir un token client_credentials cote serveur B DATA.
  2. Verifier que iss vaut l'issuer M2M B DATA, que aud contient bdata-nexus-worker, que le client est bdata-nexus-worker et qu'au moins un scope nexus.* est present.
  3. Appeler GET /api/auth/oidc/me avec le bearer M2M.
  4. Attendre is_machine=true, client_id=bdata-nexus-worker et les scopes Nexus.
  5. Tester GET /api/source-apps?locale=fr-FR puis le workflow ingestion upload/init, upload presigne, upload/commit avec caller_app=b_data, et polling GET /api/ingest/jobs/{job_id}.

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.

Intégrations M2M V1 : scopes et binding

Les APIs /api/v1/integration-scopes, /api/v1/media, /api/v1/domain-projections et /api/v1/knowledge-graph appliquent les contrôles cumulés suivants :

  1. principal OIDC classé machine ;
  2. caller_app configuré dans NEXUS_M2M_CALLER_APP_CLIENTS ;
  3. client_id ou sujet du bearer autorisé pour ce caller ;
  4. source_app == caller_app dans le contrat actuel ;
  5. scope OAuth Nexus requis ;
  6. permission can_read ou can_write sur la source ;
  7. résolution du tenant_id et du workspace côté Nexus.
FamilleLectureMutation
Integration scopesnexus.query + can_readnexus.ingest + can_write
Media V1nexus.query + scope opaque actifnexus.ingest + scope opaque actif
Domain projectionsnexus.query pour lecture/réconciliationnexus.ingest pour upsert/retract/restore
Knowledge Graph workspacenexus.querynexus.ingest pour rebuild

Le external_scope_id n'est pas une autorisation : il ne devient utilisable qu'après résolution d'un mapping actif appartenant au même tenant, caller et source. Une ressource hors périmètre reste non énumérable.

Le client Narrélia livré utilise un principal technique dédié, lié à caller_app=narrelia. Les routes génériques Media V1 réutilisent actuellement ce backend privé ; leur ouverture à un autre caller exige un lot de sécurité explicite. Le contrat fonctionnel complet est dans ../07_Reference-Tech/56-API-Integrations-M2M-V1.md.

Exemples de profils :

ClientScopes NexusUsage
nexus-n8n-workernexus.ingestDeposer des documents et lancer l'ingestion.
bdata-nexus-workeropenid profile email nexus.ingest nexus.query nexus.searchExport serveur B DATA Studio, destinations et ingestion HTML.
narrelia-nexus-workernexus.ingest nexus.queryScopes opaques, projections, médias privés et KG workspace Narrélia.
nexus-intelligence-readernexus.queryLire des context packs / requetes RAG.
nexus-exporternexus.query nexus.exportExport controle, a eviter par defaut.

Exemple de binding Nexus :

NEXUS_M2M_CALLER_APP_CLIENTS=b_data:bdata-nexus-worker

Ce binding ne remplace pas les permissions historiques : les applications non migrees Authentik continuent d'utiliser les sessions/JWT Nexus. Une app peut etre migree plus tard en ajoutant son client Authentik et, si elle fournit un caller_app, son entree dans NEXUS_M2M_CALLER_APP_CLIENTS.

Rotation recommandee :

  1. Creer un nouveau token/app password cote Authentik.
  2. Mettre a jour le secret dans le coffre runtime de l'integration cliente.
  3. Verifier l'obtention d'un nouveau token client_credentials.
  4. Revoquer l'ancien token/app password.
  5. 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 | None

is_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.read

Regle : 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_worker

Mapping 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_app

Pour 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

EndpointLotRegle
GET /auth/loginNX-AUTH-002redirection authentik
GET /auth/callbackNX-AUTH-002echange code server-side
POST /auth/logout ou GET /auth/logoutNX-AUTH-002logout local + IdP
GET /auth/meNX-AUTH-002/003principal Nexus courant
dependencies FastAPINX-AUTH-003/004get_current_principal, require_scope, require_role
step-up dependencyNX-AUTH-008require_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 :

  1. NX-AUTH-002 ajoute OIDC sans supprimer brutalement l'ancien code.
  2. NX-AUTH-005 masque et borne le login password local.
  3. NX-AUTH-005 desactive reset password en flux normal.
  4. 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 si BREAK_GLASS_LOGIN_ENABLED=true et que l'e-mail appartient a BREAK_GLASS_EMAILS;
  • les evenements d'authentification distinguent oidc, password_legacy et break_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 Login comme action principale quand NEXT_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.query refuse 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.ingest autorise 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_time trop ancien;
  • admin avec e-mail OTP seul refuse si amr/acr permet la distinction;
  • action sensible auditee.

Webhooks

  • signature valide acceptee;
  • signature invalide refusee;
  • timestamp trop ancien refuse;
  • key_id inconnu refuse;
  • secret jamais logue.

Stop conditions pour implementation

  • authentik ne fournit pas une cle de signature asymetrique/JWKS;
  • issuer ou audience non stabilises;
  • claims tenant_id, groups, scope/scp impossibles a obtenir ou mapper;
  • besoin d'exposer un secret client au navigateur;
  • absence de strategie break-glass;
  • impossibilite de tester avec JWKS fake local.

On this page