Overview
After authentication, the EPR LAPS Backend API applies role-based access control (RBAC) to determine if a user has permission to perform specific operations. Authorization is implemented as a Hapi plugin that intercepts requests using theonPostAuth lifecycle hook.
How Authorization Works
The access control plugin (src/plugins/access-control.js) runs after JWT authentication completes and checks if the user’s role has permission to access the requested endpoint.
Authorization Flow
- Request authenticated - JWT validated and credentials extracted
- Role mapped - User’s role mapped to internal role code
- Permission checked - Route mapped to permission requirement
- Access decision - User’s role compared against allowed roles
- Flag set -
request.auth.isAuthorizedset totrueorfalse
The authorization plugin sets a flag but does not reject requests. Route handlers must check
request.auth.isAuthorized and respond accordingly.Role Mapping
User roles from Defra ID are mapped to internal role codes (src/plugins/access-control.js:11-17):
Supported Roles
| Role Name | Code | Typical Permissions |
|---|---|---|
| Chief Executive Officer | CEO | Full access to all operations |
| Head of Finance | HOF | Financial operations |
| Head of Waste | HOW | Waste management operations |
| Waste Officer | WO | Limited waste operations |
| Finance Officer | FO | Limited financial operations |
Permission Model
Each API operation is mapped to a permission key (src/plugins/access-control.js:3-9):
Permission to Role Mapping
Permissions are configured insrc/config.js:171-202 with environment variable overrides:
Authorization Plugin Implementation
The access control plugin uses Hapi’sonPostAuth extension point (src/plugins/access-control.js:30-48):
Key Points
- Route matching - Matches
METHOD /pathformat - No permission key - If route not in map, request continues (no authorization check)
- Debug logging - Logs authorization decisions for auditing
- Non-blocking - Sets flag but doesn’t reject request
Ignored Routes
Certain routes bypass authorization checks entirely (src/plugins/access-control.js:22-27):
Using Authorization in Routes
Route handlers should check theisAuthorized flag:
Always check
request.auth.isAuthorized before performing sensitive operations, even if the route is protected.Permission Matrix
Here’s the complete default permission matrix: | Permission | CEO | HOF | HOW | WO | FO | |------------|-----|-----|-----|----|----|----| | View Full Bank Details | ✓ | ✗ | ✗ | ✗ | ✗ | | Confirm Bank Details | ✓ | ✗ | ✗ | ✓ | ✗ | | Create Bank Details | ✓ | ✗ | ✗ | ✗ | ✗ | | List Finance Documents | ✓ | ✗ | ✗ | ✗ | ✗ | | Access Finance Document | ✓ | ✗ | ✗ | ✗ | ✗ |Customizing Permissions via Environment Variables
Customizing Permissions via Environment Variables
You can override default permissions using environment variables:Note: Values must be valid JSON arrays.
Adding New Permissions
To add a new permission:1. Add Route Permission Mapping
Insrc/plugins/access-control.js:
2. Add Permission Configuration
Insrc/config.js authorization section:
3. Implement Authorization Check
In your route handler:Testing Authorization
Security Considerations
Organization-Level Isolation
In addition to role-based checks, consider implementing organization-level isolation:This pattern ensures users can only access resources belonging to their current organization, even if they have the required role.