hectoday
DocsCoursesChangelog GitHub
DocsCoursesChangelog GitHub

Access Required

Enter your access code to view courses.

Invalid code

← All courses Authorization with @hectoday/http

Beyond Authentication

  • Authentication vs. Authorization
  • Project Setup

Role-Based Access Control (RBAC)

  • Roles and What They Mean
  • Checking Roles in Route Handlers
  • Role Hierarchy

Permission-Based Access Control

  • From Roles to Permissions
  • Checking Permissions
  • Custom Permissions

Organization Scoping

  • Multi-Tenancy
  • Switching Organizations
  • Inviting Members

API Keys and Scoping

  • API Keys
  • Scoped API Keys

Putting It All Together

  • Policy Functions
  • Audit Logging
  • Authorization Checklist
  • Capstone: Multi-Tenant Notes API

Authentication vs. Authorization

Two different questions

Authentication asks: who are you? The user provides credentials (password, OAuth token, API key), and the server verifies their identity. The auth course covered this thoroughly.

Authorization asks: what can you do? The user is authenticated — the server knows they are Alice. But can Alice delete this note? Can she invite a member to this organization? Can she access the billing page?

These are separate concerns. A user can be fully authenticated and still not authorized to perform a specific action.

Why a role field is not enough

The auth course added a role field to the User type: "user" or "admin". The security course checked it with requireAdmin. This works for a simple app with two permission levels, but it breaks down quickly.

Consider a team collaboration app. Alice is an admin of her team but a regular member of another team. Bob can edit documents but not delete them. Carol can view reports but not create them. A single role field on the user cannot express any of this.

The problems with a single role field:

It is global. Alice’s role applies everywhere. She cannot be an admin in one context and a viewer in another.

It is coarse. “Admin” and “user” are the only options. There is no way to express “can edit but not delete” or “can read notes but not billing.”

It is static. The role is set when the account is created. Changing it requires an admin or a database update. There is no self-service role management.

What we will build

This course replaces the single role field with a layered authorization system:

Roles (Section 2): Owner, editor, viewer — defined per-organization, not per-user. Alice can be an owner in one org and a viewer in another.

Permissions (Section 3): Fine-grained actions like notes:create, notes:delete, members:invite. Each role maps to a set of permissions. Custom roles with custom permission sets.

Organization scoping (Section 4): Every resource belongs to an organization. Every query is scoped to the user’s active organization. Multi-tenancy.

API keys (Section 5): Non-interactive authentication with scoped permissions. A key that can only read notes in a specific organization.

Policy functions (Section 6): A single can(user, action, resource) function that encapsulates all authorization logic. Clean, testable, and centralized.

By the end, you will have a production-grade authorization system that handles everything from “can this user view this note?” to “can this API key create notes in this organization?”

A user is authenticated but receives a 403 Forbidden response. What does this mean?

Why does a single 'role' field on the User type fail for team-based apps?

Project Setup →

© 2026 hectoday. All rights reserved.