AI Passport developer docs

For agents

Connect hosted apps and personal agents, discover capabilities, and read owner-approved memory and live data.

AI Passport has three connection paths. Choose the one that fits where your agent runs. The owner's approval always governs what the connected app can read.

For a hosted app, use redirect sign-in with a Client Identifier Metadata Document (CIMD). Install ai-passport-signin, host the document on your app's HTTPS host, and use its URL as client_id. The SDK handles the server-side begin and callback routes.

For a personal or headless agent without a public host, use device authorization. This includes any agent whose OAuth callback would land on localhost or 127.0.0.1: browser sign-in refuses unverified loopback clients with unauthorized_client. No public tunnel, metadata host, or callback route is needed. The agent shows a code and the owner approves it while signed in on my.ego.ist. A caller-chosen agent name is shown as unverified.

For an agent with an owner-minted connect code, redeem that code once. The five families are openclaw, hermes, opencode, muse, and other. Use other for any agent and provide its own name; the owner sees it as unverified. The muse family is displayed as Muse.

Sign-in is generally available. Admission for host-consistent metadata-document clients is automatic. Every non-loopback redirect host must equal the metadata document host or be a strict subdomain. Loopback redirect URIs are exempt. Non-host-consistent clients need manual review; deprecated DCR clients need manual admission. Admission confirms domain control only and grants no memory or connector pass. The contract changes only with notice on the changelog.

Connect a personal agent

Device authorization follows RFC 8628. Fetch discovery from https://passport.ego.ist/.well-known/openid-configuration; it advertises device_authorization_endpoint and the device-code grant type. The SDK's createDevicePairing helper implements this flow, or use curl and jq below. Run these commands in a private local shell with tracing disabled.

Begin pairing

PAIRING=$(curl --fail-with-body -sS \
  -X POST https://passport.ego.ist/oauth/device_authorization \
  -H 'content-type: application/json' \
  -d '{"client_name":"Hana","scope":"openid memory"}')
DEVICE_CODE=$(printf '%s' "$PAIRING" | jq -er '.device_code')
CLIENT_ID=$(printf '%s' "$PAIRING" | jq -er '.client_id')
USER_CODE=$(printf '%s' "$PAIRING" | jq -er '.user_code')
VERIFY_URL=$(printf '%s' "$PAIRING" | jq -er '.verification_uri_complete')
INTERVAL=$(printf '%s' "$PAIRING" | jq -er '.interval')

Send a client_name of 1 to 64 characters for a new pairing. The optional client_id is accepted only for a client id that an earlier device pairing returned. Every device-paired agent is shown to the owner as unverified. The name is self-asserted, not proof of the agent's identity. Retain the returned client id for polling. Scopes are a subset of openid profile email memory, defaulting to openid memory. Purpose scopes booking:actions and connector:reads are unavailable through this grant.

Show the owner the code

printf 'Open %s and check that the code is %s\n' "$VERIFY_URL" "$USER_CODE"

Tell the owner: open the link while signed in to my.ego.ist, check that the agent name and code match this pairing, and choose Allow or Deny. The code is formatted XXXX-XXXX, expires in 10 minutes, and the base verification URL is https://my.ego.ist/device. The complete URL adds ?code=.

The owner page warns that a caller-chosen name is unverified. Ask the owner to confirm that pairing started from their own agent. Never approve the pairing on the owner's behalf or ask for their Passport password.

Poll for the decision

Wait at least the returned interval (normally 5 seconds) before each poll. This command performs one poll and keeps the token response out of output:

