BuzzTrip delegates all user identity management to Clerk, keeping authentication secure and fully managed while your user records live in Convex. When a user creates an account or signs in, Clerk issues a short-lived JWT that every Convex query and mutation validates server-side — so your map data is always tied to a verified identity.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/jacobsamo/buzztrip/llms.txt
Use this file to discover all available pages before exploring further.
How It Works
User signs up or signs in via Clerk
Clerk hosts the sign-in and sign-up flows at
/sign-in and /sign-up respectively. After a successful auth event, Clerk issues a signed JWT.Clerk issues a JWT with the convex template
The token is generated using the
convex JWT template configured in your Clerk dashboard. This template shapes the claims Convex needs to verify the request.Next.js server retrieves the token
On the server,
getAuthToken() calls Clerk’s auth().getToken({ template: "convex" }) and passes the result into convexNextjsOptions(), which builds the Convex client configuration containing both the deployment URL (NEXT_PUBLIC_CONVEX_URL) and the bearer token.Convex validates the JWT on every request
Convex checks the token against the
CLERK_FRONTEND_API_URL domain configured in auth.config.ts. Every query and mutation that requires a logged-in user will fail immediately if the token is missing or expired.Clerk fires a user.created webhook on new sign-up
When a brand-new user completes sign-up, Clerk sends a
user.created event to the BuzzTrip Convex HTTP endpoint at POST /clerk-users-webhook. The webhook handler calls internal.users.createUser with the raw Clerk UserJSON payload.User Record Fields
TheuserSchema (defined in zod-schemas/auth-schema.ts) describes every field stored for each BuzzTrip user in Convex:
| Field | Type | Notes |
|---|---|---|
clerkUserId | string | The Clerk user ID — used as the primary lookup key |
name | string | Full name, constructed as first_name + " " + last_name |
first_name | string (optional) | Given name from Clerk profile |
last_name | string (optional) | Family name from Clerk profile |
email | string | Primary email address from Clerk |
username | string (optional) | Clerk username, if set |
image | string | Profile image URL from Clerk (image_url) |
updatedAt | string | ISO timestamp of the last sync from Clerk |
createdAt | string (optional) | ISO timestamp when the user record was created |
bio | string (optional) | User-provided biography |
isBetaUser | boolean (optional) | Early-access flag — see note below |
Users with
isBetaUser: true on their account have been enrolled in the BuzzTrip beta programme. This flag is used for quick permission checks without joining additional tables, and gates early-access features as they are released.Session Helpers
Three server-side helpers inapps/web/src/lib/auth.ts abstract Clerk and Convex session handling:
getAuthToken()
getAuthToken()
Retrieves the Clerk JWT scoped to the
convex template. Returns undefined if the user is not signed in.convexNextjsOptions()
convexNextjsOptions()
Returns a
NextjsOptions object containing the Convex deployment URL and the current auth token. Pass this to any fetchQuery or fetchMutation call from Next.js Server Components or Route Handlers.getConvexServerSession()
getConvexServerSession()
Runs the
api.users.userLoginStatus Convex query server-side and returns one of three states:| Message | Meaning |
|---|---|
"No JWT Token" | The request carries no Clerk token — user has not started the login flow |
"No Clerk User" | A valid token exists but Convex has not yet received the user.created webhook |
"Logged In" | Token is valid and the user document exists in Convex |
Webhook Setup
The Clerk → Convex sync is driven by a webhook registered in your Clerk dashboard. The Convex HTTP router exposes a single endpoint that handles all user lifecycle events:| Clerk Event | Convex Mutation |
|---|---|
user.created | internal.users.createUser |
user.updated | internal.users.updateUser |
user.deleted | internal.users.deleteUser |
Environment Variables
For self-hosting or local development, set the following environment variables:Protected Routes
BuzzTrip uses Clerk middleware to enforce authentication. All routes under/app/* require a valid session — unauthenticated visitors are redirected to /sign-in automatically. Public marketing pages (/, /pricing, /sign-in, /sign-up, etc.) are accessible without a session.