Skip to main content

Encryption scopes

Enable encryption by requesting an e2ee:* scope at sign-in. No developer-portal configuration is required. Request exactly one E2EE mode scope per sign-in. Re-sign-in reuses existing per-app keys unless you also request e2ee:reset:
After consent, parse the fragment with mergeAppEncryptionFromUrl (PKCE) or completeOAuthCallback (session helper). Store the private key locally in your app; persist the public key on your user record. On key rotation (e2ee:reset), the fragment also includes previous keys (#app_key_old, #app_public_key_old, #app_private_key_old) and #app_key_reset=true so your app can migrate ciphertext before discarding the old material.

Multi-user encryption (asymmetric)

Look up another user’s app public key, encrypt for them, and they decrypt with the private key you already stored locally.

Lookup API

Public endpoint (no user token). Returns 404 if the handle is unknown, the user has never signed in to your app, or they have not provisioned an app encryption key — your app should show messaging like “this person hasn’t used your app yet” instead of generating keys server-side.
  • GET /api/encryption/app-lookup?client_id=…&handle=… → public key + user metadata
  • GET /api/encryption/app-lookup?client_id=…&public_key=… → user metadata for that key

Symmetric mode (legacy-compatible)

Older apps with supportsE2ee still default to symmetric when no e2ee:* scope is requested. The flow is unchanged: #app_key= in the redirect fragment.

Removed: identity wrapped OAuth payloads

The old wrapped_key / unwrapped_secret authorize flow is removed. It required per-identity encryption keys and sent users back through Ave for every invite. Use app keypairs and the lookup API instead. Ave Signing (Ed25519) is unchanged and separate from app encryption.
Last modified on June 25, 2026