Configuration

defineAuth(component, config)

defineAuth is the vNext preview setup surface. It is the preferred way to describe the app’s auth primitive: providers, permissions, table extensions, and HTTP intent live on one typed definition.

Current stable releases may still expose defineAuth. Treat defineAuth and definePermissions as the vNext target vocabulary while the implementation lands.

import { authEvents, defineAuth } from "@robelest/convex-auth/server";
import { definePermissions } from "@robelest/convex-auth/permissions";
import { password } from "@robelest/convex-auth/providers";
import { components } from "./_generated/api";
import { v } from "convex/values";

const permissions = definePermissions({
  grants: ["members.read", "sso.connection.manage"],
  roles: {
    member: {
      label: "Member",
      grants: ["members.read"],
    },
    admin: {
      label: "Admin",
      grants: ["members.read", "sso.connection.manage"],
    },
  },
});

const auth = defineAuth(components.auth, {
  providers: [password()],
  permissions,
  extend: {
    User: v.object({ stripeCustomerId: v.optional(v.string()) }),
  },
  session: {
    totalDurationMs: 30 * 24 * 60 * 60 * 1000, // 30 days
    inactiveDurationMs: 7 * 24 * 60 * 60 * 1000, // 7 days
  },
  jwt: {
    durationMs: 60 * 1000, // 1 minute
  },
  signIn: {
    maxFailedAttemptsPerHour: 10,
  },
  events: authEvents.handlers({
    user: {
      created: async (ctx, event) => {
        await enqueueOnboarding(ctx, { userId: event.subject.id });
      },
    },
    password: {
      changed: async (ctx, event) => {
        await auditPasswordChange(ctx, { userId: event.subject.id });
      },
    },
  }),
  path: "/auth",
});

Config options

OptionTypeDefaultDescription
providersAuthProviderConfig[]requiredAuth methods to enable
permissionsPermissionsDefinition{}App-defined grants and role bundles from definePermissions(...).
extend{ User?, Group?, GroupMember? } Convex validators{}Validator for each table’s extend field. Types auth.v.* (so viewer.extend.<field> is typed) and validates return shapes.
session.totalDurationMsnumber30 daysMaximum session lifetime
session.inactiveDurationMsnumbervariesInactive session timeout
jwt.durationMsnumber60sJWT token lifetime
signIn.maxFailedAttemptsPerHournumber10Failed sign-in throttle (backed by @convex-dev/rate-limiter token bucket; resets on successful sign-in)
eventsAuthEventHandlerMapStream-backed lifecycle handlers from authEvents.handlers(...).
pathstring"/auth"HTTP path where the app-owned auth protocol routes are mounted. Provider callbacks, the JWT issuer, OAuth discovery, and auth.request.add(http) all use this path.

Note: Email transport is configured via email({ from, send }) in the providers array, not as a top-level config option.

See Authorization Patterns for the recommended authorization model.

Return value

defineAuth returns an object with:

  • signIn — Action for client sign-in
  • signOut — Action for client sign-out
  • store — Internal runtime mutation for session token exchange
  • auth.user.* — User helpers
  • auth.session.* — Session helpers
  • auth.account.* — Account helpers
  • auth.group.* — Group helpers
  • auth.member.* — Membership helpers
  • auth.invite.* — Invite helpers
  • auth.key.* — API key helpers
  • auth.request.* — HTTP route helpers
  • auth.http() — app-owned HTTP router for OAuth callbacks, JWKS, and protocol routes
  • auth.v.* — Convex returns: validators for the read surface (user, group, member, invite, viewer, list). See Typed Returns.
  • auth.connection.* — group connection (SSO) admin facade when connection() is in providers
  • InferClientApi<typeof auth> — Type-level utility; use as the generic for client() on the frontend to get conditional passkey/totp/device helpers
  • Doc, Viewer, Group, Membership — exported document types (extend-aware), importable from @robelest/convex-auth/server

Per-provider OAuth options

OAuth provider factories (google, github, apple, microsoft, custom) accept these common options in addition to provider-specific fields:

OptionTypeDefaultDescription
redirectUristringderivedCallback URL override. Defaults to ${CONVEX_SITE_URL}/auth/callback/<provider>.
scopesstring[]provider-defaultOAuth scopes requested at the authorize step.
accountLinking"verifiedEmail" \| "none""verifiedEmail"On first sign-in, link to an existing user if the verified email matches.
updateProfileOnLoginbooleantrueOn a returning sign-in, refresh User.name/image/email from the new profile. Set false if your app owns the canonical profile. Behavior matches Auth.js / Clerk.

For SSO connections, the equivalent of updateProfileOnLogin lives on the group connection policy under policy.provisioning.user.updateProfileOnLogin.

API layers

Auth-flow actions

signIn and signOut are the app-facing Convex functions used by the frontend auth client.

Helper namespaces

auth.*, auth.connection.*, and auth.connection.scim.* are server-side helper APIs for your Convex code.

App-owned admin RPC

Expose admin operations with your own authMutation/authQuery functions calling the auth.connection.* facade.

The auth.connection.* namespace is a server-side helper API. It is not automatically exposed as client-callable Convex functions just because it exists on the returned object.

If your app wants public group connection admin RPC, expose it explicitly by writing authMutation/authQuery functions that authorize with auth.member.assert and call the auth.connection.* facade — for example in convex/auth/group.ts.

Use Convex-native args on those wrappers: { id } for primary IDs, { connectionId } for foreign-key scoped operations, { data } for create/update payloads, and paginationOpts for unbounded lists.