# Convex WorkOS AuthKit Convex WorkOS AuthKit is the official Convex component for integrating WorkOS AuthKit authentication into Convex applications. It provides seamless synchronization of user data from WorkOS to your Convex database through webhooks, enabling reliable and durable user management. The component handles user creation, updates, and deletions automatically while exposing hooks for custom event handling. The core functionality centers around the `AuthKit` class which manages webhook routes, user data synchronization, and authentication configuration. It supports WorkOS Actions for controlling user registration and authentication flows, allowing developers to implement custom allow/deny logic. The component also provides typed event handlers for responding to WorkOS events like `user.created`, `user.updated`, `user.deleted`, and custom session events. ## Installation and Component Setup Install the package and configure it as a Convex component to enable WorkOS AuthKit integration in your project. ```typescript // convex/convex.config.ts import workOSAuthKit from "@convex-dev/workos-authkit/convex.config"; import { defineApp } from "convex/server"; const app = defineApp(); app.use(workOSAuthKit); export default app; ``` ## Environment Variables Configuration Set up the required environment variables for WorkOS integration. These must be configured in your Convex deployment. ```bash # Required: Get from WorkOS dashboard npx convex env set WORKOS_CLIENT_ID= npx convex env set WORKOS_API_KEY= npx convex env set WORKOS_WEBHOOK_SECRET= # Optional: Only required if using WorkOS Actions npx convex env set WORKOS_ACTION_SECRET= ``` ## AuthKit Client Initialization Create and export an AuthKit instance that connects to the installed component. This client is used throughout your application for authentication operations. ```typescript // convex/auth.ts import { AuthKit, type AuthFunctions } from "@convex-dev/workos-authkit"; import { components, internal } from "./_generated/api"; import type { DataModel } from "./_generated/dataModel"; // Reference to internal functions for event/action handling const authFunctions: AuthFunctions = internal.auth; // Initialize AuthKit with component and optional configuration export const authKit = new AuthKit(components.workOSAuthKit, { authFunctions, // Optional: Add extra event types to handle additionalEventTypes: ["session.created", "session.revoked"], // Optional: Enable debug logging logLevel: "DEBUG", }); ``` ## Register HTTP Webhook Routes Register the component's webhook routes to receive events from WorkOS. This enables automatic user synchronization. ```typescript // convex/http.ts import { httpRouter } from "convex/server"; import { authKit } from "./auth"; const http = httpRouter(); // Registers routes: // POST /workos/webhook - Receives WorkOS webhook events // POST /workos/action - Receives WorkOS action requests authKit.registerRoutes(http); export default http; ``` ## Configure Auth Providers Export the authentication configuration for Convex to validate WorkOS JWT tokens. ```typescript // convex/auth.config.ts import { authKit } from "./auth"; export default { providers: authKit.getAuthConfigProviders(), }; // Returns provider configuration for WorkOS JWT validation: // [ // { // type: "customJwt", // issuer: "https://api.workos.com/", // algorithm: "RS256", // jwks: "https://api.workos.com/sso/jwks/", // applicationID: "", // }, // { // type: "customJwt", // issuer: "https://api.workos.com/user_management/", // algorithm: "RS256", // jwks: "https://api.workos.com/sso/jwks/", // }, // ] ``` ## Get Authenticated User Retrieve the currently authenticated user's data from the component's user table using the `getAuthUser` method. ```typescript // convex/auth.ts import { query } from "./_generated/server"; import { authKit } from "./auth"; export const getCurrentUser = query({ args: {}, handler: async (ctx, _args) => { // Returns null if not authenticated // Returns user object with WorkOS user data if authenticated const user = await authKit.getAuthUser(ctx); return user; }, }); // User object structure from WorkOS: // { // id: "user_01EXAMPLE", // email: "user@example.com", // firstName: "John", // lastName: "Doe", // emailVerified: true, // profilePictureUrl: "https://...", // lastSignInAt: "2024-01-15T10:30:00Z", // externalId: null, // metadata: {}, // locale: "en", // createdAt: "2024-01-01T00:00:00Z", // updatedAt: "2024-01-15T10:30:00Z", // } ``` ## Handle User Events Define event handlers to respond to WorkOS user lifecycle events. Use these to sync user data to your own tables or trigger custom logic. ```typescript // convex/auth.ts import { AuthKit, type AuthFunctions } from "@convex-dev/workos-authkit"; import { components, internal } from "./_generated/api"; import type { DataModel } from "./_generated/dataModel"; const authFunctions: AuthFunctions = internal.auth; const authKit = new AuthKit(components.workOSAuthKit, { authFunctions, }); // Export authKitEvent - this is called by the component when events occur export const { authKitEvent } = authKit.events({ "user.created": async (ctx, event) => { // ctx is a mutation context, event.data is typed await ctx.db.insert("users", { authId: event.data.id, email: event.data.email, name: `${event.data.firstName} ${event.data.lastName}`, }); }, "user.updated": async (ctx, event) => { const user = await ctx.db .query("users") .withIndex("authId", (q) => q.eq("authId", event.data.id)) .unique(); if (!user) { console.warn(`User not found: ${event.data.id}`); return; } await ctx.db.patch(user._id, { email: event.data.email, name: `${event.data.firstName} ${event.data.lastName}`, }); }, "user.deleted": async (ctx, event) => { const user = await ctx.db .query("users") .withIndex("authId", (q) => q.eq("authId", event.data.id)) .unique(); if (!user) { console.warn(`User not found: ${event.data.id}`); return; } await ctx.db.delete(user._id); }, }); ``` ## Handle Additional Event Types Configure the component to handle additional WorkOS event types beyond the default user events. These must also be enabled in your WorkOS webhook configuration. ```typescript // convex/auth.ts import { AuthKit, type AuthFunctions } from "@convex-dev/workos-authkit"; import { components, internal } from "./_generated/api"; import type { DataModel } from "./_generated/dataModel"; const authFunctions: AuthFunctions = internal.auth; const authKit = new AuthKit(components.workOSAuthKit, { authFunctions, // Add additional event types to handle additionalEventTypes: ["session.created", "session.revoked"], }); export const { authKitEvent } = authKit.events({ "user.created": async (ctx, event) => { console.log("User created:", event.data.email); }, "user.updated": async (ctx, event) => { console.log("User updated:", event.data.email); }, "user.deleted": async (ctx, event) => { console.log("User deleted:", event.data.id); }, // Handle session events "session.created": async (ctx, event) => { console.log("Session created:", event); // Track user sessions, update last login, etc. }, "session.revoked": async (ctx, event) => { console.log("Session revoked:", event); // Clean up session data, invalidate caches, etc. }, }); ``` ## Implement Authentication Actions Use WorkOS Actions to control user registration and authentication flows with custom allow/deny logic. Configure the action endpoint URL in your WorkOS dashboard to `https://.convex.site/workos/action`. ```typescript // convex/auth.ts import { AuthKit, type AuthFunctions } from "@convex-dev/workos-authkit"; import { components, internal } from "./_generated/api"; import type { DataModel } from "./_generated/dataModel"; const authFunctions: AuthFunctions = internal.auth; const authKit = new AuthKit(components.workOSAuthKit, { authFunctions, }); // Export authKitAction - called when WorkOS Actions are triggered export const { authKitAction } = authKit.actions({ // Control authentication attempts authentication: async (ctx, action, response) => { // action contains authentication context // Check for suspicious activity, enforce MFA, etc. return response.allow(); }, // Control user registration userRegistration: async (ctx, action, response) => { // Block specific email domains if (action.userData.email.endsWith("@blocked-domain.com")) { return response.deny("This email domain is not allowed"); } // Require corporate email if (action.userData.email.endsWith("@gmail.com")) { return response.deny("Please use your corporate email address"); } // Check against allowlist in database const allowedDomain = await ctx.db .query("allowedDomains") .filter((q) => q.eq(q.field("domain"), action.userData.email.split("@")[1]) ) .first(); if (!allowedDomain) { return response.deny("Your organization is not registered"); } return response.allow(); }, }); ``` ## Define Application Schema with User Table Create your application's user table schema that references the AuthKit user data. Index by `authId` for efficient lookups. ```typescript // convex/schema.ts import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; export default defineSchema({ // Your application's user table users: defineTable({ authId: v.string(), // References WorkOS user id email: v.string(), name: v.string(), // Add your custom fields role: v.optional(v.string()), preferences: v.optional(v.object({ theme: v.string(), notifications: v.boolean(), })), }).index("authId", ["authId"]), // Example: User-owned resources todoLists: defineTable({ userId: v.string(), // References WorkOS user id name: v.string(), items: v.array(v.object({ text: v.string(), completed: v.boolean(), })), }).index("userId", ["userId"]), }); ``` ## React Frontend Integration Use the AuthKit React hooks alongside Convex React hooks to build authenticated UI components. ```tsx // src/App.tsx import { useConvexAuth, useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; import { useAuth } from "@workos-inc/authkit-react"; function App() { const { signIn, signOut } = useAuth(); const { isAuthenticated, isLoading } = useConvexAuth(); // Skip query when not authenticated const user = useQuery( api.auth.getCurrentUser, isAuthenticated ? {} : "skip" ); if (isLoading) { return
Loading...
; } return (

My App

{isAuthenticated ? ( <>

Welcome, {user?.email}

Name: {user?.firstName} {user?.lastName}

) : ( )}
); } export default App; ``` ## WorkOS Webhook Configuration Configure webhooks in the WorkOS dashboard to enable user data synchronization with your Convex deployment. ```text Webhook Configuration in WorkOS Dashboard: 1. Navigate to: WorkOS Dashboard > Webhooks > Create Webhook 2. Endpoint URL: https://.convex.site/workos/webhook 3. Select Events (minimum required): - user.created - user.updated - user.deleted 4. Optional Additional Events: - session.created - session.revoked - organization.created - organization.updated - (see WorkOS docs for full list) 5. Copy the Webhook Signing Secret and set it: npx convex env set WORKOS_WEBHOOK_SECRET= ``` ## WorkOS Actions Configuration Configure actions in WorkOS to enable custom registration and authentication control flows. ```text Action Configuration in WorkOS Dashboard: 1. Navigate to: WorkOS Dashboard > Actions 2. Create User Registration Action: - Endpoint URL: https://.convex.site/workos/action - Copy the Action Signing Secret 3. Create Authentication Action (optional): - Endpoint URL: https://.convex.site/workos/action - Uses same signing secret 4. Set the action secret: npx convex env set WORKOS_ACTION_SECRET= ``` ## Component User Schema Reference The component maintains its own user table that stores WorkOS user data. This schema shows the structure of user records managed by the component. ```typescript // Component's internal user schema (read-only reference) // Access via authKit.getAuthUser(ctx) interface WorkOSUser { id: string; // WorkOS user ID (e.g., "user_01EXAMPLE") email: string; // User's email address firstName: string | null | undefined; // First name lastName: string | null | undefined; // Last name emailVerified: boolean; // Email verification status profilePictureUrl: string | null | undefined; // Avatar URL lastSignInAt: string | null | undefined; // ISO timestamp of last sign in externalId: string | null | undefined; // Your external ID if set metadata: Record; // Custom metadata from WorkOS locale: string | null | undefined; // User's locale preference createdAt: string; // ISO timestamp of creation updatedAt: string; // ISO timestamp of last update } ``` --- Convex WorkOS AuthKit is designed for applications requiring enterprise-grade authentication with Convex's real-time backend. The primary use case is building B2B SaaS applications where user management, SSO, and directory sync capabilities from WorkOS need to be integrated with Convex's reactive data layer. The component handles the complexity of webhook verification, event ordering, and data synchronization automatically. Integration patterns typically involve creating a custom user table that mirrors relevant WorkOS user fields while adding application-specific data. Event handlers sync changes from WorkOS to your tables, while Actions provide control over the registration and authentication flows. The React integration layer works seamlessly with both `@workos-inc/authkit-react` hooks for authentication state and Convex React hooks for data queries, enabling fully reactive authenticated applications with minimal boilerplate.