There are two ways to integrate Agentcard:
- API key (
sk_test_/sk_live_) — your org acts as itself, server-to-server, against the REST API. See the Integration Guide.
- OAuth (this page) — your users connect their own Agentcard account to your app with a “Connect with Agentcard” button. Your app then acts on each user’s behalf, scoped to the cards it creates for them.
Use OAuth when end users bring their own Agentcard account. You do not need an API key for this flow.
How it works
Agentcard’s MCP host (https://mcp.agentcard.sh) is a full OAuth 2.1 authorization server (authorization-code + PKCE, with a hosted magic-link + consent screen).
Your app ──(1) Connect button──▶ /authorize ──▶ magic-link + consent (hosted)
▲ │
└──(4) tokens◀── /token ◀──(3) ?code=… redirect ◀─────────┘ (2) user approves
- Your app redirects the user to
/authorize with PKCE.
- The user verifies by email and approves on Agentcard’s hosted screen.
- Agentcard redirects back to your
redirect_uri with an authorization code.
- Your app exchanges the code for an access token (+ refresh token) at
/token, and uses it as a Bearer token against https://mcp.agentcard.sh/mcp.
Discover the exact endpoints at any time:
curl https://mcp.agentcard.sh/.well-known/oauth-authorization-server
1. Register a client
Pin a stable OAuth client for your app with the admin CLI:
agent-cards-admin oauth-clients create \
--org <your-org-id> \
--name "Kilo" \
--redirect-uri "https://app.kilo.ai/api/integrations/agentcard/callback"
This returns a client_id. It is a public client (PKCE, no secret) — pin it in your app’s environment:
AGENTCARD_OAUTH_CLIENT_ID=<client_id>
You can also let your app self-register at runtime via POST /register (dynamic
client registration). That mints a new client_id each call, which fragments
the per-connection card scope below — so for production prefer a single pinned
client created with the admin CLI.
The --name you set is shown to users on the consent screen and in their connected apps list.
2. Authorize
PKCE: generate a code_verifier, derive code_challenge = base64url(sha256(verifier)), and redirect the user:
https://mcp.agentcard.sh/authorize
?response_type=code
&client_id=<client_id>
&redirect_uri=<your callback>
&code_challenge=<code_challenge>
&code_challenge_method=S256
&state=<signed state you can verify on return>
Keep the code_verifier recoverable on the callback (e.g. in a signed state
or a server-side session), and bind state to the initiating user to prevent CSRF.
Agentcard renders the email + consent screen; you build none of it.
3. Exchange the code
On the callback, exchange code + code_verifier for tokens:
curl -X POST https://mcp.agentcard.sh/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d grant_type=authorization_code \
-d code=<code> \
-d redirect_uri=<your callback> \
-d client_id=<client_id> \
-d code_verifier=<code_verifier>
Response: { access_token, refresh_token, expires_in, token_type }. Store both
tokens encrypted.
4. Use and refresh the token
Call the MCP server with the access token:
Authorization: Bearer <access_token>
Access tokens are short-lived (~1 hour). Refresh before expiry with the
refresh token — a one-time exchange is not enough for a long-running integration.
curl -X POST https://mcp.agentcard.sh/token \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d grant_type=refresh_token \
-d refresh_token=<refresh_token> \
-d client_id=<client_id>
Card isolation
An OAuth connection is isolated to the cards it creates. A token issued to
your client can only list, read, and close cards that were created through that
same client for that user. It cannot see or modify:
- the user’s personal cards (created via the CLI, dashboard, or another app), or
- cards belonging to a different connected app, or
- any other user’s cards.
This is enforced server-side by the card’s owning client_id, so your
integration only ever operates within its own sandbox of that user’s account.
What the user sees and controls
Users can review and revoke the apps they’ve connected with the
connections command:
agent-cards connections # list connected apps
agent-cards connections revoke <clientId> # revoke an app
Revoking immediately invalidates that app’s tokens.