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

LayerGranularity
RoleCoarse: ADMIN, USER
PermissionFine: post:create, user:delete
Resource scopePer-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

PatternExample
Owner checkpost.authorId === user.id
MembershiporgId in user.orgs
ACL listResource 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

LibraryDetail
CASLIsomorphic JS abilities
graphql-shieldPermission tree by type/field
Cerbos / OpenFGAExternal policy decision points

8. Handling Unauthorized Access

ResponseWhen
Throw FORBIDDENSensitive operation
Filter resultList queries — return only allowed items
Mask fieldReturn null on protected scalar field

9. Hiding Unauthorized Fields

Example: Conditional null

User: {
  ssn: (u, _, ctx) => (ctx.user?.role === "ADMIN" ? u.ssn : null)
}

10. Implementing Row-level Security

ApproachDetail
DB-level RLSPostgres policies enforce per session role
App-level filterAppend WHERE ownerId = $userId
Tenant isolationtenantId in every query, indexed