Skip to main content

Overview

The authentication system uses @convex-dev/auth with support for multiple providers including Password, Anonymous, GitHub, and Google OAuth.

Configuration

Auth Config

Location: convex/auth.config.ts:14
export default {
  providers: [
    {
      domain: process.env.CONVEX_SITE_URL!,
      applicationID: "convex",
    },
  ],
} satisfies AuthConfig;

Environment Variables

CONVEX_SITE_URL
string
required
Your Convex deployment URL. Automatically set by Convex.
AUTH_GITHUB_ID
string
GitHub OAuth application client ID. Required for GitHub authentication.
AUTH_GITHUB_SECRET
string
GitHub OAuth application client secret. Required for GitHub authentication.
AUTH_GOOGLE_ID
string
Google OAuth client ID. Required for Google authentication.
AUTH_GOOGLE_SECRET
string
Google OAuth client secret. Required for Google authentication.

Auth Setup

Location: convex/auth.ts:23

Providers

The authentication system dynamically loads providers based on available environment variables:
const providers = [
  Password,
  Anonymous,
];

// GitHub provider (optional)
if (process.env.AUTH_GITHUB_ID && process.env.AUTH_GITHUB_SECRET) {
  providers.push(GitHub);
}

// Google provider (optional)
if (process.env.AUTH_GOOGLE_ID && process.env.AUTH_GOOGLE_SECRET) {
  providers.push(Google);
}

Built-in Providers

Password
Provider
required
Email and password authentication provider from @convex-dev/auth/providers/Password
Anonymous
Provider
required
Anonymous authentication provider for demo/guest access from @convex-dev/auth/providers/Anonymous
GitHub
Provider
GitHub OAuth provider from @auth/core/providers/github. Enabled when GitHub credentials are configured.
Google
Provider
Google OAuth provider from @auth/core/providers/google. Enabled when Google credentials are configured.

Exported Functions

auth

Middleware function for protecting routes and queries.
export const { auth } = convexAuth({ ... });

signIn

Function to initiate sign-in flow.
export const { signIn } = convexAuth({ ... });

signOut

Function to sign out the current user.
export const { signOut } = convexAuth({ ... });

store

Auth state storage helpers.
export const { store } = convexAuth({ ... });

isAuthenticated

Helper to check if user is authenticated.
export const { isAuthenticated } = convexAuth({ ... });

Callbacks

createOrUpdateUser

Location: convex/auth.ts:26 Callback invoked when a user signs in. Creates new users or updates existing ones.
async createOrUpdateUser(ctx, args) {
  const isAnonymous = args.provider?.id === "anonymous";
  
  if (args.existingUserId) {
    return args.existingUserId;
  }
  
  const name = isAnonymous
    ? `User-${Math.floor(Math.random() * 10000)}`
    : args.profile?.name;
  
  const userId = await ctx.db.insert("users", {
    name,
    email: args.profile?.email,
    image: args.profile?.image,
    isAnonymous,
  });
  
  return userId;
}

Parameters

ctx
MutationCtx
required
Convex mutation context with database access
args
object
required
Authentication arguments
args.existingUserId
Id<'users'>
ID of existing user if found
args.provider
object
Authentication provider information
args.provider.id
string
Provider identifier (e.g., “anonymous”, “password”, “github”)
args.profile
object
User profile from OAuth provider
args.profile.name
string
User’s display name from provider
args.profile.email
string
User’s email from provider
args.profile.image
string
User’s profile image URL from provider

Returns

userId
Id<'users'>
The user ID (existing or newly created)

Behavior

  • For anonymous users: Generates a random name like User-1234
  • For existing users: Returns the existing user ID
  • For new users: Creates a user record with profile data and isAnonymous flag
  • Automatically sets isAnonymous: true for anonymous provider logins

Usage Examples

Check Authentication Status

import { getAuthUserId } from "@convex-dev/auth/server";
import { query } from "./_generated/server";

export const myQuery = query({
  handler: async (ctx) => {
    const userId = await getAuthUserId(ctx);
    if (!userId) {
      throw new Error("Not authenticated");
    }
    // ... authenticated logic
  },
});

Support Demo Mode

export const myMutation = mutation({
  handler: async (ctx, args) => {
    const userId = await getAuthUserId(ctx);
    // Works with or without authentication
    const finalUserId = userId ?? undefined;
    // ... logic that supports both authenticated and demo mode
  },
});

Build docs developers (and LLMs) love