Thème
Identité & accès (IAM / RBAC)
Objectif
Cet espace pilote qui accède à quoi dans votre tenant : le mode d'authentification (JWT local ou SSO Okta), les rôles et permissions (RBAC), l'accès aux données par cost center, et l'audit des changements. L'identité (IdP) prouve qui vous êtes ; Finoptika décide ce que vous pouvez faire — indépendamment de l'IdP.
Qui l'utilise
Tenant Admin, FinOps Admin. Le Super Admin gère l'ensemble.
| Page | Route | Permission de garde |
|---|---|---|
| Utilisateurs | \/admin/iam → Users | platform:users:read |
| Rôles & permissions | \/admin/iam → Roles | platform:roles:read |
| Accès & audit / IdP | \/admin/iam → Access | platform:audit:read ou platform:settings:read |
Prérequis
- Rôle Admin ou Super Admin dans le tenant.
- Pour le SSO : accès à votre console Okta (ou autre IdP OIDC/SAML) pour récupérer issuer, audience et JWKS.
- Tenant déjà provisionné (voir Provisionnement tenant) — les 5 rôles système sont créés automatiquement.
Accès
- Menu Platform → Identity & access
- URL :
\/admin/iam(sous-vues\/admin/iam/users,\/admin/iam/roles,\/admin/iam/audit)

