API FGA (Fine-Grained Authorization)
Le moteur d’Autorisation Fine-Grained fournit un contrôle d’accès basé sur les relations (ReBAC) style Zanzibar. Il étend le niveau RBAC avec une autorisation au niveau objet : au lieu de “l’utilisateur a la permission X globalement,” FGA répond “Alice a la relation viewer sur le document readme ?”
Le système repose sur trois concepts :
- Modèles d’Autorisation — définissent les types d’objets, leurs relations et les règles de réécriture en utilisant un DSL compatible OpenFGA.
- Tuples de Relation — sont les faits du système. Chaque tuple affirme qu’un sujet a une relation avec un objet.
- Requêtes d’Autorisation (
check,expand,list-objects) — évaluent les tuples par rapport aux règles de réécriture du modèle pour répondre aux questions d’accès.
Tous les endpoints FGA nécessitent le header x-tenant et un access token valide.
DSL du Modèle d’Autorisation
Le DSL définit les types et leurs relations. Chaque relation peut avoir des règles de réécriture qui composent l’accès depuis d’autres relations ou relations indirectes.
type user
type group
relations
define member: [user]
type document
relations
define owner: [user]
define editor: [user, group#member]
define viewer: [user, group#member] or editor or ownerTypes de règles de réécriture :
| Règle | Syntaxe | Description |
|---|---|---|
Directe (this) | [user] | Le sujet doit être assigné directement via un tuple |
| Union | A or B | Le sujet doit satisfaire au moins une des relations |
| Intersection | A and B | Le sujet doit satisfaire toutes les relations |
| Exclusion | A but not B | Le sujet doit satisfaire A et ne pas satisfaire B |
| Userset calculé | owner | Hérite d’une autre relation sur le même objet |
| Tuple-to-userset | group#member | Suit une relation sur un objet lié (indirect) |
Le moteur FGA utilise l’évaluation récursive avec une profondeur maximale de 25 et la détection des cycles via un ensemble de nœuds visités. Cela prévient les boucles infinies dans les définitions de relations circulaires.
Modèles d’Autorisation
Lister les Modèles
/api/fga/modelsRequires: view:fga_modelsListe tous les modèles d’autorisation pour le tenant, triés par version décroissante. Un seul modèle peut être actif à la fois. Le modèle actif est utilisé pour toute la validation des tuples et les requêtes d’autorisation.
Paramètres de query
| Paramètre | Type | Description |
|---|---|---|
page | integer | Numéro de page (défaut : 1) |
limit | integer | Éléments par page (défaut : 20) |
Réponse de succès
{
"ok": true,
"data": [
{
"id": "model_abc123",
"name": "Modèle d'Autorisation SaaS",
"version": 3,
"isActive": true,
"createdAt": "2025-02-10T00:00:00Z",
"updatedAt": "2025-02-12T08:30:00Z"
},
{
"id": "model_def456",
"name": "Modèle d'Autorisation SaaS",
"version": 2,
"isActive": false,
"createdAt": "2025-02-05T00:00:00Z",
"updatedAt": "2025-02-05T00:00:00Z"
}
]
}Créer un Modèle
/api/fga/modelsRequires: manage:fga_modelsCrée un nouveau modèle d’autorisation en fournissant un nom et une définition DSL. Le DSL est analysé ligne par ligne et validé avant le stockage. Si le DSL contient des erreurs de syntaxe ou des références à des types ou relations non définis, la requête est rejetée avec un message d’erreur détaillé incluant le numéro de ligne.
Corps de la requête
{
"name": "Modèle Accès Documents",
"dsl": "type user\n\ntype group\n relations\n define member: [user]\n\ntype document\n relations\n define owner: [user]\n define editor: [user, group#member]\n define viewer: [user, group#member] or editor or owner\n"
}Réponse de succès
{
"ok": true,
"data": {
"id": "model_ghi789",
"name": "Modèle Accès Documents",
"version": 1,
"isActive": false,
"dsl": "type user\n\ntype group\n relations\n define member: [user]\n\ntype document\n relations\n define owner: [user]\n define editor: [user, group#member]\n define viewer: [user, group#member] or editor or owner\n",
"schema": {
"typeDefinitions": [
{ "type": "user", "relations": {} },
{ "type": "group", "relations": { "member": { "this": {} } } },
{
"type": "document",
"relations": {
"owner": { "this": {} },
"editor": { "this": {} },
"viewer": {
"union": {
"children": [
{ "this": {} },
{ "computedUserset": { "relation": "editor" } },
{ "computedUserset": { "relation": "owner" } }
]
}
}
}
}
]
},
"createdAt": "2025-02-18T10:00:00Z"
}
}Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
DSL_PARSE_ERROR | 400 | La syntaxe DSL n’est pas valide. Le champ message inclut le numéro de ligne et la description de l’erreur |
DSL_VALIDATION_ERROR | 400 | Le DSL est syntaxiquement valide mais fait référence à des types ou relations non définis ou contient des cycles |
VALIDATION_ERROR | 400 | Champs obligatoires manquants (name ou dsl) |
Récupérer un Modèle
/api/fga/models/[id]Requires: view:fga_modelsRécupère un modèle d’autorisation spécifique par son ID. Retourne le modèle complet incluant le texte DSL brut et l’objet schéma analysé.
Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Le modèle n’existe pas ou appartient à un tenant différent |
Mettre à Jour un Modèle
/api/fga/models/[id]Requires: manage:fga_modelsMet à jour le nom ou la définition DSL d’un modèle. Quand le DSL est mis à jour, il est ré-analysé et re-validé. La version du modèle n’est pas incrémentée automatiquement lors d’une mise à jour — crée un nouveau modèle pour les modifications avec versioning.
Corps de la requête
{
"name": "Modèle Accès Documents v2",
"dsl": "type user\n\ntype document\n relations\n define owner: [user]\n define viewer: [user] or owner\n"
}Les champs name et dsl sont optionnels. Seuls les champs fournis sont mis à jour.
Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Le modèle n’existe pas |
DSL_PARSE_ERROR | 400 | Le DSL mis à jour contient des erreurs de syntaxe |
DSL_VALIDATION_ERROR | 400 | Le DSL mis à jour fait référence à des types ou relations non définis |
Supprimer un Modèle
/api/fga/models/[id]Requires: manage:fga_modelsSupprime un modèle d’autorisation. Les modèles actifs ne peuvent pas être supprimés — il faut d’abord activer un modèle différent.
La suppression d’un modèle ne supprime pas automatiquement les tuples écrits avec ce modèle. Les tuples orphelins sont ignorés par les requêtes d’autorisation mais restent dans la base de données jusqu’au nettoyage manuel.
Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Le modèle n’existe pas |
MODEL_IS_ACTIVE | 400 | Impossible de supprimer le modèle actuellement actif |
Activer un Modèle
/api/fga/models/[id]/activateRequires: manage:fga_modelsDéfinit un modèle comme modèle d’autorisation actif pour le tenant. Tout modèle précédemment
actif est automatiquement désactivé. Toutes les requêtes check, expand et list-objects
suivantes utiliseront les règles de réécriture du modèle nouvellement activé. Le cache du
modèle est invalidé immédiatement.
Réponse de succès
{
"ok": true,
"data": {
"activated": true,
"modelId": "model_ghi789"
}
}Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
NOT_FOUND | 404 | Le modèle n’existe pas |
ALREADY_ACTIVE | 400 | Ce modèle est déjà le modèle actif |
Le moteur FGA met en cache le modèle actif en mémoire avec un TTL de 5 minutes. Après l’activation d’un nouveau modèle, les requêtes peuvent utiliser l’ancien modèle pendant jusqu’à 5 minutes sur d’autres instances serveur.
Tuples de Relation
Les tuples sont les faits d’autorisation. Chaque tuple affirme qu’un sujet a une relation avec un objet.
Format tuple : typeObjet:idObjet#relation@typeSujet:idSujet
Exemples :
document:readme#viewer@user:alice— Alice est un viewer du document “readme”document:readme#editor@group:engineering#member— les membres du groupe “engineering” sont editors du document “readme”folder:projects#owner@user:bob— Bob est le propriétaire du dossier “projects”
Lister les Tuples
/api/fga/tuplesRequires: view:fga_tuplesListe les tuples de relation avec filtrage optionnel. Il est recommandé d’utiliser au moins un paramètre de filtre pour éviter de retourner tout le tuple store. Supporte la pagination.
Paramètres de query
| Paramètre | Type | Description |
|---|---|---|
objectType | string | Filtre par type d’objet (ex. document) |
objectId | string | Filtre par ID objet |
relation | string | Filtre par nom de relation |
subjectType | string | Filtre par type sujet |
subjectId | string | Filtre par ID sujet |
page | integer | Numéro de page (défaut : 1) |
limit | integer | Éléments par page (défaut : 20, max : 100) |
Écrire un Tuple
/api/fga/tuplesRequires: manage:fga_tuplesÉcrit un seul tuple de relation. Le tuple est validé par rapport au modèle d’autorisation actif avant le stockage.
Corps de la requête — assignation directe utilisateur
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}Corps de la requête — subject set (indirect / appartenance au groupe)
{
"objectType": "document",
"objectId": "readme",
"relation": "editor",
"subjectType": "group",
"subjectId": "engineering",
"subjectRelation": "member"
}Cela signifie : “toutes les entités qui ont la relation member sur group:engineering sont également editor sur document:readme.”
Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Aucun modèle d’autorisation actif pour ce tenant |
INVALID_TYPE | 400 | Le type d’objet n’existe pas dans le modèle actif |
INVALID_RELATION | 400 | La relation n’existe pas sur ce type d’objet dans le modèle actif |
INVALID_SUBJECT_TYPE | 400 | La relation n’accepte pas ce type de sujet comme cible valide |
TUPLE_EXISTS | 409 | Un tuple identique existe déjà |
VALIDATION_ERROR | 400 | Champs obligatoires manquants |
Supprimer un Tuple
/api/fga/tuplesRequires: manage:fga_tuplesSupprime un tuple de relation spécifique. Retourne succès même si le tuple n’existe pas (suppression idempotente).
Écriture/Suppression Bulk de Tuples
/api/fga/tuples/bulkRequires: manage:fga_tuplesÉcrit et/ou supprime plusieurs tuples en une seule requête atomique. Toutes les opérations du batch sont validées par rapport au modèle actif avant toute écriture. Si même un seul tuple échoue à la validation, l’intégralité du batch est rejeté.
Corps de la requête
{
"writes": [
{
"objectType": "document",
"objectId": "api-spec",
"relation": "owner",
"subjectType": "user",
"subjectId": "bob"
}
],
"deletes": [
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}
]
}Les champs writes et deletes sont tous deux optionnels, mais au moins un doit être présent. Chaque tableau peut contenir jusqu’à 100 tuples.
Réponse de succès
{
"ok": true,
"data": {
"written": 2,
"deleted": 1
}
}Les opérations bulk sont atomiques. Si le tuple #47 sur 100 échoue à la validation, aucun des 100 tuples n’est écrit ni supprimé.
Requêtes d’Autorisation
Check
/api/fga/checkRequires: debug:fgaVérifie si un sujet a une relation spécifique avec un objet. Le moteur évalue les règles de réécriture du modèle actif de manière récursive. Retourne optionnellement un arbre de résolution montrant exactement comment la décision a été prise.
Corps de la requête
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice",
"explain": false
}| Champ | Type | Obligatoire | Description |
|---|---|---|---|
objectType | string | Oui | Le type de l’objet cible |
objectId | string | Oui | L’ID de l’objet cible |
relation | string | Oui | La relation à vérifier |
subjectType | string | Oui | Le type du sujet (typiquement user) |
subjectId | string | Oui | L’ID du sujet |
explain | boolean | Non | Si true, inclut l’arbre de résolution (défaut : false) |
Réponse de succès (sans explain)
{
"ok": true,
"data": {
"allowed": true
}
}Réponse de succès (avec explain)
{
"ok": true,
"data": {
"allowed": true,
"resolution": {
"type": "union",
"relation": "viewer",
"result": true,
"children": [
{ "type": "this", "relation": "viewer", "result": false },
{ "type": "computedUserset", "relation": "editor", "result": false },
{
"type": "computedUserset",
"relation": "owner",
"result": true,
"children": [
{
"type": "this",
"relation": "owner",
"result": true,
"tupleFound": "document:readme#owner@user:alice"
}
]
}
]
}
}
}Codes d’erreur
| Code | HTTP | Description |
|---|---|---|
NO_ACTIVE_MODEL | 400 | Aucun modèle d’autorisation actif |
INVALID_TYPE | 400 | Le type d’objet n’existe pas dans le modèle actif |
INVALID_RELATION | 400 | La relation n’existe pas sur le type spécifié |
MAX_DEPTH_EXCEEDED | 400 | L’évaluation a dépassé la profondeur maximale de récursion de 25 |
VALIDATION_ERROR | 400 | Champs obligatoires manquants |
Expand
/api/fga/expandRequires: debug:fgaDéveloppe une relation sur un objet pour découvrir tous les sujets qui ont cette relation. Retourne une structure arborescente qui suit les règles de réécriture.
Corps de la requête
{
"objectType": "document",
"objectId": "readme",
"relation": "viewer"
}List Objects
/api/fga/list-objectsRequires: debug:fgaListe tous les objets d’un type donné auxquels un sujet peut accéder via une relation spécifique. Effectue une recherche inverse à travers le tuple store et les règles de réécriture. Utile pour construire des vues filtrées comme “montre-moi tous les documents que cet utilisateur peut voir.”
Corps de la requête
{
"objectType": "document",
"relation": "viewer",
"subjectType": "user",
"subjectId": "alice"
}Réponse de succès
{
"ok": true,
"data": {
"objectIds": ["readme", "api-spec", "changelog", "roadmap"],
"total": 4
}
}La requête list-objects peut être coûteuse pour les tuple stores de grande taille. Utilise la pagination et envisage de mettre en cache les résultats pour les patterns fréquemment accédés.
Référence des Permissions
| Permission | Description |
|---|---|
view:fga_models | Visualiser les modèles d’autorisation et leurs définitions DSL |
manage:fga_models | Créer, mettre à jour, supprimer et activer les modèles d’autorisation |
view:fga_tuples | Lister et lire les tuples de relation |
manage:fga_tuples | Écrire et supprimer des tuples de relation (individuels et bulk) |
debug:fga | Exécuter les requêtes check, expand et list-objects |
Exemple Complet
Cet exemple démontre un pattern d’autorisation courant : un système d’accès aux documents basé sur des équipes.
Étape 1 : Créer le modèle
POST /api/fga/models
{
"name": "Documents d'Équipe",
"dsl": "type user\n\ntype team\n relations\n define member: [user]\n define admin: [user]\n\ntype document\n relations\n define owner: [user]\n define team: [team]\n define editor: [user, team#admin]\n define viewer: [user, team#member] or editor or owner\n"
}Étape 2 : Activer le modèle
POST /api/fga/models/{modelId}/activateÉtape 3 : Écrire les tuples
POST /api/fga/tuples/bulk
{
"writes": [
{ "objectType": "team", "objectId": "engineering", "relation": "member", "subjectType": "user", "subjectId": "alice" },
{ "objectType": "team", "objectId": "engineering", "relation": "admin", "subjectType": "user", "subjectId": "alice" },
{ "objectType": "document", "objectId": "arch-doc", "relation": "editor", "subjectType": "team", "subjectId": "engineering", "subjectRelation": "admin" },
{ "objectType": "document", "objectId": "arch-doc", "relation": "viewer", "subjectType": "team", "subjectId": "engineering", "subjectRelation": "member" }
]
}Étape 4 : Vérifier l’accès
POST /api/fga/check
{
"objectType": "document",
"objectId": "arch-doc",
"relation": "editor",
"subjectType": "user",
"subjectId": "alice",
"explain": true
}
// Résultat : { "allowed": true } — Alice est admin de l'équipe engineering, ce qui accorde editorPages Associées
- Modèle FGA / Zanzibar — Comment fonctionnent le modèle d’autorisation et les règles de réécriture
- Guide Autorisation Fine-Grained — Guide pratique d’implémentation FGA
- FGA Débogueur — Teste les vérifications et inspecte les arbres de résolution depuis la Console
- API Rôles et Permissions — Endpoints RBAC qui complètent FGA