Authentication & Authorization API
Relevant source files
The following files were used as context for generating this wiki page:
The Authentication and Authorization system is a critical module responsible for verifying user identities and controlling access to protected resources within the application. It provides a secure login mechanism, generates authentication tokens, and implements a Role-Based Access Control (RBAC) model to enforce permissions for various API endpoints.
The system is designed with flexibility, supporting both stateless JWT authentication and stateful, Redis-backed sessions. This allows for scalability while also providing a mechanism for immediate session invalidation if needed. Authorization is managed through a clear mapping of user roles to specific permissions, ensuring that users can only perform actions and access data that their role allows.
Authentication
Authentication is the process of verifying a user's identity. In this system, it is primarily handled by the /api/auth/login endpoint.
Login Flow
When a user attempts to log in, they submit their username and password to the login endpoint. The server then validates these credentials against the database. If successful, it generates a token that the client can use for subsequent authenticated requests.
The following sequence diagram illustrates the login process.
This diagram shows the sequence of operations during user login, including credential validation and the two possible token generation strategies (with or without Redis).
Sources: src/app/api/auth/login/route.ts:15-41, src/lib/auth.ts:68-81
API Endpoint: POST /api/auth/login
This endpoint authenticates a user and returns a token and user information.
Request Body:
| Parameter | Type | Description |
|---|---|---|
username | string | The user's username. |
password | string | The user's password. |
Sources: src/app/api/auth/login/route.ts:16-19
Response Body (Success):
| Parameter | Type | Description |
|---|---|---|
token | string | The bearer token for authenticating subsequent requests. |
user | object | An object containing user details (id, username, role, teams, etc.). |
Sources: src/app/api/auth/login/route.ts:37-40
Token Generation Strategies
The system supports two strategies for generating authentication tokens, determined by whether Redis is enabled.
-
Redis-backed Sessions (Stateful): If
redis.enabledis true, the system creates a session in Redis containing the user's ID and role. A uniqueauthKeyis generated for this session, and this key is then embedded in a JWT. This approach allows for server-side session invalidation.
Sources: src/lib/auth.ts:68-81, src/app/api/auth/login/route.ts:31-32 -
Stateless JWT: If Redis is not enabled, the system generates a standard stateless JWT. The payload of this token directly contains the
userIdandrole. This is a simpler approach that does not require a separate session store.
Sources: src/app/api/auth/login/route.ts:33-35
Authorization
Authorization is the process of determining if an authenticated user has the necessary permissions to access a specific resource or perform an action. This is achieved through a Role-Based Access Control (RBAC) system.
Roles and Permissions
The system defines a set of roles and a set of permissions. Each role is granted a specific list of permissions.
Defined Roles:
| Role | Description |
|---|---|
admin | Administrator with all permissions. |
user | Standard user with rights to manage own resources. |
view-only | User with read-only access. |
team-owner | Owner of a team with full control over it. |
team-manager | Manager of a team with update rights. |
team-member | Member of a team with creation rights. |
team-view-only | Member of a team with read-only access. |
Sources: src/lib/constants.ts:114-123
Permission Mapping:
The ROLE_PERMISSIONS object maps each role to an array of permissions. The admin role has a special all permission, granting universal access.
// From src/lib/constants.ts
export const ROLE_PERMISSIONS = {
[ROLES.admin]: [PERMISSIONS.all],
[ROLES.user]: [
PERMISSIONS.websiteCreate,
PERMISSIONS.websiteUpdate,
PERMISSIONS.websiteDelete,
PERMISSIONS.teamCreate,
],
[ROLES.viewOnly]: [],
[ROLES.teamOwner]: [
PERMISSIONS.teamUpdate,
PERMISSIONS.teamDelete,
PERMISSIONS.websiteCreate,
// ... and more
],
// ... other roles
} as const;
Sources: src/lib/constants.ts:135-163
Authorization Flow
For each incoming request to a protected endpoint, the system performs an authorization check.
The following diagram shows the authorization flow for a typical API request.
This flow demonstrates how a request is authenticated via its token and then authorized by checking the user's role against the required permissions for the endpoint.
Sources: src/lib/auth.ts:20-50, src/app/api/users/[userId]/route.ts:16-20, src/permissions/index.ts
Key Authorization Functions
| Function | File | Description |
|---|---|---|
checkAuth | src/lib/auth.ts | Middleware function to authenticate a request by parsing the token and retrieving the user. |
hasPermission | src/lib/auth.ts | Checks if a given role has a specific permission. |
can... | src/permissions/ | A set of functions (e.g., canViewUser, canUpdateUser) that encapsulate permission logic for specific actions. |
getBearerToken | src/lib/auth.ts | Extracts the token from the Authorization header. |
Sources: src/lib/auth.ts, src/permissions/index.ts
An example of how these permissions are used to protect an endpoint can be seen in the user details route:
// From src/app/api/users/[userId]/route.ts
export async function GET(request: Request, { params }: { params: Promise<{ userId: string }> }) {
const { auth, error } = await parseRequest(request);
if (error) {
return error();
}
const { userId } = await params;
if (!(await canViewUser(auth, userId))) {
return unauthorized();
}
const user = await getUser(userId);
return json(user);
}
This snippet shows that before fetching user data, the canViewUser permission check is performed.
Sources: src/app/api/users/[userId]/route.ts:12-26
Summary
The authentication and authorization system provides a robust and flexible foundation for securing the application. It handles user login through a dedicated API endpoint and uses JWTs for session management, with an optional Redis-backed stateful layer. Access control is managed granularly through a well-defined set of roles and permissions, ensuring that users can only access the resources and perform the actions appropriate for their role. This architecture is central to maintaining data integrity and security across the platform.
Sources: src/app/api/auth/login/route.ts, src/lib/auth.ts, src/lib/constants.ts