Magic Link
A signed URL your agent (or your backend) can hand to the user for authentication.
Magic Link is a signed URL the user opens in their own browser to authenticate a Connector. The user clicks, completes OAuth at the third party, lands either back in your app (via a callback URL) or on a generic “you’re done” page, and credentials are stored against their Registered User.
Magic Link vs embedded Link
Both flows produce the same outcome but apply in different contexts.
Use embedded Link when you can. Use Magic Link when you can’t render the component - most commonly when the auth needs to happen in a different browser session than where the user got the link.
Generating a Magic Link
Backend call. Hit the same /link-token endpoint as embedded Link; the response includes a magic_link_url you can hand to the user.
Send magic_link_url to the user - email, chat message, in-app notification, the body of an agent response. They open it in any browser, complete OAuth, and the credential is stored.
At-runtime via the agent
When the agent calls a tool the user hasn’t authenticated, the Connector returns an authenticate_meta payload that includes the Magic Link URL ready to share:
The message field is written for the agent - the model can include it verbatim in its reply to the user. The user clicks the link, authenticates, and the agent’s next attempt at the same tool succeeds.
Callback URLs
Without a callback URL, the user lands on a generic “authentication complete” page after auth. With one, they’re redirected back to your app.
Set up:
- Register the origin. At Settings → API Keys → Allowed callback origins, add the origin (scheme + host) of your callback URL. Origins must be HTTPS for web; custom schemes (
myapp://,tauri://) are allowed for mobile and desktop apps. - Pass
callback_urlwhen minting the token.
After the user authenticates (or exits), the browser redirects to your callback URL with query parameters appended:
Don’t append your own ?state= to the callback URL - Agent Handler appends it for you. Doubled-up query parameters break the flow.
Mobile and desktop deep links
Same flow, custom URL scheme. Register myapp:// as an allowed origin, pass callback_url: "myapp:///integrations/done". After authentication the browser redirects to that scheme, your OS routes it to your app, your app reads the status parameter.
Authorization code exchange (for server-to-server flows)
By default, credentials are stored the moment the user finishes authenticating in the browser. For higher-security flows - most common with mobile and desktop apps where the browser session and your backend are different processes - you can require a server-to-server step before the credential is created.
The flow:
-
Mint the link token with both
callback_urlandstate. The presence ofstatetriggers authorization code mode. -
The user authenticates. The callback URL is hit with
status=success&code=ah_code_xyz&state=random-csrf-token-123. The credential is not yet stored. -
Validate
state. It should match the value you minted with. If not, abort - this is a CSRF attempt. -
Exchange the code from your backend. Hit the confirmation endpoint with the code. Agent Handler creates the credential and returns the IDs.
Codes expire after 5 minutes. They’re single-use. They can only be exchanged by the same organization that minted them.
The state-and-code dance is OAuth’s standard CSRF protection: the redirect comes from the user’s browser, but the code exchange comes from your backend. Even if an attacker hijacks the redirect, they can’t redeem the code without the API key.
When to use code exchange
- Mobile and desktop apps. The browser flow and the app are separate processes; code exchange lets the app verify the auth before trusting it.
- Compliance. Some security reviews want server-to-server credential creation as a hard requirement.
- Pre-credential validation. You want to check the user’s identity in your own system before the credential is created on Agent Handler’s side.
For simpler web flows where the user authenticates and closes the tab, omit state - credentials are created immediately, no exchange step needed.
Errors during code exchange
Treat all of these as terminal - re-mint a fresh link token and start over.
Next
Brand the Link experience with your logo and colors via Link customization.