Ask whether a user can perform an action on a resource.
Access checks answer: “Can this user do this action on this resource?”
FGA looks at all the ways the user might have access – a role assigned directly on the resource, a role on a parent resource that grants inherited permissions, or an organization-level role. If any grant the permission, the user is authorized.
Alice wants to deploy an app. Here’s her access:
Org: Acme (Alice: org-member) └─ Workspace: Engineering (Alice: workspace_admin) └─ Project: Web └─ App: Frontend
Can Alice deploy App: Frontend? Yes – her workspace-admin role includes app:deploy, which flows down to all apps in that workspace.
JWT (fast) – For org-wide permissions, check the token directly. No API call needed. Good for navigation and feature flags.
API (precise) – For resource-specific permissions, call the authorization API:
curl https://api.workos.com/authorization/organization_memberships/om_01HXYZ/check \ -X POST \ -H "Authorization: Bearer sk_example_123456789" \ -H "Content-Type: application/json" \ -d '{ "permission_slug": "project:edit", "resource_id": "authz_resource_01HXYZ" }'
Response:
{ "authorized": true }
For best performance, check the JWT first for org-wide permissions, then fall back to the API for resource-specific checks.
Here’s how you might protect an API endpoint that updates a project. Before performing the operation, check whether the user has the proj:edit permission on the specific project they’re trying to modify:
import { WorkOS } from '@workos-inc/node'; const workos = new WorkOS(process.env.WORKOS_API_KEY); app.patch('/projects/:projectId', async (req, res) => { const { organizationMembershipId } = req.user; const { projectId } = req.params; // Check if the user can edit this project const { authorized } = await workos.authorization.check({ organizationMembershipId, permissionSlug: 'proj:edit', resourceExternalId: projectId, resourceTypeSlug: 'project', }); if (!authorized) { return res.status(403).json({ error: 'Forbidden' }); } // User is authorized — proceed with the update const project = await updateProject(projectId, req.body); return res.json(project); });
The check() method evaluates all possible sources of access – direct assignments on the project, inherited permissions from a parent workspace, and organization-level roles. You don’t need to check each level yourself.
Protecting actions – Before a user performs an action, check if they’re allowed. Return 403 if not.
Showing or hiding UI – Check permissions before rendering to show edit buttons, delete options, or admin settings only to authorized users.
Filtering lists – Only show resources the user can access in navigation and search results.