Cosmo Docs
Server

Auth Module

JWT, Clerk sync, org management, invitations, and webhooks

The Auth module handles all identity, token, and organisation management. Source: packages/server/src/modules/auth/.

REST Endpoints

AuthController (auth.controller.ts)

All endpoints are prefixed with /api/v1/auth.

MethodPathGuardsDescription
GET/cli-authNoneCLI auth step 1 — redirect to Clerk sign-in
GET/cli-callbackNoneCLI auth step 2 — exchange session for Cosmo JWT
POST/exchange-tokenNoneDesktop/web — exchange Clerk JWT for Cosmo JWT
POST/onboarding-completeClerkAuthGuardMark user's onboarding complete
POST/seed-onboardingClerkAuthGuardSeed org with sample teams + tasks (idempotent)
POST/refreshNoneRefresh expired Cosmo JWT (7-day grace)
GET/meClerkAuthGuard + OptionalOrgGet authenticated user profile
POST/webhookNoneClerk webhook receiver (Svix-verified)

OrgController (org.controller.ts)

All endpoints are prefixed with /api/v1/org.

MethodPathGuardsDescription
GET/membersClerkAuthGuard + RolesGuardList org members
PATCH/members/:userId/role@Roles('OWNER')Change a member's role
DELETE/members/:userId@Roles('OWNER', 'ADMIN')Remove a member
GET/invites@Roles('OWNER', 'ADMIN')List pending invitations
POST/invite@Roles('OWNER', 'ADMIN')Invite a user by email
POST/invite/:id/resend@Roles('OWNER', 'ADMIN')Resend an invitation
DELETE/invite/:id@Roles('OWNER', 'ADMIN')Revoke an invitation

Auth Service (services/auth.service.ts)

Token Operations

MethodDescription
mintCosmoToken(userId, orgId, orgRole)Issue a 30-day signed JWT
verifyCosmoToken(token)Verify and decode; throws on invalid/expired
refreshToken(token)Re-issue JWT; allows up to 7 days after expiry
verifyClerkToken(token)Verify Clerk JWT, return { clerkUserId, clerkOrgId, clerkOrgRole }

User & Org Provisioning

MethodDescription
syncUserFromClerk(clerkUserId, email, name, avatarUrl)Create or update User record
syncOrgFromClerk(clerkId, name, slug)Create or update Organization record
syncMembership(clerkOrgId, clerkUserId, role)Upsert OrgMember with mapped role
getMembership(orgId, userId)Fetch membership or null
markOnboardingCompleted(orgId, userId)Set onboardingCompleted = true
fetchClerkUser(clerkUserId)Fetch user from Clerk Management API
fetchFirstClerkOrg(clerkUserId)Get user's first org from Clerk
fetchClerkMembershipRole(orgId, userId)Get role from Clerk (for refresh flows)

Member Management

MethodDescription
listMembers(orgId)All members with user data
updateMemberRole(orgId, userId, role)Change role
removeMember(orgId, userId)Delete membership record

Invitations

MethodDescription
createInvite(orgId, email, role)Generate invite with secure token (24h expiry)
listInvites(orgId)All pending (non-expired) invites
resendInvite(inviteId, orgId)Regenerate token with fresh 24h expiry
revokeInvite(inviteId, orgId)Delete the invite record

Onboarding Service (services/onboarding.service.ts)

seedOrgOnboarding(orgId, userId, data?) is the entry point called by POST /auth/seed-onboarding. It:

  1. Creates a shared team ("Shared") and a personal team for the user.
  2. Creates a shared workspace ("Shared Workspace") in the shared team.
  3. Seeds 6 sample tasks across the personal and shared workspaces.

The seeding is idempotent — it checks for an existing shared team before creating anything. A database transaction prevents race conditions from concurrent requests.

Webhook Handler (webhooks/webhook.handler.ts)

Handles Clerk webhooks verified with Svix. Registered at POST /api/v1/auth/webhook.

EventAction
user.createdsyncUserFromClerk(...)
user.updatedsyncUserFromClerk(...)
user.deletedDelete User record
organization.createdsyncOrgFromClerk(...)
organization.updatedsyncOrgFromClerk(...)
organizationMembership.createdsyncMembership(...)
organizationMembership.updatedsyncMembership(...)
organizationMembership.deletedremoveMember(...)
organizationInvitation.createdcreateInvite(...)
organizationInvitation.acceptedMark invite accepted
organizationInvitation.revokedrevokeInvite(...)

Auth Repository (repositories/auth.repository.ts)

All Prisma queries for auth data are delegated here:

  • User CRUD (findByClerkId, upsert, delete)
  • Org CRUD (findByClerkId, upsert)
  • Membership queries (findMembership, upsertMembership, deleteMembership, listByOrg)
  • Invite queries (create, findById, findByOrg, findByToken, delete)

CLI Auth Flow

  1. CLI calls GET /api/v1/auth/cli-auth?port={localPort}&state={random}.
  2. Server redirects to Clerk hosted sign-in with a callback to GET /api/v1/auth/cli-callback.
  3. After Clerk auth, the callback exchanges the Clerk session for a Cosmo JWT.
  4. Server redirects to http://localhost:{port}/callback?token=...&state=... — the CLI's local callback server (path is /callback, not /; includes the state parameter for CSRF protection).

Desktop Auth Flow

  1. Desktop opens the web app's auth page in the system browser.
  2. Web app authenticates via Clerk, then calls POST /api/v1/auth/exchange-token with the Clerk JWT.
  3. Server verifies the Clerk token, syncs user/org, issues a Cosmo JWT.
  4. Web app deep-links back to the desktop with cosmo://auth?token=....