> ## Documentation Index
> Fetch the complete documentation index at: https://system.muzemus.online/llms.txt
> Use this file to discover all available pages before exploring further.

# Authorization

> Capability-based authorization system using roles, permissions, and scope guards

MUZE uses a **three-layer authorization system**: session validation, capability-based permission checking, and store-level scope enforcement.

## Authorization Stack

```mermaid theme={null}
flowchart TD
    A[Request] --> B[SessionGuard]
    B -->|"No session"| X[401 Unauthorized]
    B -->|"Valid session"| C[PermissionsGuard]
    C -->|"No permission"| Y[403 Forbidden]
    C -->|"Granted"| D[ScopeGuard]
    D -->|"Out of scope"| Z[403 Forbidden]
    D -->|"In scope"| E[Controller Handler]
```

## Layer 1: Session Validation (SessionGuard)

Validates that the request carries a valid session cookie. No route-level override; this runs on every request.

* **File:** `backend/src/auth/session.guard.ts`
* **Behavior:** Calls `authService.getSession(headers)`. Returns 401 if no session.
* **Scope:** Global, applied to all routes

## Layer 2: Capability-based permissions (PermissionsGuard)

Routes declare the permissions they require. The guard resolves the user's roles and checks whether they carry every required permission.

* **File:** `backend/src/auth/permissions.guard.ts`
* **Behavior:** Reads `@Permissions(...)` or `@Roles(...)` metadata. Queries `UserRole` table. Checks AND semantics for `@Permissions`, OR semantics for `@Roles`.
* **Scope:** Global, but only enforced when the route has `@Permissions()` or `@Roles()` metadata. Routes without these decorators pass through.

### @Permissions vs @Roles

```typescript theme={null}
// AND semantics: user must hold EVERY listed permission
@Permissions(Permission.EMPLOYEES_MANAGE, Permission.EMPLOYEES_IMPORT)
@Post('import')
async importEmployees() { ... }

// OR semantics: user must hold ANY listed role (backwards compatibility)
@Roles(Role.HR, Role.MUZE_ADMIN)
@Get('reports')
async getReports() { ... }
```

`@Permissions(...)` is the preferred approach. `@Roles(...)` is retained for backwards compatibility only.

### What PermissionsGuard attaches to the request

After successful authorization, the guard attaches three properties:

| Property              | Type              | Purpose                                                                                           |
| --------------------- | ----------------- | ------------------------------------------------------------------------------------------------- |
| `request.userRoles`   | `UserRoleScope[]` | Array of `{ role, storeId?, regionId?, clientId? }`: used by ScopeGuard and service-layer scoping |
| `request.permissions` | `Permission[]`    | Flat array of all permissions granted by the user's roles                                         |
| `request.isAdmin`     | `boolean`         | `true` if the user holds MUZE\_ADMIN or SUPER\_ADMIN                                              |

## Layer 3: Store-Level Scope Enforcement (ScopeGuard)

Enforces that a scoped user (Store Manager, HR) can only access data within their assigned boundary.

* **File:** `backend/src/auth/scope.guard.ts`
* **Behavior:** Reads `@RequireScope({ storeIdParam: 'storeId' })` metadata. For STORE\_MANAGER, verifies the `storeId` in the URL params matches their assigned store. For HR, verifies the store belongs to their client. Admins bypass all scope checks.
* **Scope:** Global, but only enforced when the route has `@RequireScope()` metadata

### Scope Rules

| Role           | Can access...                              |
| -------------- | ------------------------------------------ |
| SUPER\_ADMIN   | Any store, any client                      |
| MUZE\_ADMIN    | Any store, any client                      |
| HR             | Any store within their assigned `clientId` |
| STORE\_MANAGER | Only their assigned `storeId`              |
| EMPLOYEE       | Only own data (no login, no API access)    |

## How roles map to permissions

The mapping is defined in `backend/src/auth/permissions.ts` as four composable groups (base, scoped manager, regional, HR) plus `ALL_PERMISSIONS` for admin roles. The full group table and role-permission matrix are in [Roles and permissions](/security/roles-permissions).
