{"revision":"9f11a31dd2951db0","language":"en","entry":{"id":"sign-in-with-veil","kind":"guide","group":"guides","title":"Sign in with Veil","summary":"Let people sign in to your app with their Veil card. The login is a signature of their device key, and you can check it against the public log yourself.","sections":[{"kind":"paragraph","text":"Sign in with Veil is an OpenID Connect provider with issuer https://veil.rip. Any OpenID Connect library works with the discovery document. The identity is the card: sub is the card's number, the same for the card's whole life."},{"kind":"code","language":"shell","code":"curl -fsS 'https://veil.rip/.well-known/openid-configuration'"},{"kind":"heading","text":"The flow"},{"kind":"steps","items":["Register the app on /developers (a card answers for it, and the consent page says Verified when the card proves the app's domain) or with POST /oidc/register (unverified, 30 days).","Send the browser to /oidc/authorize with the code flow and PKCE S256. PKCE is required for every app, confidential ones too.","On the consent page the person's device key signs a consent text that names your client_id, redirect URI, scopes, nonce, the hash of your state and your code_challenge. That signature is the login. A browser without a card makes one or adds itself, and comes back.","At your redirect URI check state and iss, then exchange the code at /oidc/token with the verifier. Access tokens last 10 minutes; refresh tokens rotate at every use."]},{"kind":"heading","text":"Scopes"},{"kind":"list","items":["openid: the card's number (sub).","profile: the name, the picture, the alias (preferred_username, or u<n>) and the card's address.","veil: veil_version and veil_log (what the login was checked against), veil_good_standing with its reasons, and veil_consent, the signed consent.","veil:accounts: the verified accounts, [{platform, id, handle, url, verified_at}].","veil:orgs: the organisations, [{n, name, role}]. veil:keys: the active device keys and the fingerprints of the public keys from elsewhere."]},{"kind":"paragraph","text":"Your app never gets the person's private key, and there is no password: they have none."},{"kind":"heading","text":"What to verify"},{"kind":"steps","items":["The ID token: the signature with the JWKS key its kid names and that key's alg (EdDSA or ES256; set id_token_signed_response_alg in your library), iss https://veil.rip, aud and azp your client_id, exp, and your nonce. Many libraries skip the signature of a token that comes straight from the token endpoint, so turn the check on (in openid-client, enableNonRepudiationChecks).","Without trusting the server for the login (scope veil): veil_consent.text begins with veil-rubrica:oidc-consent:v1; its JSON names your client_id, your nonce, SHA-256 of your state, your own code_challenge, card equal to sub and key equal to veil_consent.key; its Ed25519 signature verifies with that key.","Against the public log: GET /v1/keys/{key} says which version added the key, and GET /v1/identities/{sub} gives the card's token and its current version. For each version from that one to the current one, GET /v1/identities/{sub}/versions/{v}/proof must hold an entry that names the card's token and the version, chains to the one before, and sits under a checkpoint the log signed and its witnesses cosigned. The first adds the key as a device, none after it revokes the key, and veil_version's entry is at veil_log.index. The guide has the code.","Before you rely on the person now, read userinfo: veil_good_standing turns false at once for a suspension, a takeover window, a closing card or a revoked login key."]},{"kind":"paragraph","text":"CORS covers the discovery document and the JWKS only. A browser app exchanges its code through its own server. API keys play no part here."},{"kind":"heading","text":"Reference"},{"kind":"links","ids":["oidc-discovery","oidc-jwks","oidc-authorize","oidc-token","oidc-userinfo","oidc-revoke","oidc-introspect","oidc-register","oidc-logout","oidc-clients","oidc-client-create","oidc-apps"]}],"related":["api-keys","signed-requests","proofs"],"errors":[],"documentationUrl":"https://veil.rip/docs/sign-in-with-veil"}}