ワンクリックで
source-command-convex-auth-setup
Set up or extend authentication patterns in this Convex + Better Auth project
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Set up or extend authentication patterns in this Convex + Better Auth project
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Set up Convex authentication with proper user management, identity mapping, and access control patterns. Use when implementing auth flows.
Guide to using Convex components for feature encapsulation. Learn about sibling components, creating your own, and when to use components vs monolithic code.
Discover and use convex-helpers utilities for relationships, filtering, sessions, custom functions, and more. Use when you need pre-built Convex patterns.
Create Convex queries, mutations, and actions with proper validation, authentication, and error handling. Use when implementing new API endpoints.
Plan and execute Convex schema migrations safely, including adding fields, creating tables, and data transformations. Use when schema changes affect existing data.
Design and generate Convex database schemas with proper validation, indexes, and relationships. Use when creating schema.ts or modifying table definitions.
| name | source-command-convex-auth-setup |
| description | Set up or extend authentication patterns in this Convex + Better Auth project |
Use this skill when the user asks to run the migrated source command convex-auth-setup.
This project uses Better Auth with the Convex plugin for authentication. Use this guide when implementing auth flows, access control, or user management.
convex/auth.ts - authComponent client + createAuth() factorylib/auth-client.ts - Better Auth React client with convexClient() pluginapp/ConvexClientProvider.tsx - Wraps app with ConvexBetterAuthProviderconvex/http.ts - Auth routes at /api/auth/*middleware.ts - Protects /dashboard routesAlways use authComponent.getAuthUser(ctx) from convex/auth.ts:
import { authComponent } from "./auth";
export const myQuery = query({
args: {},
returns: v.null(),
handler: async (ctx) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
// user is now available with full type safety
return null;
},
});
For consistent auth enforcement, create custom function wrappers using convex-helpers:
// convex/lib/customFunctions.ts
import {
customQuery,
customMutation,
} from "convex-helpers/server/customFunctions";
import { query, mutation } from "../_generated/server";
import { authComponent } from "../auth";
export const authedQuery = customQuery(query, {
args: {},
input: async (ctx, args) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
return { ctx: { ...ctx, user }, args };
},
});
export const authedMutation = customMutation(mutation, {
args: {},
input: async (ctx, args) => {
const user = await authComponent.getAuthUser(ctx);
if (!user) throw new Error("Not authenticated");
return { ctx: { ...ctx, user }, args };
},
});
Then use throughout:
export const getTasks = authedQuery({
args: {},
returns: v.array(
v.object({
/* ... */
}),
),
handler: async (ctx) => {
return await ctx.db
.query("tasks")
.withIndex("by_userId", (q) => q.eq("userId", ctx.user._id))
.collect();
},
});
export const updateTask = authedMutation({
args: { taskId: v.id("tasks"), text: v.string() },
handler: async (ctx, args) => {
const task = await ctx.db.get(args.taskId);
if (!task) throw new Error("Task not found");
if (task.userId !== ctx.user._id) throw new Error("Unauthorized");
await ctx.db.patch(args.taskId, { text: args.text });
},
});
import { customQuery } from "convex-helpers/server/customFunctions";
export const adminQuery = customQuery(authedQuery, {
args: {},
input: async (ctx, args) => {
if (ctx.user.role !== "admin") throw new Error("Admin access required");
return { ctx, args };
},
});
export const teamQuery = customQuery(authedQuery, {
args: { teamId: v.id("teams") },
input: async (ctx, args) => {
const membership = await ctx.db
.query("teamMembers")
.withIndex("by_teamId_and_userId", (q) =>
q.eq("teamId", args.teamId).eq("userId", ctx.user._id),
)
.unique();
if (!membership) throw new Error("Not a team member");
return {
ctx: { ...ctx, teamId: args.teamId, role: membership.role },
args,
};
},
});
// Public - no auth required
export const listPublicPosts = query({
handler: async (ctx) => {
return await ctx.db
.query("posts")
.withIndex("by_published", (q) => q.eq("published", true))
.collect();
},
});
// Private - requires auth
export const listMyDrafts = authedQuery({
handler: async (ctx) => {
return await ctx.db
.query("posts")
.withIndex("by_authorId", (q) => q.eq("authorId", ctx.user._id))
.collect();
},
});
convex/auth.ts and lib/auth-client.tsauthComponent.getAuthUser(ctx) for user lookup (not ctx.auth.getUserIdentity() directly)internal.* (not api.*) for scheduled functionsconvex-test using t.withIdentity()