How to let users approve AI agents without leaving your app
When an AI agent registers to act on someone's behalf, a real person has to confirm it. Here's how to show that confirmation screen in your own product instead of redirecting users to a hosted page.
Say an AI agent wants to act on behalf of one of your users, reading their data, taking actions in your product, whatever it's built to do. Before that agent gets real access, WorkOS requires a moment of human confirmation: the agent is shown a short code, a person confirms it belongs to them, and only then does the agent's access get upgraded from limited to trusted. That confirmation step is called the claim ceremony.
By default, that confirmation happens on a page hosted by AuthKit: the user gets a link, opens it, signs in, and sees the code there. That works well out of the box. But if your product already has its own sign-in experience, sending a user away to a different domain mid-task is a seam. They're mid-conversation with an agent, and suddenly they're bounced somewhere else, with different styling, before landing back where they started. It's a small thing, but it's the kind of small thing that shows up in onboarding drop-off numbers.
You can remove that seam. You still rely on WorkOS for the underlying claim, but the confirmation screen, the part the user actually sees, can live entirely inside your own app.
What changes, and what doesn't
The claim ceremony has three moving parts: the agent starts a claim attempt, a human confirms it, and the agent completes the claim with a short code. The standalone version only touches the middle part.
Same as before:
- The agent starts a claim attempt and gets back a
claim_token. - The agent submits a
user_codeto complete the claim.
Different:
- Instead of the user opening a
verification_urion a hosted AuthKit page, your own backend calls an admin API endpoint to link the user to the claim attempt. - Your backend gets the
user_codeback directly, and your frontend displays it, in your own UI, in your own styling.

Turning it on
In the WorkOS Dashboard, under Authentication → Agents → Configuration → Claim flow page, set a custom page URI.

Once that's set, agents' claim attempts point users at your URI instead of the default AuthKit claim page. That's the only dashboard change. The rest is a backend call.
Linking the user
When the agent starts a claim attempt, it gets back a claim_token. Your backend takes that token, plus the identity of the user who's already signed into your app, and calls the admin API:
external_id is however you identify the user in your own system. If no WorkOS user exists with that ID yet, one gets created for you. If a user with that ID already exists and the email you passed doesn't match, the call is rejected, which is the safety net that keeps a claim from accidentally attaching to the wrong account.
The response is what your frontend has been waiting for:
Show user_code in your UI, in whatever component makes sense for your product, a modal, a banner, an inline card in the chat thread. The user reads it back to the agent, the agent submits it, and the claim completes exactly as it would in the hosted flow.
Handling multiple organizations
If the user belongs to more than one organization, you need to tell WorkOS which one the agent should act within. Pass organization_id:
If you leave organization_id out and the user belongs to multiple organizations, the API returns a 409 with code organization_selection_required, along with the list of organizations the user can pick from. That's your cue to show an org picker before you retry the call, the same UX moment you'd design for anywhere else in your product.
The rule you can't skip
This is the part worth repeating, since it's easy to gloss over: your application must authenticate the user before displaying the user_code.
The hosted AuthKit page signs the user in as its first step, before it ever shows them a code. When you move that step into your own UI, that responsibility moves with it. WorkOS still checks that the email you pass matches the email already bound to the claim attempt, but it has no way to verify that the person looking at your screen is actually that user. If your UI would show a user_code to an unauthenticated visitor, anyone who can load that page could claim the agent for themselves.
In practice, this just means: put this behind whatever auth check already gates the rest of your signed-in product. If a user is looking at their dashboard, they're already authenticated, and revealing the code there is fine. Don't add a new unauthenticated route for it.
Why bother
The mechanics here are simple on purpose, one PATCH call and a UI you already control. The value isn't in the API surface, it's in what it removes: a redirect to a different domain, a different visual identity, and a moment where the user has to trust that the page they just landed on is legitimately yours. For a flow that's already asking someone to vouch for an AI agent, keeping that trust inside a product they already recognize is worth the small amount of backend work.
For a full walkthrough of setting up Agent Registration from scratch, discovery, registration, and the credential exchange, see our tutorial on onboarding AI agents. For the full reference on the claim attempt API and organization selection, see the Agent Registration docs.