# Avonao ID: architecture and security whitepaper

Version of 9 November 2026. Published by Avonao, Inc., the operator of Avonao ID.
Current copy: https://avonao.com/trust/security-pack

## About this document

This whitepaper describes how the Avonao ID identity service (the sign-in, account and API service at `id.avonao.com`, with its seven regional Workers) is built and protected today. It is written for security reviewers and procurement teams. It describes the service as it is built, not a roadmap, and where a protection is partial, not built yet or not verified in production it says so. It covers the identity service; the marketing and documentation pages are covered only where a section says so.

Each statement carries a reference such as [A4]. Appendix A lists, for every reference, the public document that states it and the source file that implements it. The legal documents are published as drafts (version 0.1 at the date of this document) and are being finalised. Where this whitepaper and a legal document differ, the legal document governs: the [Business Terms](https://avonao.com/legal/business-terms), the [Data Processing Agreement](https://avonao.com/legal/dpa) (DPA), the [Privacy Policy](https://avonao.com/legal/privacy) and the [Terms of Service](https://avonao.com/legal/terms).

Avonao ID is the account, and it is free for people and companies. The paid offering for companies that put "Sign in with Avonao ID" into their own sites is Avonao ID Business Circle, which is sold in plans from Free to Enterprise. A platform (Entpoind, Trustvice, Agined, Intramedial, GoPlainly, Taddi) is a separate product with its own tiers, regions, billing and data. This document is about the account service they sign in with.

## 1. What the service does

Avonao ID is a passwordless identity provider. A person creates one Avonao ID, chooses a data region, and uses it to sign in to Avonao platforms and to any app whose business has registered it as an app. Apps use OpenID Connect (authorization code flow with PKCE) to ask Avonao ID who is signing in [A1].

The service stores the account (emails, sign-in methods, sessions, consents, a security log) in the member's own region, hands each app only what the member allowed, and gives the member a receipt each time an app receives their details. It signs ID tokens with ES256 keys published in a public key set, so an app can verify a token without calling the service [A2].

Avonao ID does not prove that a person is who they say they are. It proves that the same sign-in methods were used again, and that an email address was confirmed. A separate check, Verified (document and selfie through Stripe Identity), exists behind a switch that is off; this whitepaper does not describe it as live [A3].

## 2. Architecture and data flow

### 2.1 Components

| Component | What it does | Where it runs |
|---|---|---|
| Identity service, home Worker (`avonao-id-idp`) | The only public entry on `id.avonao.com`: sign-in, sessions, the OpenID Connect endpoints, the member API, the business API, and the control plane (apps and platforms, businesses, signing keys, billing, rate limits, the account index) | Cloudflare Workers with Cloudflare D1; home region US West [A4] |
| Regional identity Workers (`avonao-id-idp-<region>`) | Serve the member plane for one region each: users, passkeys, sessions, tokens, grants, consent receipts, the member's security log | Six Cloudflare Workers (US East, Europe Central, Europe West, Europe North, Asia-Pacific, Oceania), each bound to its own D1 database; US West is served by the home Worker [A4][A5] |
| Business console | Where a company registers apps, verifies domains, sets up webhooks and enterprise connections, and manages its plan | `business.avonao.com`, calling the API on `id.avonao.com` with the member's session cookie [A6] |
| Avonao Billing | Checkout, entitlements and signed events to platforms for the plans, add-ons and packs members buy; Stripe is the seller of record | Home Worker, with Stripe [A7] |
| Email | Sign-in links and codes, guardian and security emails from `no-reply@id.avonao.com` | Cloudflare Email Service [A8] |
| Optional modules | Agents, Avonao Wallet, Verified, token exchange, shared signals and the business-owned AWS database | Built, behind switches that stay off unless decided [A3][A9] |

### 2.2 The path of a request

1. **Connection.** The caller connects over HTTPS. Cloudflare terminates the connection at the network location nearest the caller [A10].
2. **Region resolution.** The home Worker reads the member's region from the request itself: the session cookie (`__Host-avid`, value `<region>_<random>`), a bearer token, an authorization code, a sign-in or second-factor token, or the sign-up's chosen region. It does not look the region up. Home is asked first for exactly three things: the account index by email for starting and finishing an email sign-in, and by account id for the platform subscription report [A4].
3. **Hop.** For a member whose region is not US West, the home Worker forwards the same request (URL, method, body, cookies, origin, user agent and the visitor headers) over a service binding to that region's Worker, adding `x-avonao-hop`, an HMAC over region, method, path and query, the time (within 120 seconds) and the visitor values. The key is derived from the platform key-encryption key, so no new secret exists [A4].
4. **Regional check.** A regional Worker answers `403 not_via_front` to anything without a valid hop for its own region, method and path, answers `404` outside the member plane, and rebuilds the visitor headers from the hop. A token or cookie of another region, the home region included, sent to a regional Worker is a `503` and runs no query [A4].
5. **Work.** The regional Worker reads and writes only its own region's D1 database. It is bound to the home database (signing keys, apps, account index, rate limits, none of which is member data) and to no other regional database, so its code cannot reach them [A4].
6. **Fail closed.** If a regional Worker cannot be reached, the home Worker answers `503 region_unavailable` and does not retry or fall back to the other databases it has bound. An unknown region value answers `503 region_unknown` [A4].
7. **Response.** The response, including any redirect, is passed on as it is. The session and the member's security log entry are written in the member's region.
8. **Verification by the app.** The app checks an ID token against the public key set (signature, issuer, audience, expiry, nonce) without contacting Avonao ID [A2].

### 2.3 Signing in to an app

The authorization code flow with PKCE (S256) is the one flow offered to registered apps. Redirect URIs match exactly, confidential apps authenticate with `client_secret_basic`, authorization codes live 60 seconds and access tokens 10 minutes, and an ID token lives 5 minutes. A refresh family dies after 30 days without use and at the latest after 90 days from the first sign-in [A1].

An app is registered in development mode, with members and invited testers only, and needs a verified domain and a privacy URL to go live. Platforms of Avonao (the first-party clients) receive the account id as the subject; every other app receives a pairwise identifier of its own for the member, so two apps cannot match their accounts. The consent screen shows the app by its business name and lists the scopes; the member gets a receipt when an app receives their details and can remove an app's access at any time [A11].

OAuth token exchange, rich authorization requests, shared signals, agents and Avonao Wallet credentials are built behind switches that stay off unless decided. This whitepaper does not describe them as live [A9].

### 2.4 Outbound requests and webhooks

Three kinds of request leave the service for a destination a business chooses: business webhooks (up to five endpoints per business, Beta), the signed account events sent to registered platforms, and the verifier completion callback of Avonao Wallet. Enterprise OIDC connections also make discovery and key requests to the identity provider the business named. Each destination is checked when it is saved and again when it is used [A12]:

- only `https` on the default port, without credentials or a fragment;
- the host must be a public domain name: no IP literal in any notation, no `localhost`, no special-use or single-label name;
- a Wallet callback must additionally be covered by a domain the business has verified;
- redirects are not followed, requests time out after 5 seconds, and an answer is read only up to a small cap and never returned to the caller.

Stated limit: the filter works on the URL and does not resolve the name, because Workers cannot pin a resolved address. A public name pointed at a private address is stopped by Cloudflare's own egress rules, not by this check. Avonao does not describe the filter as a complete defence [A12].

Every delivery carries `avonao-signature: t=<unix>,v1=<hex HMAC-SHA256 of "<t>.<body>">`, so a receiver can verify the sender and reject old deliveries. The first attempt is inline; retries follow at 1, 5 and 30 minutes and at 2, 6 and 24 hours, after which the delivery is given up. Business webhooks carry `grant.revoked`, `member.deleted`, `member.deletion_requested` and `member.deletion_cancelled`; platform events carry `account.deletion_requested`, `account.deletion_cancelled`, `account.deleted` and `account.appearance_changed`. Event bodies carry ids only, never an email address or a name. The signing secret is stored sealed with AES-256-GCM. Webhooks are Beta and carry no service level [A13].

### 2.5 Enterprise connections and SCIM (Beta)

A business can connect its own identity provider for people whose email is on a domain the business verified (one business per domain). OIDC connections verify the provider's ID token (signature from its published keys, issuer, audience, expiry, nonce). SAML connections pin the provider's certificate (RSA 2048 bits or more, or EC P-256, up to four per connection); the signature must verify under a pinned key and nothing inside the response chooses the key. The XML reader refuses anything outside a small subset (no `DOCTYPE`, so no entities, no processing instructions, comments or CDATA), exactly one assertion is accepted, a response can be tried once, and an assertion cannot be replayed. Sign-in is SP-initiated only [A14].

SCIM 2.0 provisioning is available on Enterprise only. A SCIM user becomes a membership of the business for a person who already has an Avonao ID, matched by a verified email on a verified domain of the business. SCIM never creates a person's Avonao ID and never changes it; deprovisioning removes the membership and revokes the grants the person gave that business's apps. Member data stays in the member's region [A15].

Both SAML and SCIM are tested against test clients written for the purpose. Neither has been run against a live Entra ID, Okta or Google Workspace tenant, and both are Beta [A14][A15].

## 3. Token signing key custody

- ID tokens are signed with ES256 (ECDSA P-256). The key set is global: one issuer, one key set, shared by all regions [A2].
- The private keys are stored in the home D1 database, encrypted with AES-256-GCM under the platform key-encryption key (`ID_KEK`), with the key id as additional authenticated data. `ID_KEK` is held as a Cloudflare Worker secret and is never stored in the database [A16].
- The private keys are not held in a hardware security module or a cloud key management service. Whoever can deploy the Workers or read the `ID_KEK` secret can decrypt them; access to both is limited to named Avonao staff [A16].
- No API route returns private key material; the public route returns public keys only [A2].
- **Rotation.** An active key signs for up to 90 days. A daily job promotes the next key once it has been published for at least 24 hours, so every verifier has it before it signs [A2].
- **Retirement.** A retired key stays published as long as the longest token it signed can live, plus clock skew (at least 70 minutes; 200 days when Avonao Wallet is on, because credentials live up to 180 days) [A2].
- **Compromise.** A compromised key is flagged and removed from the published key set at once, whatever its retirement time [A2].
- **Key id.** The key id is the first 22 characters of the base64url SHA-256 of the key's canonical public JWK members.
- **`ID_KEK` rotation** is a documented, idempotent re-wrap of every column it encrypts (signing keys, TOTP secrets, webhook secrets, enterprise connection secrets) with an operator script; it is a manual operation, not a schedule. Keyed hashes derived from `ID_KEK` (the account index, rate-limit keys, the regional hop, the guardian consent hash) cannot be re-wrapped [A16].
- **Stated limits.** There is no key revocation list and no key transparency log. A compromise would be announced by notice and by a change to the published key set. Holding the keys encrypted in the database limits who can read them; it does not stop whoever can deploy the service from causing it to sign.

## 4. Data regions and residency

| Region | Code | Worker placement | Storage |
|---|---|---|---|
| US East | `enam` | `aws:us-east-1` | Cloudflare location hint |
| US West (home) | `wnam` | Cloudflare location of the visitor | Cloudflare location hint |
| Europe Central | `weur-1` | `aws:eu-central-1` | Cloudflare EU jurisdiction (enforced) |
| Europe West | `weur-2` | `aws:eu-west-1` | Cloudflare EU jurisdiction (enforced) |
| Europe North | `neur` | `aws:eu-north-1` | Cloudflare EU jurisdiction (enforced) |
| Asia-Pacific | `apac` | `aws:ap-southeast-1` | Cloudflare location hint |
| Oceania | `oc` | `aws:ap-southeast-2` | Cloudflare location hint |

[A5]

- **What is regional.** A member's personal data: users, emails, sign-in identities, passkeys, TOTP secrets, recovery codes, the Guard name and recovery-key hash, sessions, sign-in links, second-factor challenges, authorization codes, access tokens, grants, pairwise identifiers, consent receipts, the member's security log, platform links and subscription status, and the records of a sign-up waiting for a guardian [A5].
- **What is in the home region (US West).** The control plane: apps and platforms, businesses and their records (organizations, domains, webhooks and deliveries, enterprise connections, directory listings, moderation decisions, reports), signing keys, pending authorization requests, rate limits, and the account index. The index holds the account id, the region and keyed hashes of email addresses and sign-in identifiers, not the addresses themselves. Short-lived records created before the region is known (a pending sign-in request, passkey and social sign-in state) are also kept at home [A5][A17].
- **EU jurisdiction.** For the three European regions the databases are created under Cloudflare's EU jurisdiction, which Cloudflare enforces; Cloudflare chooses the datacenter within the EU, so no city is named. For the other regions the database is created with a location hint, which is a placement request, not a guarantee [A5].
- **Chosen at sign-up.** The region is chosen when the Avonao ID is created. No migration between regions is documented.
- **Fail closed, never across regions.** A regional Worker reads only its own database, the home Worker never serves a member of another region from its own bindings, and a request is never answered from another region [A4].
- **Daily maintenance** runs in every Worker over its own region only (purge of due accounts, expired short-lived rows, sessions, the 395-day security log); the control-plane part runs at home [A4].
- **What crosses regions.** The metadata the home Worker needs to find a region and to enforce rate limits, as keyed hashes; requests are handled on Cloudflare's network at the nearest location; webhook and platform event deliveries go wherever the receiver is [A17].
- **Business-owned AWS database.** Code for a business on Scale or Enterprise (or the isolation add-on) to have its own AWS database is built and switched off; it is not available and this whitepaper does not rely on it [A9].

## 5. Sub-processors

The current list, with purpose, data seen, location and transfer safeguards, is published at [https://avonao.com/legal/sub-processors](https://avonao.com/legal/sub-processors). At the date of this document it names [A18]:

| Provider | Purpose |
|---|---|
| Cloudflare, Inc. | Hosting and compute (Workers), D1 databases, network and DNS, outgoing email (Email Service), Turnstile bot check, service logs |
| Stripe, LLC | Payments for business plans and platform purchases through Avonao Billing (Checkout and Managed Payments, seller of record); identity checks for Verified (Stripe Identity), only when Verified is switched on and the person chooses to verify |
| Google (Google Ireland Limited in the EEA and Switzerland; Google LLC elsewhere) | "Sign in with Google", only when the person chooses it |
| Microsoft (Microsoft Ireland Operations Limited in the EEA, the UK and Switzerland) | "Sign in with Microsoft", only when the person chooses it |
| GitHub, Inc. | "Sign in with GitHub", only when the person chooses it |
| Microsoft 365 | Company mailboxes behind the support, privacy and report addresses |

Analytics and error-monitoring tools (Cloudflare Web Analytics and Zaraz, Google Analytics 4 and Search Console, Sentry) are listed as planned, and none is live. They are designed not to receive business personal data and never run on sign-in pages [A18].

Businesses are told of a new or replaced sub-processor at least 30 days ahead, by email to the owners or in the console, and may object on reasonable data protection grounds [A18]. The published list is authoritative over this table.

## 6. Encryption

- **In transit.** All traffic uses HTTPS. Responses carry `Strict-Transport-Security` (one year, `includeSubDomains`), `X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`, `X-Frame-Options: DENY` and `frame-ancestors 'none'`. The session cookie is `__Host-` prefixed, `Secure`, `HttpOnly` and `SameSite=Lax`. Regional calls between the home Worker and regional Workers use service bindings inside Cloudflare's account [A10][A19].
- **At rest, provider level.** Account data is stored in Cloudflare D1. Cloudflare documents that all objects stored in D1, including metadata and inactive databases, are encrypted at rest with AES-256 (GCM preferred) [A20]. Avonao does not manage those storage keys.
- **At rest, application level.** Secrets the service must read back (TOTP secrets, token signing private keys, webhook and platform-event secrets, enterprise connection client secrets) are sealed with AES-256-GCM under `ID_KEK`, with the record they belong to as additional authenticated data, so a ciphertext copied to another row, column or tenant does not open. Written values are marked with the key id so a rotation can tell old from new [A16].
- **Hashes.** Session tokens, sign-in links and codes, authorization codes, access tokens, sign-in state, second-factor challenges, invitation tokens, SCIM tokens and app client secrets are stored only as SHA-256 hashes [A16].
- **Keyed hashes.** Rate-limit keys (which name emails, IP addresses and account ids of members of every region) and the account index store a keyed HMAC derived from `ID_KEK`, so no address, IP or account id is stored in clear [A4][A17].
- **Passwords.** Passwords are never used, stored or sent. Sign-in uses passkeys (which store only the public key), an emailed link or code, or Google, Microsoft or GitHub [A21].

## 7. Access control

### 7.1 Member access

| Control | As built |
|---|---|
| Passkeys | ES256 and Ed25519 credentials, attestation `none`, user verification required, discoverable credentials. Only the public key is stored [A21] |
| Email link or code | Single-use, expires after 10 minutes, at most 5 code attempts, rate limited [A21] |
| Social sign-in | Google, Microsoft or GitHub, at the member's choice; an account identifier and a verified email are received [A18][A21] |
| Second factor | Optional TOTP with replay protection and recovery codes stored only as hashes and shown once; the secret is sealed [A21] |
| Guard name and emergency kit | A sign-in link is sent only when the email address and the Guard name are both right; the Guard name is not an identifier, nothing looks a member up by it, and it is never shown to a platform. The emergency kit carries the recovery key [A22] |
| Sessions | `__Host-` cookie, 14 days without use and 90 days at most, listing and ending of sessions by the member, sensitive account changes need a confirmation within the last 10 minutes [A19] |
| Step-up | Apps can ask for a stronger sign-in before a sensitive action, and Avonao ID tells them how strongly the member signed in (`acr`, `amr`) [A23] |
| Rate limits | Fixed-window limits on sign-in, code entry, the token endpoint, business creation, invitations, domain verification, reports, follows and other actions; an exceeded limit is `429` with a retry time [A24] |
| Under-age sign-ups | A sign-up under the minimum age waits for a parent or guardian: a single-use link valid up to 14 days, one reminder after 7 days; a refusal or no answer deletes the request [A25] |

### 7.2 Business access

- A business is a workspace created from a member's own Avonao ID, with roles owner, admin and developer. Invitations can be accepted only by the invited, confirmed email address. A change that would leave a business without an owner is refused [A26].
- App client secrets are shown once and stored as hashes. Apps in development mode can be used only by members and invited testers; a Live app needs a verified domain and a privacy URL [A11].
- Domain verification uses a DNS TXT record or a file at a well-known path, and one business can own a domain [A26].
- Plan limits (apps, console seats, webhooks, enterprise connections, SCIM) are enforced server-side from the business's entitlement. Over the user limit owners are warned and sign-ins never stop; over the app or seat limit new ones are refused and existing ones stay [A27].
- Platform-level roles and permissions belong to each platform, not to Avonao ID.

### 7.3 Separation

A regional Worker can reach only its own region's member database. The home Worker serves members of US West itself and forwards every other member's request without reading it. Business records are separated from member records by database. Business tables are separated from one another by business id on every query; there is no database per business on the plans sold today [A4][A9].

### 7.4 Avonao personnel and operators

- Access to production is limited to named Avonao staff who are bound by confidentiality [A28].
- Administrative functions need a separate bearer token, compared in constant time, held by named staff and stored as a platform secret, never in the database [A28].
- Operators can run a regional maintenance job through the home Worker, which checks the token and signs the hop; a regional Worker serves the internal path only with a valid hop [A4].
- There is no customer-grant support-access feature. This whitepaper makes no claim about how staff access to member data is approved or reviewed.

### 7.5 Abuse controls

Rate limits on the actions listed above. Cloudflare Turnstile on sign-up and business creation when configured; the check fails closed. Browser requests that change data must come from the same origin. There is no automated scanner or credential-stuffing detection beyond these [A24].

## 8. Logging and audit

- **Security log.** Sign-ins and account changes are written per member to a security log in the member's region, with time, IP address and user agent where the event allows [A29].
- **Audit log.** Business events are written to an audit log in the home database; per-app sign-in statistics are shown in the business console [A29].
- **Customer access.** A member reads their own security log in the dashboard and in their data export [A30].
- **Retention.** The security log is kept for 395 days, about 13 months, and never longer than the account; at purge, entries are anonymised (account id, IP address, user agent and details removed). Webhook delivery records are kept for 30 days. Hosting request logs are kept for up to 7 days [A30].
- **Content of logs.** SCIM and enterprise connection events carry ids, not an address, name or token [A15].
- **Observability.** Cloudflare Workers observability is on. No analytics, error-monitoring or recording tool is live [A18].

## 9. Availability and incident response

- **Status.** There is no public status page with incident history today. Anyone can check that `id.avonao.com` serves its OpenID discovery document and its published key set.
- **Personal data breaches.** Businesses for which Avonao is processor are told without undue delay and where possible within 48 hours of Avonao becoming aware, with what is known and supplemented as more is learned. For members, the runbook follows GDPR Articles 33 and 34: notification of the authority within 72 hours of becoming aware, and a plain-language notice to people at high risk [A31].
- **Runbook.** A written incident and personal-data-breach runbook describes containment (revoke or rotate a secret, end sessions, disable a route or Worker, pause a cron), assessment, notification and a breach register. It is a draft: roles are still to be named, and no exercise is recorded [A31].
- **Service levels.** No uptime commitment, service credits or support response time is offered. During early access there is no service level agreement unless agreed in writing, and Beta features (webhooks, enterprise connections, SCIM) are outside any service level [A27].
- **Verification independence.** An app verifies an ID token against the published key set, which it can cache, without contacting Avonao ID. Obtaining a token needs the service to be up.
- **Code rollback.** Each Worker is deployed as a version and can be returned to an earlier one; a code rollback does not touch data [A32].

## 10. Vulnerability disclosure

- Report to `security@avonao.com` or through the form at `https://avonao.com/security/report`. A `security.txt` is published at `https://avonao.com/.well-known/security.txt` [A33].
- The Acceptable Use policy welcomes good-faith security research and asks researchers not to access other people's data, not to disrupt the service and to allow reasonable time to fix an issue before publishing it [A33].
- Not yet: a dedicated disclosure policy with safe harbor, acknowledgement and fix targets, and a coordinated publication window. No monetary bug bounty is offered.

## 11. Backup and recovery

- **Point-in-time recovery.** Each Cloudflare D1 database (the home database and one per region) has Time Travel, which Cloudflare runs always-on: it can be restored in place to any minute of the last 30 days on the paid Workers plan that Avonao uses (7 days on the free plan) [A34].
- **Not a copy.** Time Travel is the database recovery mechanism. No scheduled export or copy of the databases outside Cloudflare D1 is claimed.
- **After a restore.** Provider recovery data is not used except to bring the service back after a failure. If a restore is needed, accounts that had already been purged are purged again, and during an incident the runbook requires the incident lead's written approval before any restore [A31][A34].
- **Secrets.** `ID_KEK` and the other platform secrets are Worker secrets outside D1, so Time Travel does not cover them. Losing `ID_KEK` makes the sealed columns unreadable.
- **Customer copies.** Members download their data at any time from the dashboard [A30].
- **Commitments.** Avonao publishes no recovery point or recovery time objective and no continuity statement.

## 12. Retention and deletion

- Sessions end after 14 days without use and at most 90 days; ended sessions are deleted 30 days later [A30].
- The security log is kept for 395 days and anonymised at purge [A30].
- A deleted account can be restored for 28 days and is then purged; every platform the member uses is told to erase. The hosting provider's recovery data can hold purged data for up to 30 days [A30].
- Webhook delivery records are kept for 30 days; the sharing history of Avonao Wallet 90 days; the activity record of agents 396 days by default (30 days to 3 years at the member's choice), when those modules are on [A30].
- A sign-up waiting for a guardian is kept for 14 days at most [A25].
- Purchases: Stripe is the seller of record and keeps the payment details; Avonao receives and keeps the outcome of a purchase (plan, status, amount and currency, Stripe identifiers) [A18][A30].

## 13. What is not claimed

- No SOC 2, ISO/IEC 27001 or comparable certification, and no third-party audit report or penetration test report.
- No hardware security module or cloud key management service holds the token signing keys, and no key revocation list or key transparency log exists.
- No customer-managed encryption keys and no dedicated per-customer database are part of the plans sold today.
- No IP allow-list, no organisation-wide enforcement of two-step sign-in, and no automated abuse detection beyond rate limits and the bot check.
- SAML sign-in and SCIM provisioning are Beta and have not been run against a live Entra ID, Okta or Google Workspace tenant.
- No public status page, no uptime commitment, no recovery point or recovery time objective, no database copy beyond D1 point-in-time recovery.
- No dedicated disclosure policy with safe harbor and response targets, and no bug bounty.
- No claim is made about personnel background checks, security training or periodic access reviews.

Questions about this document, or a written security questionnaire of your own, go to `privacy@avonao.com`. Where documentation is not enough, the DPA provides for an audit by the business or an independent auditor once a year on 30 days' notice at the business's cost [A35].

## Appendix A: evidence references

Public documents are at `https://avonao.com`. Source paths are relative to the Avonao ID repository and are listed so a reviewer under a confidentiality agreement can trace each statement to the code.

| Ref | Statement | Public document | Source |
|---|---|---|---|
| A1 | OpenID Connect authorization code with PKCE S256, exact redirect URIs, token lifetimes | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/oauth.ts, runtime/avonao-id/docs/02-api-contract.md |
| A2 | ES256 signing, key set, rotation, retirement, compromise removal | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/keys.ts |
| A3 | Verified and other optional modules behind switches | /legal/verified-consent | runtime/avonao-id/src/env.ts, runtime/avonao-id/docs/legal/verified-consent.md |
| A4 | Home Worker, regional Workers, hop, fail-closed routing, account index, daily maintenance | /legal/privacy | runtime/avonao-id/docs/11-regions.md, runtime/avonao-id/src/lib/forward.ts, runtime/avonao-id/src/lib/regional.ts |
| A5 | Seven regions, what is regional, EU jurisdiction versus location hint, placement | /legal/privacy, /legal/sub-processors | runtime/avonao-id/src/lib/regions.ts, runtime/avonao-id/wrangler.*.jsonc, runtime/avonao-id/docs/11-regions.md |
| A6 | Hosts: id.avonao.com, business.avonao.com | /security | lib/avonao-id/hosts.ts |
| A7 | Avonao Billing, Stripe as seller of record | /legal/sub-processors | runtime/avonao-id/docs/24-billing.md, runtime/avonao-id/src/lib/stripe.ts |
| A8 | Outgoing email from no-reply@id.avonao.com | /legal/sub-processors | runtime/avonao-id/src/lib/mailer.ts, runtime/avonao-id/docs/13-support-mail.md |
| A9 | Optional modules and the business-owned AWS database, off by default | (internal) | runtime/avonao-id/src/env.ts, runtime/avonao-id/src/lib/isolation.ts |
| A10 | TLS and Cloudflare termination | /legal/dpa (Annex 2) | runtime/avonao-id/docs/legal/data-processing-agreement.md |
| A11 | Apps, development mode and Live, pairwise identifiers, consent screen and receipts | /legal/privacy | runtime/avonao-id/docs/08-business-api.md, runtime/avonao-id/src/lib/pairwise.ts, runtime/avonao-id/docs/09-network-api.md |
| A12 | Outbound URL checks, redirects, timeouts, stated limit | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/ssrf.ts, runtime/avonao-id/src/lib/webhooks.ts |
| A13 | Webhook and platform-event signing, events, retries, sealed secrets | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/webhooks.ts, runtime/avonao-id/src/lib/backchannel.ts |
| A14 | Enterprise OIDC and SAML connections, strict SAML subset, replay and state rules | /legal/dpa | runtime/avonao-id/docs/14-saml-security.md, runtime/avonao-id/src/lib/saml.ts, runtime/avonao-id/src/routes/enterprise.ts |
| A15 | SCIM rules, Enterprise only, no change to a person's Avonao ID | /legal/business-terms | runtime/avonao-id/docs/15-scim.md, runtime/avonao-id/src/lib/scim.ts |
| A16 | AES-256-GCM sealing under ID_KEK, AAD binding, SHA-256 hashes, KEK re-wrap | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/crypto.ts, runtime/avonao-id/src/lib/kek-rotation.ts |
| A17 | Account index and what stays at home | /legal/privacy | runtime/avonao-id/src/lib/accounts.ts, runtime/avonao-id/docs/11-regions.md |
| A18 | Sub-processors, planned tools, change notice | /legal/sub-processors | runtime/avonao-id/docs/legal/sub-processors.md |
| A19 | Security headers, session cookie, session lifetime | /security | runtime/avonao-id/src/lib/http.ts, runtime/avonao-id/src/lib/sessions.ts |
| A20 | D1 encryption at rest and in transit | Cloudflare: developers.cloudflare.com/d1/reference/data-security/ | Provider documentation |
| A21 | Passkeys, email link and code, social sign-in, TOTP, recovery codes, no passwords | /security | runtime/avonao-id/src/lib/webauthn.ts, runtime/avonao-id/src/lib/login.ts, runtime/avonao-id/src/lib/totp.ts, runtime/avonao-id/docs/05-signup-login-concept.md |
| A22 | Guard name and emergency kit | /security | runtime/avonao-id/docs/25-guard-name.md, runtime/avonao-id/src/lib/guard.ts |
| A23 | Step-up and authentication context | (internal) | runtime/avonao-id/docs/21-stepup-rar.md, runtime/avonao-id/src/lib/acr.ts |
| A24 | Rate limits and Turnstile | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/ratelimit.ts, runtime/avonao-id/src/routes/auth.ts |
| A25 | Under-age sign-ups and guardian consent | /legal/privacy | runtime/avonao-id/docs/05-signup-login-concept.md, runtime/avonao-id/src/lib/guardian.ts |
| A26 | Business roles, invitations, last-owner rule, domain verification | /legal/business-terms | runtime/avonao-id/docs/08-business-api.md, runtime/avonao-id/src/lib/orgs.ts, runtime/avonao-id/src/lib/domains.ts |
| A27 | Plans, limits, early-access and Beta terms, no service level | /legal/business-terms | runtime/avonao-id/src/lib/plans.ts, runtime/avonao-id/docs/legal/business-terms.md |
| A28 | Personnel access, confidentiality, administrative token | /legal/dpa (Annex 2) | runtime/avonao-id/docs/legal/data-processing-agreement.md |
| A29 | Security log and audit log | /legal/dpa (Annex 2) | runtime/avonao-id/src/lib/audit.ts |
| A30 | Retention, deletion, export, recovery data | /legal/privacy | runtime/avonao-id/docs/legal/privacy-policy.md |
| A31 | Breach process, 48-hour business notice, 72-hour authority notice | /legal/dpa (clause 8) | runtime/avonao-id/docs/legal/breach-process.md |
| A32 | Versioned Worker deployments and rollback | (internal runbook) | runtime/avonao-id/docs/10-deploy-runbook.md, runtime/avonao-id/wrangler.jsonc |
| A33 | Disclosure channels, security.txt, acceptable use | /security/report, /.well-known/security.txt, /legal/acceptable-use | public/.well-known/security.txt, runtime/avonao-id/docs/legal/acceptable-use.md |
| A34 | D1 Time Travel, always on, 30 days on the paid plan | Cloudflare: developers.cloudflare.com/d1/reference/time-travel/ | runtime/avonao-id/docs/legal/privacy-policy.md |
| A35 | Questionnaire and audit rights | /legal/dpa (clause 10) | runtime/avonao-id/docs/legal/data-processing-agreement.md |
