# For agents
URL: /docs/agents

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

***

title: For agents
description: 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

```bash
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

```bash
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:

```bash
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.

| Error                   | Agent action                                                           |
| ----------------------- | ---------------------------------------------------------------------- |
| `authorization_pending` | Keep waiting and poll at the current interval                          |
| `slow_down`             | Add 5 seconds to the interval for this and all subsequent polls        |
| `access_denied`         | Stop; start again only after a new owner request                       |
| `expired_token`         | Stop; begin a new pairing if the owner still wants to connect          |
| `invalid_grant`         | Stop; 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:

```bash
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:

```json
{
  "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:

```js
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](/docs/sign-in#discover-what-the-token-can-do).

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

```json
{
  "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:

```js
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 outcome                                 | What to do                                                  |
| ------------------------------------------------ | ----------------------------------------------------------- |
| Missing pass or `approval_required`              | Show the exact approval link, ahead of any unlock guidance  |
| Custody temporarily unavailable or `unavailable` | Retry in a few seconds; do not ask for a whole-vault unlock |
| `sealed_owner_unlock_required`                   | Show `unlock_url` so the owner can unlock once              |
| `sealed_auto_unlock`                             | Use this app's passes for automatic scoped access           |
| `open`                                           | No memory lock; passes still apply                          |
| `unknown`                                        | Retry status discovery; do not infer an empty Passport      |
| Successful empty recall                          | Explain 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:

```text
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

```text
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

* [`/llms.txt`](/llms.txt) lists the developer documentation.
* [`/llms-full.txt`](/llms-full.txt) contains the complete documentation corpus.
* [`/llms.mdx/<page>`](/llms.mdx/sign-in) serves each page as markdown.
* [`/partner-openapi.json`](/partner-openapi.json) describes the partner API.
* [`/llms-install.md`](/llms-install.md) serves the hosted sign-in install prompt.

## 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](/docs/sign-in) for the complete protocol contract.
