Resource-Level Authorization

Role checks alone are often insufficient. Many applications need to determine whether the authenticated user can access a specific resource.

Consider:

mutation UpdateProfile($id: ID!, $input: UpdateProfileInput!) {
  updateProfile(id: $id, input: $input) {
    id
    name
  }
}

Suppose the authenticated user is user-10, but the requested profile belongs to user-20.

A simple CUSTOMER role check would not be enough. The server must verify ownership:

const profile = await profileService.findById(id);

if (profile.ownerId !== context.user.id) {
  throw new Error("Forbidden");
}

This is resource-level authorization.

A more scalable policy might be:

authorization.canUpdateProfile(context.user, profile)

The policy can then consider multiple conditions:

  • Is the user the owner?
  • Is the user an administrator?
  • Is the account active?
  • Is the resource locked?
  • Does the user's organization own the resource?

This type of authorization is especially important in multi-tenant applications where users from one organization must never access another organization's data.

Resource-Level Authorization
Key Takeaways
  • Authentication alone does not protect individual resources.
  • Resource ownership can be part of an authorization policy.
  • Multi-tenant systems require strong tenant isolation.
  • Authorization logic should be centralized enough to remain consistent.
Knowledge Check

Why is a role check alone insufficient for a customer updating a profile?