sleep "$INTERVAL"
TOKEN_RESPONSE=$(curl -sS -X POST https://passport.ego.ist/token \
  -H 'content-type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \
  --data-urlencode "device_code=$DEVICE_CODE" \
  --data-urlencode "client_id=$CLIENT_ID")
printf '%s' "$TOKEN_RESPONSE" | jq '{error, token_type, expires_in, scope, mcp_url}'

Repeat only while pending, respecting the interval and the response below. Use createDevicePairing().waitForApproval() for an automatic polling loop.

ErrorAgent action
authorization_pendingKeep waiting and poll at the current interval
slow_downAdd 5 seconds to the interval for this and all subsequent polls
access_deniedStop; start again only after a new owner request
expired_tokenStop; begin a new pairing if the owner still wants to connect
invalid_grantStop; the device code or client binding is invalid or already consumed

Success returns the normal access and refresh token response plus mcp_url. When openid was granted, id_token carries at_hash and the passport claim. Verify the signature through JWKS, issuer, audience, expiry, and access token hash before trusting identity claims. Device grants have no nonce. ai-passport-signin/server performs these checks for you.

Store tokens in the agent's secure credential store. Keep device codes and tokens out of logs, source control, chat output, and browser storage. Refresh at https://passport.ego.ist/token and atomically replace the token pair.

Redeem a connect code

The owner mints a one-time code on my.ego.ist under Assistants or the install step in onboarding. It expires in 10 minutes and works once. Redeem it with JSON, using the family the owner selected:

CONNECT_RESPONSE=$(curl --fail-with-body -sS \
  -X POST https://passport.ego.ist/connect-code/redeem \
  -H 'content-type: application/json' \
  -d '{"code":"XXXX-XXXX","app":"other","client_name":"Hana"}')

The response has this shape. All token values below are placeholders:

{
  "mcp_url": "https://passport.ego.ist/mcp",
  "access_token": "ACCESS_TOKEN",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "REFRESH_TOKEN",
  "scope": "memory",
  "client_id": "YOUR_CLIENT_ID",
  "token_url": "https://passport.ego.ist/token"
}

Use muse for Muse, or other with client_name for any other personal agent. OpenClaw, Hermes, and OpenCode retain their named families. A connect code grants the memory scope, not an OpenID identity token or a category pass. Store and refresh its tokens with the same care as device-flow tokens.

After connecting

Discover capabilities first

Connect an MCP client to https://passport.ego.ist/mcp with the memory-scoped bearer and call passport_status before the first recall:

const status = await client.callTool({ name: "passport_status", arguments: {} });
const capabilities = status.structuredContent;

The response includes a text summary plus structured scopes, the exact client id and verification status, memory state and categories, this app's memory passes, enabled connectors, linked connector slugs, and connector passes. memory.passes_known and connectors.passes_known are false when that pass lookup failed. An empty list with passes_known: true means no active passes. It also links to the owner's inbox, connectors page, and memory lock page. See the complete response shape.

These fields show a successful empty memory-pass lookup and an unavailable connector-pass lookup:

{
  "memory": { "passes": [], "passes_known": true },
  "connectors": { "passes": [], "passes_known": false }
}

linked_known: false means the connector lookup failed, not that none are linked.

Read the verified passport claim too. memory_access says whether the token may ask for memory. Optional memory_locked is true only when the owner must unlock once before any app can read. Optional connectors lists linked slugs. Both fields are absent without memory or when their lookup did not finish in time. Missing values mean unknown. /userinfo follows the same rule.

Read live sources through Passport

The MCP recall tool reads live connector data through its connectors parameter. Get enabled connector names and data categories from passport_status or the tool schema; do not invent slugs or category names. For example, after confirming Google Calendar is enabled and linked:

await client.callTool({
  name: "recall",
  arguments: {
    query: "upcoming meetings",
    connectors: [{ connector: "google-calendar", data_category: "calendar.events" }],
  },
});

Follow the current tool schema for category arguments. The structured HTTP endpoint POST /memory/v1/recall reads governed memory only, never live connector data. Prefer Passport connectors for calendar, mail, code, and fitness when the owner's Passport exposes those sources. Do not default to your own native connector and ask the owner to connect the same source again.

Honor passes and recall outcomes

Owners may grant category passes when they connect your app. These passes let a first recall serve approved memories without an approval round trip. Each pass belongs to your app, one category, and the recall purpose. It stays active until the owner revokes it on the Passes page. Unselected categories still require approval.

A bare MCP recall, with no categories, connectors, or partner workspaces, uses the memory categories for which this app holds active passes. If it holds none, recall returns guidance without an error and creates no approval request. Call recall again naming the categories you need so the owner can review the request in their inbox.

If Passport cannot check the passes, recall says so without an error and asks you to name the categories on your next call. That guidance does not mean this app has no passes. Already approved categories can still serve through the governed read.

A sealed Passport that needs the owner to unlock returns a notice without an error. Relay that notice and its unlock link to the owner. If a connector also fails, recall returns an error with both the unlock notice and connector retry text. Temporary custody outages remain retryable errors. Governed memory reads retry a temporary engine outage once before returning an error.

A pass names the exact app, category, controlled purpose, and duration. Durations can be one-time, session, or permanent. The owner can configure rules that auto-approve requests. Approval still does not authorize another app, category, or purpose. Connector passes and protected-memory approvals remain separate from normal-memory category passes. Revocation takes effect on subsequent reads, and expiry never silently becomes permanent access.

State or outcomeWhat to do
Missing pass or approval_requiredShow the exact approval link, ahead of any unlock guidance
Custody temporarily unavailable or unavailableRetry in a few seconds; do not ask for a whole-vault unlock
sealed_owner_unlock_requiredShow unlock_url so the owner can unlock once
sealed_auto_unlockUse this app's passes for automatic scoped access
openNo memory lock; passes still apply
unknownRetry status discovery; do not infer an empty Passport
Successful empty recallExplain that this search found no matching approved content

Approval notices remain visible when another category is locked. Structured recall gives top-level approval_required priority over locked; a locked category may carry unlock_url. Only the owner-unlock state needs that link. A temporary custody outage is retryable and does not mean a pass was revoked. New memory writes are proposals in the owner's inbox until approved, and approval does not grant this agent read access.

Install prompt

Paste this into a coding agent building a hosted app:

Add AI Passport sign-in to this app with ai-passport-signin.
Use the official browser button or React wrapper with the visible label
"Sign in with AI Passport" or "Continue with AI Passport".
Host an HTTPS client metadata document on this app's host. Use its exact URL
as client_id. Include client_id, client_name, redirect_uris, and
token_endpoint_auth_method set to none. Do not use a client secret.
Admission for host-consistent metadata-document clients is automatic. Each
non-loopback redirect host must equal the document host or a strict subdomain.
Loopback redirects are exempt. Other host relationships need manual admission.
Create server-side begin and callback routes with ai-passport-signin/server.
Keep state and PKCE data in the user's server-side session. Complete with the
returned code, state, iss, and stored state. Keep tokens out of browsers and logs.
Request memory and its MCP resource only when the app needs Passport context.
Test with https://passport.ego.ist/.well-known/openid-configuration.
After memory sign-in, call passport_status first and inspect passes and linked
connectors. Use recall with connectors for live data. Show approval links before
unlock guidance, retry temporary custody failures, and honor owner decisions.
Read https://ego.ist/docs/sign-in for the full contract.

Prompt for a personal agent

Connect yourself to my AI Passport using device authorization. Read
https://ego.ist/docs/agents and fetch discovery from
https://passport.ego.ist/.well-known/openid-configuration.
Use your own client_name, shown to me as unverified, and request openid memory.
Begin at the discovered device authorization endpoint. Show me the user code
and verification URL. Tell me to check your name and the code while signed in
to my.ego.ist, confirm I started this pairing, and choose Allow or Deny.
Poll the token endpoint at the returned interval. Add 5 seconds on slow_down.
Stop on denial or expiry. Never approve for me. Verify any ID token, including
its at_hash binding. Store tokens securely and keep them and device codes out
of chat, logs, source control, and browser storage. Rotate refresh tokens.
After approval, connect to the returned mcp_url and call passport_status first.
Inspect memory state, this app's passes, and enabled and linked connectors.
Prefer Passport connectors for calendar, mail, code, and fitness. Call recall
with connectors and categories from the status response or tool schema.
Show pass approval links before any unlock guidance. Retry a temporary custody
failure in a few seconds. Ask me to unlock only when Passport returns an owner
unlock state. Treat unavailable data as unknown, never as an empty Passport.

Machine-readable surfaces

Task checklist

  1. Choose hosted sign-in, device authorization, or an owner-minted connect code.
  2. Keep the exact client identity and requested scopes throughout the flow.
  3. Show pairing details and let the owner decide on my.ego.ist.
  4. Verify ID tokens when present and store credentials securely.
  5. Call passport_status first and inspect this app's passes and linked sources.
  6. Use MCP recall for live sources and preserve approval and outage outcomes.
  7. Verify denial, expiry, refresh rotation, and revocation before relying on it.

Read Sign in with AI Passport for the complete protocol contract.

On this page