User Authentication & Authorization
Relevant source files
The following files were used as context for generating this wiki page:The authentication and authorization system in this project is built upon two primary mechanisms: interactive user authentication managed by Clerk, and programmatic access via a custom API key system. Clerk handles user sign-up, sign-in, and session management for the web application. User data from Clerk is synchronized to the application's local database via webhooks.
For non-interactive or automated tasks, the system provides API key-based authentication. These keys are associated with a user and can be used to authenticate against specific API endpoints, such as the MCP server. Authorization is enforced at the middleware level, protecting routes and ensuring that only authenticated users or valid API key holders can access protected resources.
Route Protection Middleware
Route protection is handled by a Next.js middleware that leverages the @clerk/nextjs/server package. By default, all routes are protected, and only explicitly defined public or ignored routes are accessible without authentication.
Sources: apps/web/middleware.ts
Middleware Configuration
The authMiddleware function is configured with two lists of routes:
publicRoutes: These routes are accessible to everyone, but the authentication state is still available.ignoredRoutes: These routes are completely bypassed by the authentication middleware. This is typically used for webhooks or other external services that have their own verification mechanisms.
// File: apps/web/middleware.ts:4-17
export default authMiddleware({
// Routes that can be accessed while signed out
publicRoutes: ["/login", "/api/health/openrouter", "/api/v1/invoke"],
// Routes that can always be accessed, and auth middleware will not run
ignoredRoutes: [
"/api/clerk/webhooks",
"/api/cron/cleanup",
"/api/evolution-runs/cleanup",
"/api/help/icon",
"/api/test/approve",
"/api/test/help",
"/api/test",
],
});
Sources: apps/web/middleware.ts:4-17
Authentication Flow
This diagram illustrates how the middleware processes incoming requests to protect routes.
Sources: apps/web/middleware.ts
User Synchronization with Clerk
User data is synchronized from Clerk to the application's local database using webhooks. This ensures that the local user table is kept up-to-date with user creation, updates, and deletion events from Clerk.
Webhook Handler
The endpoint at /api/clerk/webhooks listens for POST requests from Clerk. It verifies the authenticity of the webhook using the svix library and then processes the event.
Sources: apps/web/src/app/api/clerk/webhooks/route.ts
The handler processes the following event types:
| Event Type | Action |
|---|---|
user.created | Calls syncUser to create a new user record in the database. |
user.updated | Calls syncUser to update an existing user record. |
user.deleted | Calls deleteUser to remove the user record from the database. |
Sources: apps/web/src/app/api/clerk/webhooks/route.ts:31-48
User Sync Sequence Diagram
This diagram shows the sequence of events when a user is created in Clerk.
Database Synchronization Logic
The syncUser function in lib/iam/sync-user.ts is responsible for the UPSERT logic into the User table. It maps attributes from the Clerk user object to the corresponding columns in the database.
The deleteUser function handles the removal of a user record based on their clerkId.
Sources: apps/web/src/lib/iam/sync-user.ts:10-41
Principal Identity
The application uses the concept of a "Principal" to represent the currently authenticated user. The getPrincipal function retrieves the userId (which corresponds to the clerkId) from the active Clerk session.
Key Functions
getPrincipal(): Asynchronously returns theclerkIdof the signed-in user, ornullif no user is authenticated.getPrincipalOrThrow(): A synchronous-like wrapper that throws an error if no authenticated user is found, useful for ensuring a user is present in protected contexts.
Sources: apps/web/src/lib/auth/principal.ts:3-13
API Key Authentication
For programmatic access, the system uses API keys which are tied to a user's clerkId. These keys are used to authenticate requests to endpoints like the MCP server.
API Key Generation and Storage
API keys are generated and stored in the lockbox.secret_keys table. The process involves creating a key, hashing its secret part, and storing the hash along with metadata.
This diagram shows the relationship between users and their API keys.
The createTestUserWithServiceRole helper function provides a clear example of this process:
- A
clerkIdis generated for the user. generateApiKey()creates a new key ID, a secret, and the full API key.hashSecret()is used to hash the secret part of the key.- An entry is inserted into
lockbox.secret_keyswith theclerk_id,key_id, andsecret_hash.
Sources: tests/helpers/test-auth-simple.ts:20-48
API Key Extraction and Validation
On the server side, incoming requests are authenticated by extracting the API key from the HTTP headers.
The extractApiKey function looks for the key in the following headers, in order of preference:
x-lucky-api-keyorx-api-keyAuthorizationheader with aBearertoken.
This extracted key is then used to authenticate the request.
Sources: packages/mcp-server/src/index.ts:33-45, packages/mcp-server/src/index.ts:52-64
This sequence diagram shows how an API key is used to authenticate a request to the MCP server.