WorkOS Docs Homepage
FGA
API referenceDashboardSign In
OverviewOverviewQuick StartQuick StartCore ConceptsResource TypesResource TypesResourcesResourcesRoles and PermissionsRoles and PermissionsAssignmentsAssignmentsHigh-Cardinality EntitiesHigh-Cardinality EntitiesAccess ControlAccess ChecksAccess ChecksResource DiscoveryResource DiscoveryIntegrationsAuthKit IntegrationAuthKit IntegrationStandalone IntegrationStandalone IntegrationIdP Role AssignmentIdP Role AssignmentMigration GuidesMigrate from OpenFGAMigrate from OpenFGAMigrate from SpiceDBMigrate from SpiceDBMigrate from Oso CloudMigrate from Oso Cloud
API Reference
API Reference
Events
Events
Integrations
Integrations
Migrate to WorkOS
Migrate to WorkOS
SDKs
SDKs

AuthKit Integration

Use FGA with AuthKit for role-aware sessions and seamless authorization.

On this page

  • Introduction
  • What’s in the session token
  • FGA and organization memberships
  • Two layers of authorization
  • Groups and group role assignments
    • Assigning a resource-scoped role to a group
    • How it integrates with access checks
    • Dynamic membership and assignments
    • Example: team-based resource access
  • When roles change

Introduction

FGA integrates with AuthKit to provide two layers of authorization. Organization-scoped roles and permissions are embedded directly in the session token for instant checks. Resource-scoped permissions are checked through the Authorization API.

What’s in the session token

When a user authenticates, their session token includes organization-scoped role information:

{
sub: "user_01HXYZ..."
org_id: "org_01HXYZ..."
role: "org_member"
permissions: ["org:view", "workspace:view", "project:view"]
}

Your application can check these permissions directly from the token without making API calls.

Why only organization-scoped roles?

Resource-scoped roles are intentionally excluded from the JWT:

  • Token size – Users might have roles on hundreds of resources, bloating the JWT beyond practical limits
  • Freshness – Resource assignments change frequently; stale tokens would cause mismatches
  • Performance – Larger tokens mean slower requests and verification

For resource-level permissions, use the Authorization API – it’s fast and always current.

FGA and organization memberships

FGA role assignments are scoped to organization memberships, not users directly. When you assign a role on a resource, the subject is the organization membership ID (om_...), which represents a user’s relationship to a specific organization.

This means FGA access checks require the organization membership ID rather than the user ID. You can include this ID in your JWT using JWT Templates:

{
"organization_membership_id": "{{ organization_membership.id }}"
}

This produces a token with the membership ID alongside the default claims:

{
"sub": "user_01HXYZ...",
"org_id": "org_01HXYZ...",
"role": "org_member",
"permissions": ["org:view", "workspace:view"],
...
"organization_membership_id": "om_01HXYZ..."
}

Your application can then extract the membership ID from the JWT and pass it to FGA access checks without needing an additional API call.

Two layers of authorization

Organization layer (JWT) – Check the token directly for org-wide features like navigation and settings. Instant, no API call needed.

Resource layer (API) – Call the Authorization API for specific resource access. Checks the full permission hierarchy including inheritance.

Can this user edit this project?
1. Quick check: Does the JWT include project:edit for all projects?
→ If yes, authorized (no API call)
2. Otherwise: Call the API for this specific project
→ Checks direct assignments and inheritance

Groups and group role assignments

Groups let you assign resource-scoped roles to a set of users at once. Instead of creating individual role assignments for each organization membership on a resource, assign the role to a group and let WorkOS propagate it to all members.

Assigning a resource-scoped role to a group

curl https://api.workos.com/authorization/groups/group_01HXYZ/role_assignments \
-X POST \
-H "Authorization: Bearer sk_example_123456789" \
-H "Content-Type: application/json" \
-d '{
"role_slug": "workspace-admin",
"resource_type_slug": "workspace",
"resource_external_id": "ws-engineering"
}'

Every member of the group gains the workspace-admin role on the Engineering workspace. Permissions propagate through the resource hierarchy just like direct assignments, so members also get inherited access to child resources (projects, apps, etc.).

How it integrates with access checks

Resource-scoped roles from group role assignments are checked through the Authorization API the same way as direct assignments. The access check evaluates all role sources for the organization membership, including group-sourced roles:

Alice's effective roles:
├─ org-member (direct assignment)
├─ workspace-admin on Workspace: Engineering (from "Engineering" group)
└─ project-viewer on Project: Sensitive (direct assignment)

A single check call returns the combined result across all sources. Your application does not need to distinguish between direct and group-sourced roles.

Dynamic membership and assignments

Roles update when group membership or group role assignments change:

  • Add member – the member gains all resource-scoped roles from the group’s assignments
  • Remove member – the member loses resource-scoped roles that came from that group
  • Add group role assignment – all current members of the group gain the role on the specified resource
  • Remove group role assignment – all members lose the role that came from that assignment

This makes groups ideal for managing team-level access. When an engineer joins the platform team, adding them to the “Platform” group grants access to all the team’s workspaces and projects without individual assignments.

Example: team-based resource access

Consider a project management application where you want all engineers to have the editor role on a shared workspace:

  1. Create a group named “Engineering” in the organization
  2. Add members to the group for each engineer’s organization membership
  3. Assign the role editor on the workspace resource to the group
# 1. Create the group
curl https://api.workos.com/organizations/org_01HXYZ/groups \
-X POST \
-H "Authorization: Bearer sk_example_123456789" \
-H "Content-Type: application/json" \
-d '{"name": "Engineering"}'
# 2. Add a member
curl https://api.workos.com/organizations/org_01HXYZ/groups/group_01HXYZ/organization-memberships \
-X POST \
-H "Authorization: Bearer sk_example_123456789" \
-H "Content-Type: application/json" \
-d '{"organization_membership_id": "om_01HXYZ"}'
# 3. Assign the role to the group
curl https://api.workos.com/authorization/groups/group_01HXYZ/role_assignments \
-X POST \
-H "Authorization: Bearer sk_example_123456789" \
-H "Content-Type: application/json" \
-d '{
"role_slug": "editor",
"resource_type_slug": "workspace",
"resource_external_id": "ws-engineering"
}'

Every member of the “Engineering” group now has the editor role on the Engineering workspace. When a new engineer joins, adding them to the group grants the role automatically.

For full details, see Group role assignments.

When roles change

API checks reflect changes immediately.

JWT permissions require a session refresh since the token was issued at sign-in. Resource roles aren’t in the JWT, so API checks always return current data.

Standalone Integration Use FGA with your own authentication system by managing users, organizations, and memberships via API
Up next
© WorkOS, Inc.
FeaturesAuthKitSingle Sign-OnDirectory SyncAdmin PortalFine-Grained Authorization
DevelopersDocumentationChangelogAPI Status
ResourcesBlogPodcastPricingSecuritySupport
CompanyAboutCustomersCareersLegalPrivacy
© WorkOS, Inc.