OpenFGA Provider
Manage OpenFGA stores, authorization models, and relationship tuples with Pulumi
The OpenFGA provider enables you to manage OpenFGA stores, authorization models, and relationship tuples with Pulumi. OpenFGA is a fine-grained, relationship-based authorization system inspired by Google Zanzibar. This provider is dynamically bridged from the Terraform OpenFGA Provider.
Installation
Install the OpenFGA provider package using your preferred package manager:
bun add pulumi-openfgapnpm add pulumi-openfgayarn add pulumi-openfganpm install pulumi-openfgaConfiguration
The provider supports two authentication modes: a pre-shared API token, or OAuth 2.0 client credentials.
API Token
pulumi config set openfga:apiUrl https://api.us1.fga.dev
pulumi config set openfga:apiToken YOUR_API_TOKEN --secretOr via environment variables:
export FGA_API_URL="https://api.us1.fga.dev"
export FGA_API_TOKEN="your-api-token"OAuth Client Credentials
pulumi config set openfga:apiUrl https://api.us1.fga.dev
pulumi config set openfga:clientId YOUR_CLIENT_ID
pulumi config set openfga:clientSecret YOUR_CLIENT_SECRET --secret
pulumi config set openfga:apiTokenIssuer https://fga.us.auth0.com
pulumi config set openfga:apiAudience https://api.us1.fga.dev/Equivalent environment variables: FGA_CLIENT_ID, FGA_CLIENT_SECRET, FGA_API_TOKEN_ISSUER, FGA_API_AUDIENCE, FGA_API_SCOPES.
Self-Hosted OpenFGA
For a self-hosted OpenFGA server, point apiUrl at the deployment and supply the matching auth credentials:
import * as openfga from "pulumi-openfga";
const provider = new openfga.Provider("self-hosted", {
apiUrl: "https://openfga.your-domain.com",
apiToken: config.requireSecret("openfgaToken"),
});
const store = new openfga.Store("app", { name: "app" }, { provider });Quick Start
import * as openfga from "pulumi-openfga";
// 1. Create a store.
const store = new openfga.Store("docs-app", {
name: "docs-app",
});
// 2. Define an authorization model from an OpenFGA DSL document.
const modelDoc = openfga.getAuthorizationModelDocumentOutput({
dsl: `
model
schema 1.1
type user
type document
relations
define viewer: [user]
define editor: [user]
`,
});
const model = new openfga.AuthorizationModel("docs-app-model", {
storeId: store.id,
modelJson: modelDoc.result,
});
// 3. Write a relationship tuple: alice can view document:readme.
const tuple = new openfga.RelationshipTuple("alice-can-view-readme", {
storeId: store.id,
authorizationModelId: model.id,
user: "user:alice",
relation: "viewer",
object: "document:readme",
});
export const storeId = store.id;
export const modelId = model.id;Key Resources
Store
A logical container for an authorization model and its relationship tuples.
const store = new openfga.Store("billing", {
name: "billing-service",
});Authorization Model
The schema describing the object types, relations, and rewrite rules. Use getAuthorizationModelDocument to author the model in DSL form and convert it to canonical JSON.
const model = new openfga.AuthorizationModel("billing-model", {
storeId: store.id,
modelJson: openfga.getAuthorizationModelDocumentOutput({
dsl: `
model
schema 1.1
type user
type group
relations
define member: [user]
type invoice
relations
define owner: [user]
define viewer: [user, group#member] or owner
`,
}).result,
});Relationship Tuple
A single fact in the form (user, relation, object). Optionally pinned to a specific authorization model.
const tuple = new openfga.RelationshipTuple("finance-can-view-invoice-42", {
storeId: store.id,
authorizationModelId: model.id,
user: "group:finance#member",
relation: "viewer",
object: "invoice:42",
});Read-Side Data Sources
The provider exposes data sources for offline checks against an authorization model without writing to the store: getCheckQuery, getListObjectsQuery, getListUsersQuery, plus lookups for stores, models, and tuples (getStore, getAuthorizationModel, getRelationshipTuple, etc.).
const canRead = openfga.getCheckQueryOutput({
storeId: store.id,
authorizationModelId: model.id,
tupleKey: {
user: "user:alice",
relation: "viewer",
object: "document:readme",
},
});
export const aliceCanRead = canRead.allowed;