Principes
- Identité ≠ autorisation — l'IdP prouve l'identité ; rôles, permissions et cost centers sont gérés dans Finoptika.
- Tenant-first — config d'auth, rôles et cost centers scopés au tenant (RLS PostgreSQL + prédicat
tenant_id). - Défense en profondeur — authN au décodage du token → authZ par permission sur chaque route → filtrage cost center dans le SQL → RLS en base.
Authentification multi-IdP
Mode (auth_mode) | Description |
|---|---|
jwt | Token HS256 signé par Finoptika (historique / dev). |
okta_oidc | Validation RS256 via JWKS de l'issuer Okta du tenant (issuer, audience, exp, signature). |
okta_saml | Fédération SAML ; après assertion, une session OIDC/JWT est émise (validation runtime identique à OIDC). |
Okta ne transporte aucune permission applicative : seuls l'identité (
sub,
Workflow — configurer Okta OIDC + rôles + cost centers
Objectif : un Tenant Admin part d'un tenant neuf et arrive à un SSO opérationnel avec des accès scopés.
Étape 1 — Récupérer les paramètres Okta
Dans Okta, créez une application OIDC et notez : issuer, audience (ou client_id), l'URL JWKS (.../v1/keys), le client_id.
Étape 2 — Déclarer l'IdP dans Finoptika
- Platform → Identity & access → onglet Identity Provider.
- Passez
auth_modeàokta_oidc. - Renseignez
oidc_issuer,oidc_audience,oidc_jwks_url,oidc_client_id. - Laissez
enforce_sso = falsependant la migration (fallback JWT local autorisé). - Enregistrez (l'API
PUT /platform/auth-configinvalide le cache d'auth).
Bascule progressive
Gardez enforce_sso=false le temps de valider la connexion SSO d'un premier utilisateur, puis passez-le à true pour n'accepter que le SSO.
Étape 3 — Créer les rôles (ou utiliser les rôles système)
Cinq rôles système sont livrés par tenant (non supprimables). Vous pouvez ajouter des rôles personnalisés :
- Onglet Roles → New role.
- Nom + sélection des permissions dans le catalogue (
/platform/permissions). - Optionnel : cost centers de rôle (hérités par ses membres).
Étape 4 — Créer les utilisateurs et affecter rôles + cost centers
- Onglet Users → New user : e-mail, nom, prénom, IdP (
okta_oidc), rôles, cost centers. - L'utilisateur se connecte via Okta ; ses droits sont résolus dans Finoptika.

Matrice des rôles système (RBAC)
Permissions au format domaine:ressource:action. Source canonique : backend/app/core/authorization/system_roles.py.
| Permission \ Rôle | Super Admin | Admin | Manager | Analyste | Std. User |
|---|---|---|---|---|---|
platform:tenant:read | ✅ | ✅ | ✅ | ✅ | ✅ |
platform:users:read | ✅ | ✅ | ✅ | — | — |
platform:users:write | ✅ | ✅ | — | — | — |
platform:roles:read / write | ✅ | ✅ | — | — | — |
platform:settings:read / write | ✅ | ✅ | — | — | — |
platform:cost-centers:read | ✅ | ✅ | ✅ | — | — |
platform:cost-centers:write | ✅ | ✅ | — | — | — |
platform:cost-centers:all (toutes données) | ✅ | — | — | — | — |
platform:audit:read | ✅ | ✅ | — | — | — |
billing:* | ✅ | ✅ | read | read | read |
allocation:* | ✅ | ✅ | read+write | read | — |
optimization:* | ✅ | ✅ | read+write+approve | read | read |
forecasting:* | ✅ | ✅ | read+write | read+write | read |
governance:* | ✅ | ✅ | read+write | read | — |
automation:* | ✅ | ✅ | read+write+approve+execute | — | — |
reporting:* | ✅ | ✅ | read+write+export | read+export | read |
copilot:query | ✅ | ✅ | ✅ | ✅ | ✅ |

Accès aux données par cost center
| Cas | Périmètre effectif |
|---|---|
Permission platform:cost-centers:all (ex. Super Admin) | Toutes les données du tenant |
| Utilisateur avec cost centers (directs et/ou de rôles) | Union des cost centers |
| Manager multi-CC | Données de tous ses cost centers |
| Aucune association | Aucune donnée de coût (ensemble vide) |
Le cost center d'une ligne est dérivé des tags (cost_center, cost-center, CostCenter…) ; les lignes non taguées vont dans unallocated, visibles uniquement des utilisateurs non restreints.
Rollup vs fact_cost
Un scope cost center actif force le modèle ligne à ligne (fact_cost) plutôt que le rollup mensuel (non découpé par cost center). Les clés de cache dashboard incluent le suffixe de périmètre → pas de fuite entre utilisateurs.
Audit
Chaque action sensible est journalisée : tenant_id, acteur, action, ressource, diff avant/après, request_id, méthode, chemin, horodatage.
| Événement | Action |
|---|---|
| Connexion | auth.login |
| Création/modif/suppression utilisateur | platform.user.create / update / delete |
| Activation / désactivation | platform.user.activate / deactivate |
| Attribution de rôles | platform.user.roles.update |
| Changement cost centers | platform.user.cost_centers.update |
| Modif permissions d'un rôle | platform.role.permissions.update |
| Changement config IdP | platform.auth_config.update |

Formules & définitions
- RBAC — contrôle d'accès par rôles ; default deny : toute permission non définie est refusée.
- JWKS — jeu de clés publiques de l'IdP servant à vérifier la signature RS256 des tokens Okta.
- enforce_sso —
true: seul le SSO est accepté ;false: fallback JWT local (migration).
Bonnes pratiques FinOps & sécurité
- 🔒 Principe du moindre privilège : partez des rôles système, créez des rôles custom au besoin.
- Restreignez par cost center dès que l'organisation dépasse quelques équipes.
- Migrez vers le SSO avec
enforce_sso=false, validez, puis verrouillez àtrue. - Révoquez immédiatement en désactivant l'utilisateur (
disabled) : le token encore valide est rejeté à la requête suivante.
Limitations & disclaimers
- Le masquage de menu côté frontend est un confort UX — l'autorité reste le backend (
require_permission). - Un rôle système n'est pas supprimable ; un rôle affecté à des utilisateurs ne peut être supprimé (409/400).
- Un ID de ressource d'un autre tenant renvoie 404 (anti-énumération), jamais 403.
Dépannage
| Symptôme | Cause probable | Résolution |
|---|---|---|
| SSO échoue, connexion impossible | JWKS/issuer/audience erronés | Vérifier oidc_* ; garder enforce_sso=false le temps de corriger |
| Utilisateur ne voit aucune donnée | Aucun cost center affecté | Affecter un cost center (ou cost-centers:all) |
| Entrée de menu absente | Permission manquante | Ajuster le rôle |
| Token valide mais 401 | Utilisateur disabled | Réactiver l'utilisateur |
| Suppression de rôle refusée | Rôle système ou encore affecté | Réaffecter les utilisateurs d'abord |