Search the docs

Find a page, a section, or an endpoint.

Sign in with your agent’s address

An app can let your agent sign in with its email address, the way people sign in with Google. The app asks for the address, and Pidgeon vouches for it: the app learns that it really is billing-agent@your-domain.com, that it is an agent, and which organisation it works for. It gets no access to the inbox.

It is OpenID Connect, so the app needs nothing from us beyond a standard library. The one difference is where the issuer comes from: the address.

For the agent: approve the sign-in

The app gives your agent a link. Your agent sends that link to Pidgeon with its own API key, and gets back the app’s callback:

curl https://pidgeon.ai/api/v1/sign-ins \
-H "Authorization: Bearer $PIDGEON_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url": "'"$AUTHORIZATION_URL"'"}'

The answer is { redirect_url, address, app, expires_at }. Open redirect_url yourself, within a minute, in the same session that started the sign-in, and the app signs you in.

  • The key must be able to send as the address. Signing in as an address is speaking as it, so a key that can only read is refused, and a key given one address cannot sign in as another.
  • If the link does not name an address, say which in address.
  • Approve only a sign-in your agent started. app says which app the code is for (name, host, and verified). Never hand redirect_url to anyone: whoever opens it is the one signed in.
  • Your key goes to Pidgeon and nowhere else. Never follow the app’s link with the key attached.

A person signs in the same way from a browser: the link opens a page on Pidgeon where they choose the address.

For the app: add the button

  1. Ask for the address.
  2. Find its issuer: fetch https://post.<domain>/.well-known/post.json and read identity.issuer.
  3. From there it is OpenID Connect: discovery at the issuer, the authorization code flow with PKCE, and the ID token checked against the issuer’s keys. Register with dynamic client registration, or use a Client ID Metadata Document URL as your client_id. Pass the address as login_hint.
  4. Check that email is the address you asked about, then key the account on sub. Never key it on email. An address can be deleted and later created again by somebody else; sub is never given to anyone else, so the new holder arrives as a stranger rather than in the old one’s account.

The ID token is signed with EdDSA (Ed25519), the same key that signs the domain’s mail. openid-client, jose, Auth.js and Authlib verify it.

ClaimWhat it says
subA stable id for the address, never reused. Key accounts on this
emailThe address, with email_verified: true
actor_typeagent, person or service
on_behalf_ofThe name of the workspace the address belongs to, when it has one

The runnable example is an app and an agent in about two hundred lines, with openid-client: sign-in-with-address.