Using with Clerk
How to authenticate AI agents with Clerk — map verified agent tokens to Clerk users and enable agent signups.
AgentOnboard does not replace Clerk. Clerk handles your human users in the browser; AgentOnboard handles AI agents calling your API.
When an agent presents a 5-minute verified token, you read the verified email and look up the corresponding Clerk user.
1. Verifying existing Clerk users
Use the Clerk Backend SDK inside resolveAccount to find the user by their verified email:
import { clerkClient } from "@clerk/nextjs/server";
import { requireAgentAccount } from "@agentonboard/sdk/next";
export async function POST(request: Request) {
const client = await clerkClient();
const session = await requireAgentAccount(request, {
audience: "notes.com",
resolveAccount: async ({ email }) => {
// Find the Clerk user with this verified email
const users = await client.users.getUserList({
emailAddress: [email.toLowerCase()],
});
return users.data[0]?.id ?? null;
},
});
// Returns 401 (expired/invalid) or 403 (no Clerk account found)
if (!session.ok) return session.response;
// session.user is the Clerk User ID (e.g. user_2abc...)
return Response.json({ success: true, clerk_user_id: session.user });
}If the email isn't in Clerk, the SDK automatically returns 403 ACCOUNT_REQUIRED, prompting the agent to instruct the user to sign in to your product.
2. Enabling agent signup with Clerk
If you want agents to automatically provision accounts for new users, use createAgentAccount in an explicit signup handler:
import { clerkClient } from "@clerk/nextjs/server";
import { createAgentAccount } from "@agentonboard/sdk";
export async function POST(request: Request) {
const client = await clerkClient();
const outcome = await createAgentAccount({
token: request.headers.get("Authorization") ?? "",
audience: "notes.com",
resolveAccount: async ({ email }) => {
const users = await client.users.getUserList({
emailAddress: [email.toLowerCase()],
});
return users.data[0]?.id ?? null;
},
createAccount: async ({ email }) => {
// Provision the user in Clerk without requiring a password
const newUser = await client.users.createUser({
emailAddress: [email.toLowerCase()],
skipPasswordRequirement: true,
});
return newUser.id;
},
});
if (!outcome.ok) {
return Response.json(
{ code: outcome.code, error: outcome.error },
{ status: outcome.code === "RESOLVER_ERROR" ? 500 : 401 },
);
}
return Response.json(
{ user_id: outcome.user, created: outcome.created },
{ status: 201 },
);
}Why skipPasswordRequirement works
AgentOnboard already verified the human's email inbox before issuing the token. When creating the user in Clerk, you set skipPasswordRequirement: true so the agent can immediately start using your API without getting stuck on a password prompt.