Embedded identity
Bind MCP authorization to a customer-verified end user without trusting agent-supplied identity.
An Embedded project keeps your application's users separate from Arc0 dashboard accounts. Your backend establishes the mapping after authenticating the person in your own product. An email match, agent argument, or account picker is not proof of that identity.
Server-side connection management
Keep management API keys on your server. Create a connection link with POST /v1/connect,
connect permission, and the Arc0 endUserId resolved from your authenticated session.
The returned ten-minute capability opens Arc0 Connect. The provider
credential belongs to that user. This link is a connection setup capability, not a general
management session or permission to browse other users' connections.
Link an MCP OAuth authorization
The linking contract connects a signed MCP OAuth request, an authenticated Arc0 browser session and your independently authenticated end user:
- In the Arc0 consent browser,
POST /v1/mcp/link-requestson the core/auth base URL with the session cookie and{ organizationId, projectId, oauth_query }. The unchangedoauth_querycomes from the signed OAuth request. The result is{ requestId, expiresIn: 300 }. - Your backend authenticates the person in your application and resolves their Arc0 user ID.
It calls
POST /v1/mcp/authorization-ticketson the API base URL with a server-side management key carryingmcp:link, and{ requestId, endUserId }. The result is{ ticket, requestId, expiresIn: 300 }. Do not accept the end-user ID directly from the browser. - After explicit confirmation in the same Arc0 browser session, call
POST /v1/mcp/link-confirmon the core/auth base URL with{ oauth_query, ticket, confirm: true }. The ticket is consumed once and returns the linked{ organizationId, projectId, endUserId, bindingId }. - The consent flow selects that linked context through
POST /v1/mcp/authorizeand completes the OAuth authorization. The resulting MCP token is bound to that subject; tool calls cannot replace it with anendUserIdargument.
Browser requests require the session and trusted Origin. Preserve the signed OAuth query verbatim; do not reconstruct its client, redirect URI or PKCE parameters. Tickets expire with their request and are bound to the original browser session and OAuth request. Treat them as secrets, send them over HTTPS, and keep them out of logs.
The issuing key must remain enabled and owned by an authorized administrator. Arc0 rechecks that authority and the linked subject on subsequent access. Relinking a conflicting identity requires an explicit new authorization instead of silently changing an existing grant.
This is the implemented integration contract. A general hosted Embedded connection-management portal is separate work; these tickets do not grant such a session. Direct accounts use their own Arc0 identity and do not use Embedded linking tickets.
Runtime keys when OAuth is unavailable
Your backend can mint a short-lived, user-bound key with
POST /v1/users/:endUserId/keys on the API base URL. Authenticate with a server-side
Embedded management key carrying mcp:keys and every permission requested for the child.
Resolve the end-user ID from your application's authenticated session.
{
"name": "Headless agent",
"permissions": ["execute"],
"expiresIn": 3600
}The response is { id, key, endUserId, expiresIn }; store the returned secret securely.
Only execute and connect may be delegated. The lifetime is 60–86,400 seconds;
the default is one hour. If permissions are omitted, both execute and connect are
requested, so the parent must hold both. A child key cannot mint more keys or act as a
management key.
Use the child key as x-api-key for MCP, or as a Bearer API key for REST. MCP tool use
requires execute; hosted connection creation additionally requires connect.
The subject is fixed, and the child stops working if the parent expires, is revoked,
loses required permissions, or its owner loses administrative authority. Arc0 rechecks
these conditions for subsequent requests and approval resumption. Keep the broad parent
key on your server; give only the user-bound child key to the agent.