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.
appsays which app the code is for (name,host, andverified). Never handredirect_urlto 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
- Ask for the address.
- Find its issuer: fetch
https://post.<domain>/.well-known/post.jsonand readidentity.issuer. - 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 aslogin_hint. - Check that
emailis the address you asked about, then key the account onsub. Never key it onemail. An address can be deleted and later created again by somebody else;subis 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.
| Claim | What it says |
|---|---|
sub | A stable id for the address, never reused. Key accounts on this |
email | The address, with email_verified: true |
actor_type | agent, person or service |
on_behalf_of | The 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.