Authentication
Fabric resolves authentication in priority order. The first matching mechanism is used.
Authentication Chain
Section titled “Authentication Chain”1. API Key (Authorization: Bearer fab_*)
Section titled “1. API Key (Authorization: Bearer fab_*)”API keys are the primary authentication mechanism for service-to-service communication.
import { FabricClient } from "@fabric-platform/sdk";
const fabric = new FabricClient({ apiKey: "fab_your_api_key_here" });const me = await fabric.getMe();from fabric_platform import FabricClient
fabric = FabricClient(api_key="fab_your_api_key_here")me = fabric.get_me()use fabric_sdk::FabricClient;
let client = FabricClient::new("http://localhost:3001", "fab_your_api_key_here")?;let me = client.get_me().await?;curl -H 'Authorization: Bearer fab_your_api_key_here' \ http://localhost:3001/v1/meHow it works:
- Keys use the
fab_prefix for identification - The prefix is used for fast lookup, then the full key hash is verified
- Keys are hashed at rest (never stored in plaintext)
- Keys are org-scoped with configurable expiry and permission scopes
2. JWT (Authorization: Bearer <jwt>)
Section titled “2. JWT (Authorization: Bearer <jwt>)”JWT tokens issued by Supabase are validated using HS256.
const fabric = new FabricClient({ apiKey: "eyJhbGciOiJIUzI1NiIs...", // JWT token});fabric = FabricClient(api_key="eyJhbGciOiJIUzI1NiIs...") # JWT tokenlet client = FabricClient::new("http://localhost:3001", "eyJhbGciOiJIUzI1NiIs...")?;curl -H 'Authorization: Bearer eyJhbGciOiJIUzI1NiIs...' \ http://localhost:3001/v1/meConfigure with: JWT_SECRET=<supabase_jwt_secret>
3. Dev Header (X-Principal-Id: <uuid>)
Section titled “3. Dev Header (X-Principal-Id: <uuid>)”For development only. Allows setting an arbitrary principal ID without authentication.
const fabric = new FabricClient({ principalId: "550e8400-e29b-41d4-a716-446655440000",});fabric = FabricClient(principal_id="550e8400-e29b-41d4-a716-446655440000")let client = FabricClient::with_principal("http://localhost:3001", "550e8400-...")?;curl -H 'X-Principal-Id: 550e8400-e29b-41d4-a716-446655440000' \ http://localhost:3001/v1/meBlocked in production. Set FABRIC_ENV=production to disable.
4. Anonymous
Section titled “4. Anonymous”Requests without credentials are treated as anonymous. Only public endpoints are accessible:
GET /healthzGET /readyzGET /openapi.json
API Keys
Section titled “API Keys”Creating API Keys
Section titled “Creating API Keys”const key = await fabric.createApiKey({ name: "my-service-key", organizationId: "<org-id>", scopes: ["jobs:write", "providers:execute"],});console.log("Store this key:", key.raw_key); // shown only oncekey = fabric.create_api_key( name="my-service-key", organization_id="<org-id>", scopes=["jobs:write", "providers:execute"],)print("Store this key:", key["raw_key"]) # shown only oncelet key = client.create_api_key(serde_json::json!({ "name": "my-service-key", "organization_id": "<org-id>", "scopes": ["jobs:write", "providers:execute"]})).await?;println!("Store this key: {}", key.raw_key); // shown only oncecurl -X POST http://localhost:3001/v1/api-keys \ -H 'Authorization: Bearer fab_xxx' \ -H 'content-type: application/json' \ -d '{ "name": "my-service-key", "organization_id": "<org-id>", "scopes": ["jobs:write", "providers:execute"] }'The raw key (fab_...) is returned only once in the response. Store it securely.
Scopes
Section titled “Scopes”API keys can be scoped to specific permissions:
| Scope | Description |
|---|---|
jobs:write | Create and manage jobs |
jobs:read | Read job status and history |
providers:execute | Execute provider requests |
workflows:write | Create and manage workflows |
workflows:read | Read workflow definitions and runs |
| (empty list) | Full access (no restrictions) |
An empty scope list grants full access. Scopes are enforced at the route level.
Managing API Keys
Section titled “Managing API Keys”// List keysconst keys = await fabric.listApiKeys();
// Revoke a keyawait fabric.deleteApiKey("<key-id>");# List keyskeys = fabric.list_api_keys()
# Revoke a keyfabric.delete_api_key("<key-id>")// List keyslet keys = client.list_api_keys().await?;
// Revoke a keyclient.delete_api_key("<key-id>").await?;# List keyscurl -H 'Authorization: Bearer fab_xxx' \ http://localhost:3001/v1/api-keys
# Get key metadatacurl http://localhost:3001/v1/api-keys/<key-id>
# Disable a keycurl -X POST http://localhost:3001/v1/api-keys/<key-id>/disable
# Revoke (delete) a keycurl -X DELETE http://localhost:3001/v1/api-keys/<key-id>Authorization (RBAC)
Section titled “Authorization (RBAC)”After authentication, Fabric enforces role-based access control:
| Role | Level | Capabilities |
|---|---|---|
| Owner | Highest | Full access, can manage other owners |
| Admin | High | Manage teams, invitations, most resources |
| Member | Standard | Create and manage own resources |
| Viewer | Lowest | Read-only access |
Scope Resolution
Section titled “Scope Resolution”Roles are scoped to organizations and optionally to teams. The effective permission is the highest role across all scopes for a given principal.
Permission Checks
Section titled “Permission Checks”// Single checkconst allowed = await fabric.checkPermission({ resourceType: "organization", resourceId: "<org-id>", action: "team.create",});
// Batch checkconst results = await fabric.checkPermissions([ { action: "organization.read" }, { action: "team.create" },]);# Single checkallowed = fabric.check_permission( resource_type="organization", resource_id="<org-id>", action="team.create",)
# Batch checkresults = fabric.check_permissions([ {"action": "organization.read"}, {"action": "team.create"},])// Single checklet allowed = client.check_permission("organization", "<org-id>", "team.create").await?;
// Batch checklet results = client.check_permissions(vec![ ("organization.read", None), ("team.create", None),]).await?;# Single checkcurl -X POST http://localhost:3001/v1/authz/check \ -H 'Authorization: Bearer fab_xxx' \ -H 'content-type: application/json' \ -d '{"resource_type":"organization","resource_id":"<org-id>","action":"team.create"}'
# Batch checkcurl -X POST http://localhost:3001/v1/authz/check-batch \ -H 'Authorization: Bearer fab_xxx' \ -H 'content-type: application/json' \ -d '{"checks":[{"action":"organization.read"},{"action":"team.create"}]}'Clients must not compute permissions themselves. Fabric is the enforcement authority.