Implementing Authorization
1. Implementing Role-based Access
Example: RBAC check
function requireRole(ctx, ...roles) {
const u = requireAuth(ctx);
if (!roles.includes(u.role)) throw new GraphQLError("Forbidden", { extensions: { code: "FORBIDDEN" } });
return u;
}
2. Implementing Permission-based Access
| Layer | Granularity |
|---|---|
| Role | Coarse: ADMIN, USER |
| Permission | Fine: post:create, user:delete |
| Resource scope | Per-org/team/project |
3. Creating Auth Directives
Example: Permission directive
directive @hasPermission(permission: String!) on FIELD_DEFINITION
type Mutation {
deleteUser(id: ID!): Boolean! @hasPermission(permission: "user:delete")
}
4. Checking Field-level Permissions
Example: Field-level check
User: {
email: (parent, _, ctx) => {
if (ctx.user?.id === parent.id || ctx.user?.role === "ADMIN") return parent.email;
return null; // hide
}
}
5. Checking Object-level Permissions
| Pattern | Example |
|---|---|
| Owner check | post.authorId === user.id |
| Membership | orgId in user.orgs |
| ACL list | Resource has explicit allowed users |
6. Using Context for Permissions
Example: Permission helper on context
context: ({ req }) => {
const user = await auth(req);
return {
user,
can: (permission, resource) => checkAbility(user, permission, resource)
};
}
7. Implementing Resource Authorization
| Library | Detail |
|---|---|
| CASL | Isomorphic JS abilities |
| graphql-shield | Permission tree by type/field |
| Cerbos / OpenFGA | External policy decision points |
8. Handling Unauthorized Access
| Response | When |
|---|---|
| Throw FORBIDDEN | Sensitive operation |
| Filter result | List queries — return only allowed items |
| Mask field | Return null on protected scalar field |
9. Hiding Unauthorized Fields
10. Implementing Row-level Security
| Approach | Detail |
|---|---|
| DB-level RLS | Postgres policies enforce per session role |
| App-level filter | Append WHERE ownerId = $userId |
| Tenant isolation | tenantId in every query, indexed |