Skip to Content

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 :

  1. 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.
  2. Tuples de Relation — sont les faits du système. Chaque tuple affirme qu’un sujet a une relation avec un objet.
  3. 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 owner

Types de règles de réécriture :

RègleSyntaxeDescription
Directe (this)[user]Le sujet doit être assigné directement via un tuple
UnionA or BLe sujet doit satisfaire au moins une des relations
IntersectionA and BLe sujet doit satisfaire toutes les relations
ExclusionA but not BLe sujet doit satisfaire A et ne pas satisfaire B
Userset calculéownerHérite d’une autre relation sur le même objet
Tuple-to-usersetgroup#memberSuit 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

GET/api/fga/modelsRequires: view:fga_models

Liste 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ètreTypeDescription
pageintegerNuméro de page (défaut : 1)
limitintegerÉ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

POST/api/fga/modelsRequires: manage:fga_models

Cré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

CodeHTTPDescription
DSL_PARSE_ERROR400La syntaxe DSL n’est pas valide. Le champ message inclut le numéro de ligne et la description de l’erreur
DSL_VALIDATION_ERROR400Le DSL est syntaxiquement valide mais fait référence à des types ou relations non définis ou contient des cycles
VALIDATION_ERROR400Champs obligatoires manquants (name ou dsl)

Récupérer un Modèle

GET/api/fga/models/[id]Requires: view:fga_models

Ré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

CodeHTTPDescription
NOT_FOUND404Le modèle n’existe pas ou appartient à un tenant différent

Mettre à Jour un Modèle

PUT/api/fga/models/[id]Requires: manage:fga_models

Met à 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

CodeHTTPDescription
NOT_FOUND404Le modèle n’existe pas
DSL_PARSE_ERROR400Le DSL mis à jour contient des erreurs de syntaxe
DSL_VALIDATION_ERROR400Le DSL mis à jour fait référence à des types ou relations non définis

Supprimer un Modèle

DELETE/api/fga/models/[id]Requires: manage:fga_models

Supprime 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

CodeHTTPDescription
NOT_FOUND404Le modèle n’existe pas
MODEL_IS_ACTIVE400Impossible de supprimer le modèle actuellement actif

Activer un Modèle

POST/api/fga/models/[id]/activateRequires: manage:fga_models

Dé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

CodeHTTPDescription
NOT_FOUND404Le modèle n’existe pas
ALREADY_ACTIVE400Ce 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

GET/api/fga/tuplesRequires: view:fga_tuples

Liste 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ètreTypeDescription
objectTypestringFiltre par type d’objet (ex. document)
objectIdstringFiltre par ID objet
relationstringFiltre par nom de relation
subjectTypestringFiltre par type sujet
subjectIdstringFiltre par ID sujet
pageintegerNuméro de page (défaut : 1)
limitintegerÉléments par page (défaut : 20, max : 100)

Écrire un Tuple

POST/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

CodeHTTPDescription
NO_ACTIVE_MODEL400Aucun modèle d’autorisation actif pour ce tenant
INVALID_TYPE400Le type d’objet n’existe pas dans le modèle actif
INVALID_RELATION400La relation n’existe pas sur ce type d’objet dans le modèle actif
INVALID_SUBJECT_TYPE400La relation n’accepte pas ce type de sujet comme cible valide
TUPLE_EXISTS409Un tuple identique existe déjà
VALIDATION_ERROR400Champs obligatoires manquants

Supprimer un Tuple

DELETE/api/fga/tuplesRequires: manage:fga_tuples

Supprime un tuple de relation spécifique. Retourne succès même si le tuple n’existe pas (suppression idempotente).

Écriture/Suppression Bulk de Tuples

POST/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

POST/api/fga/checkRequires: debug:fga

Vé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 }
ChampTypeObligatoireDescription
objectTypestringOuiLe type de l’objet cible
objectIdstringOuiL’ID de l’objet cible
relationstringOuiLa relation à vérifier
subjectTypestringOuiLe type du sujet (typiquement user)
subjectIdstringOuiL’ID du sujet
explainbooleanNonSi 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

CodeHTTPDescription
NO_ACTIVE_MODEL400Aucun modèle d’autorisation actif
INVALID_TYPE400Le type d’objet n’existe pas dans le modèle actif
INVALID_RELATION400La relation n’existe pas sur le type spécifié
MAX_DEPTH_EXCEEDED400L’évaluation a dépassé la profondeur maximale de récursion de 25
VALIDATION_ERROR400Champs obligatoires manquants

Expand

POST/api/fga/expandRequires: debug:fga

Dé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

POST/api/fga/list-objectsRequires: debug:fga

Liste 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

PermissionDescription
view:fga_modelsVisualiser les modèles d’autorisation et leurs définitions DSL
manage:fga_modelsCréer, mettre à jour, supprimer et activer les modèles d’autorisation
view:fga_tuplesLister et lire les tuples de relation
manage:fga_tuplesÉcrire et supprimer des tuples de relation (individuels et bulk)
debug:fgaExé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 editor

Pages Associées