Passport credentials prove a human granted an agent specific, time-bounded permissions — issued from a Secure Enclave, gated by Face ID. Your store verifies them with one HTTP call. No SDK, no keys, no signup.
Three parties, one header, one POST.
The owner approves a scope set in the Passport app — e.g. browse, purchase:general — with Face ID. The credential is signed by a non-extractable Secure Enclave key.
The agent attaches the credential to every request it makes to you:X-Passport-Token: <jwt>
POST the token to the verify endpoint. If valid is true and the scope matches the action, allow it. Otherwise reject with the returned reason.
One endpoint. JSON in, JSON out.
POST https://passport-verify.passport-app.workers.dev/verify
Content-Type: application/json
| Field | Required | Description |
|---|---|---|
token | yes | The JWT from the X-Passport-Token header |
scope | no | Reject if this scope is not in the token (e.g. "purchase:general") |
pin | no | Reject unless the key thumbprint matches — locks verification to owners you already trust |
// 200 — valid
{
"valid": true,
"agent": "Shopping Bot",
"scopes": ["browse", "purchase:general"],
"jti": "f2a1...",
"key": "<thumbprint>",
"expires": 1756376000
}
// 401 — invalid (expired, bad signature, wrong scope, or revoked)
{
"valid": false,
"reason": "Token has been revoked by its owner."
}
Revocation status is also queryable directly: GET /revoked?jti=<jti> → {"revoked": true|false}.
Copy, paste, ship.
app.post('/checkout', async (req, res) => {
const token = req.headers['x-passport-token'];
if (!token) return res.status(401).json({ error: 'No Passport token' });
const check = await fetch('https://passport-verify.passport-app.workers.dev/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, scope: 'purchase:general' }),
}).then(r => r.json());
if (!check.valid) return res.status(401).json({ error: check.reason });
// Proceed — check.agent is the agent name, check.scopes are the grants.
res.json({ ok: true });
});
import httpx
from fastapi import Header, HTTPException
async def verify_passport(x_passport_token: str = Header(None)):
if not x_passport_token:
raise HTTPException(401, "No Passport token")
r = httpx.post(
"https://passport-verify.passport-app.workers.dev/verify",
json={"token": x_passport_token, "scope": "purchase:general"},
)
result = r.json()
if not result["valid"]:
raise HTTPException(401, result["reason"])
return result
curl -X POST https://passport-verify.passport-app.workers.dev/verify \
-H "Content-Type: application/json" \
-d '{"token": "<paste jwt here>", "scope": "browse"}'
No. A Passport credential is a self-contained ES256 JWT with the public key embedded in the header — any JOSE/JWT library can verify it locally. The hosted endpoint is a convenience (signature + expiry + scope check in one call), and you can deploy your own instance of the open Cloudflare Worker.
Credentials are time-bounded and carry a stable jti. Scope checks limit what an accepted token can do, and the pin field lets you accept only key thumbprints you've already trusted. Owners can also revoke a credential instantly from the app — the hosted endpoint checks the revocation list on every verify, and you can query it directly at GET /revoked?jti=<jti>.
From the Passport iOS/macOS app. The signing key is generated in the device's Secure Enclave and every issuance requires Face ID — so each credential reflects an explicit human approval, and the private key never leaves the hardware.
Nothing. The verify endpoint runs on Cloudflare Workers and is free to call.