auth-landscape
Reference map of authentication, unlock, and sealing-key primitives.
| Status | reference — this page documents no API of its own; the packages it names are documented in the on-* family catalog. |
| Cluster | collaboration-and-auth |
| Cross-cuts | every @noy-db/on-* package, @noy-db/hub core (KEK derivation, keyring layout, policy gates), and the @noy-db/at-* sealing-provider family. |
| Companion | session-tiers — how the primitives below compose into a session lifecycle. |
What this page is
noy-db is a zero-knowledge document store: every record is encrypted on the user's device before it reaches any storage backend. The whole key hierarchy hangs off one root — a key-encryption key (KEK) derived from a user credential, which wraps the per-collection data-encryption keys (DEKs) (see Core 02 — Enclave). "Login" therefore always means one concrete thing here: producing the material that unlocks the KEK.
This page maps the authentication, unlock, and sealing-key methods in common use, scores each on the dimensions that matter for a zero-knowledge offline-first vault, and names the @noy-db/* package that covers it — or states plainly that it is deliberately omitted, not covered, or out of scope. The next time someone asks "can we log in with Cognito / Active Directory / Windows / Touch ID / BankID?", the answer is one table lookup.
Three distinct functions get conflated as "auth"
| Function | What it does | noy-db family |
|---|---|---|
| Authenticator | Proves the user knows / has / is something. Produces a cryptographic proof or releases a wrap key. | on-* (sections 1–5) |
| Identity provider (IdP) | Federates identity. Issues tokens. Does not by itself produce wrap-key material. | on-oidc bridges (section 6) |
| Sealing-key store | Protects a machine-generated secret under OS-account or KMS guarantees. Does not authenticate the user. | at-* — implementations of the NoydbSealer interface exported by @noy-db/hub (sections 8–9) |
Conflating these is the single most common source of misdesign in this space. A Windows DPAPI sealing provider is not an authenticator. A hypothetical on-google would not be different from on-oidc.
Session tiers, briefly
Several rows below refer to noy-db's session tiers — the three-rung privilege ladder that structures unlock (defined in full on session-tiers):
| Tier | Role | Primitive |
|---|---|---|
| 1 | Master secret — the root secret; derives the KEK. Factory-fixed inside @noy-db/hub; there is no on-secret package. | hub core |
| 2 | Routine login — multi-slot authenticators, any one of which unlocks the same KEK. | on-webauthn, on-oidc, on-password |
| 3 | Quick-resume after idle — re-opens an already-unlocked session within a bounded idle window. | on-pin |
Dimensions
| Dimension | What it tests |
|---|---|
| Online? | Network required at unlock time. TOTP needs network only at enrollment, so it scores ❌ here. |
| Personal device | Suits a phone/laptop bound to one user. |
| Shared device | Suits a kiosk / clinic terminal / shared family iPad. Implicitly tests credential portability — methods that work well on shared hardware are ones where the credential travels with the user. |
| Factor | K = knowledge · D = possession/device · B = biometric/inherence. Multi-factor methods list all that apply. |
| noy-db match | Existing on-* package, at-* sealing provider, deliberately omitted (with reason), or not covered. |
Legend: ✅ good fit · ⚠️ works with caveats · ❌ poor fit / breaks model
1. Knowledge factors
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| Master secret (Diceware) | ❌ | ✅ | ⚠️ shoulder-surf | K | tier 1, internal to hub (no on-* package) |
| Password (tier 2) | ❌ | ✅ | ⚠️ | K | on-password |
| Numeric PIN (4–6 digits) | ❌ | ✅ | ❌ low entropy | K | on-pin (tier 3 only) |
| Pattern lock (Android-style) | ❌ | ⚠️ | ❌ | K weak | ❌ deliberately omitted |
| Security questions | varies | ⚠️ | ❌ | K weak | ❌ deliberately omitted (social-engineerable, low entropy) |
2. Possession — software OTP / link
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| TOTP (Google Auth, Authy, 1Password) | ❌ post-enrol | ✅ | ✅ phone-borne | D | on-totp |
| HOTP (RFC 4226) | ❌ | ✅ | ✅ | D | ❌ (TOTP supersedes) |
| Email OTP | ✅ | ✅ | ✅ | D (mailbox) | on-email-otp |
| SMS OTP | ✅ | ✅ | ⚠️ SIM-swap | D weakened | ❌ deliberately omitted (NIST SP 800-63B deprecates) |
| Magic link | ✅ | ✅ | ⚠️ | D (mailbox) | on-magic-link |
| Push notification (Duo, Okta Verify, MS Authenticator number-match) | ✅ | ✅ | ✅ goes to personal phone | D | ❌ (vendor; reachable via on-oidc) |
| WhatsApp / Telegram / Signal OTP | ✅ | ✅ | ⚠️ | D | ❌ |
3. Possession — hardware
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| FIDO2 / WebAuthn — roaming (YubiKey, SoloKeys, Titan) | ❌ | ✅ | ✅ bring the key | D (+ B if biometric key) | on-webauthn |
| FIDO2 / WebAuthn — platform (Hello, Touch/Face ID, Android) | ❌ | ✅ | ❌ device-bound | D + B | on-webauthn |
| Passkey — synced (iCloud Keychain, Google Password Manager, 1Password) | ✅ at sync | ✅ | ⚠️ via QR cross-device | D (synced) | on-webauthn (hybrid transport) |
| Smart cards — PIV / CAC / e-Residency | ❌ | ✅ | ✅ bring the card | D + K (card PIN) | ❌ not covered |
| Hardware OTP tokens (RSA SecurID, classic Yubikey OTP) | ❌ | ✅ | ✅ | D | ❌ (legacy; FIDO2 covers) |
| Bluetooth proximity (Apple Watch unlock, Pixel Smart Lock) | ❌ | ✅ | ❌ wearable-bound | D | ❌ |
| Recovery codes (printable) | ❌ | ✅ paper safe | ⚠️ emergency only | D | on-recovery |
| NFC / contactless ID cards (eID, MyKad, Aadhaar w/ NFC) | ❌ | ✅ | ✅ | D + K (PIN) | ❌ |
4. Inherence — biometrics
Biometrics never are the secret — they gate access to a local credential. So the noy-db match is always indirect.
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| Touch ID / Face ID (Apple) | ❌ | ✅ | ❌ | B (gates passkey/keychain) | on-webauthn (platform); sealing via at-macos-keychain |
| Windows Hello (PIN/fingerprint/face/iris) | ❌ | ✅ | ❌ | B + K | on-webauthn (platform) |
| Android Biometric (BiometricPrompt) | ❌ | ✅ | ❌ | B | on-webauthn (platform) |
| Voice biometrics (banking IVR) | ✅ | ✅ | ⚠️ replay-attackable | B weak | ❌ |
| Iris / vein / palm (industrial / clinical) | ❌ | ✅ | ✅ if scanner shared | B | ❌ |
5. Threshold / split secrets
A recovery profile is an enrolled way back into the vault when the secret is lost (full lifecycle on session-tiers). Four profiles exist in the recovery API: paper (printed single-use codes), shamir (K-of-N shares held by trustees), multi-channel 2-of-3 (email OTP + device PIN + paper code; any two suffice), and admin-mediated (an admin issues a magic-link grant and the user adds one factor). Paper and Shamir are available today; multi-channel and admin-mediated declare their API surface and throw RecoveryProfileNotImplementedError when used.
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| Shamir Secret Sharing (K-of-N) | ❌ | ⚠️ coordination | ⚠️ | D × N | on-shamir |
| Multi-channel 2-of-3 (the multi-channel recovery profile) | partial | ✅ | ⚠️ | K + D mix | composed: on-recovery + on-email-otp + on-pin (profile not yet implemented) |
| Admin-mediated magic-link grant (the admin-mediated recovery profile) | ✅ | ✅ | ✅ | D + admin | on-magic-link + the hub's magic-link grant flow |
| MPC / threshold signing (Fireblocks, Web3Auth tssLib) | ✅ | ⚠️ | ⚠️ | D × parties | ❌ |
6. OIDC / federated identity providers
All require online at auth time. All map to on-oidc with different issuer URLs. Differences are ecosystem fit and built-in 2FA strength, not protocol.
Server-side dependency — OIDC is the only
on-*family that requires consumer-operated infrastructure.@noy-db/on-oidcuses a split-key model: the KEK is XOR-split into adeviceHalf(a per-device secret that never leaves the device) and aserverHalfheld by a small HTTP service — a key connector — that verifies ID tokens against the issuer's JWKS and stores each user'sserverHalfindexed by the token'ssubclaim. The package implements the client side and documents the two-endpoint server contract (PUT /kek-fragment,GET /kek-fragment); it deliberately does not ship a reference server, hosted instance, or deploy template. If you have no off-device infrastructure, prefer@noy-db/on-webauthn(platform passkey via Touch ID / Face ID / Windows Hello) — the same "Login with X" UX without a server, because the platform passkey is the device-bound credential.
| Provider | Personal | Shared | Default factors | Notes / caveat | noy-db match |
|---|---|---|---|---|---|
| Google Sign-In | ✅ | ⚠️ leaves session | K + optional D (Google Prompt / TOTP / key) | Consumer + Workspace | on-oidc |
| Apple Sign-In | ✅ | ❌ Apple-bound | K + B (device) + D | Anonymizes email | on-oidc |
| Microsoft / Entra ID | ✅ | ✅ enterprise | K + D (Authenticator) | Conditional Access | on-oidc |
| AD FS (modern) | ✅ | ✅ | K + D | OIDC since Server 2016 | on-oidc |
| GitHub | ✅ | ⚠️ | K + D (TOTP/passkey) | Dev-tooling auth | on-oidc |
| GitLab | ✅ | ⚠️ | K + D | on-oidc | |
| Okta | ✅ | ✅ enterprise | K + D (Okta Verify push) | Workforce IdP | on-oidc |
| Auth0 | ✅ | ✅ | tenant-configurable | B2C / B2B SaaS IdP | on-oidc |
| AWS Cognito | ✅ | ⚠️ | K + optional TOTP/SMS | State-machine wrapper is real value but the wrap key still needs split-key shape | on-oidc |
| Firebase Auth | ✅ | ⚠️ | K + D | Mobile-first | on-oidc |
| Keycloak (self-host) | ✅ | ✅ | configurable | On-prem IdP | on-oidc |
| ForgeRock / PingOne | ✅ | ✅ enterprise | configurable | Legacy enterprise IAM | on-oidc |
| Facebook / Meta | ✅ | ❌ | K + optional D | Consumer; not for vault | on-oidc (not recommended) |
| LinkedIn / X / Discord / Slack / Notion / Atlassian | ✅ | ⚠️ | K + D | Work-app + consumer | on-oidc |
| LINE / Kakao / WeChat / Naver | ✅ | ⚠️ | K + D (varies) | Asia-regional | on-oidc |
| Authentik / Zitadel / Logto | ✅ | ✅ | configurable | Open-source Auth0/Okta | on-oidc |
| Clerk / Stytch / WorkOS / Frontegg | ✅ | ✅ | varies | DevX-IdP-as-SDK | on-oidc |
| ID.me / Login.gov / GOV.UK Verify | ✅ | ✅ | K + D + identity proofing | Government IdP | on-oidc |
7. Enterprise / directory protocols
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| LDAP simple/SASL bind (incl AD) | ✅ to DC | ⚠️ | ✅ on-prem | K | ❌ not covered (would need the split-key shape, like on-oidc) |
| Kerberos / IWA / SPNEGO | ✅ KDC then cached | ⚠️ | ✅ | K → D (TGT) | ❌ |
| SAML 2.0 | ✅ | ✅ | ✅ | varies by IdP | ❌ — bridge the IdP to OIDC and use on-oidc |
| RADIUS | ✅ | ⚠️ | ✅ | K | ❌ |
| SSH cert auth (CA-signed) | ❌ | ✅ | ✅ bring key | D | ❌ |
| mTLS client certs | ❌ | ✅ | ⚠️ cert provisioning | D | ❌ |
8. OS keychain / device-local sealing — NOT authenticators
These don't authenticate the user — they protect the vault's root secret under OS-account guarantees. They map to the at-* family: implementations of the NoydbSealer interface that @noy-db/hub exports for managed-secret mode — the vault mode where the secret is machine-generated, sealed by the provider, and never shown to the user (see session-tiers). One caveat is structural: unlike every other satellite family, an at-* host can decrypt the vault it unseals — that is the point, and the safeguard is scoping the host to a dedicated vault (the trust boundary is spelled out on the at-* overview).
| Store | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| Windows DPAPI / Credential Manager | ❌ | ✅ | ❌ user-bound | D (OS account) | ❌ not covered |
| macOS Keychain Services | ❌ | ✅ | ❌ | D | at-macos-keychain |
| iOS Keychain (Secure Enclave) | ❌ | ✅ | ❌ | D + B | ❌ not covered |
| Android Keystore / StrongBox / TEE | ❌ | ✅ | ❌ | D + B | ❌ not covered |
| Linux Secret Service (libsecret, gnome-keyring, KWallet) | ❌ | ✅ | ❌ | D | ❌ not covered |
| TPM 2.0 (sealed-to-PCR / no-export) | ❌ | ✅ | ✅ server | D | ❌ not covered |
| Apple Secure Enclave | ❌ | ✅ | ❌ | D + B | indirectly via on-webauthn / at-macos-keychain |
Browser CredentialStore / navigator.credentials | ❌ | ✅ | ❌ | D | indirectly via WebAuthn |
9. Cloud / centralized KMS & HSM — server-context sealing
Same family as section 8 (sealing, not auth) but server-side: at-* sealing providers for managed-secret mode in server contexts — a host you control opens a scoped vault to compute on a user's behalf.
| Service | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
Host environment variable (base64 256-bit key, NOYDB_SEALING_KEY by default) | ❌ | ⚠️ | ✅ server | D (host env) | at-env |
| AWS KMS | ✅ | ⚠️ | ✅ server | D (IAM) | at-aws-kms |
| GCP Cloud KMS / Cloud HSM | ✅ | ⚠️ | ✅ | D | at-gcp-kms |
| Azure Key Vault / Managed HSM | ✅ | ⚠️ | ✅ | D | at-azure-keyvault |
| HashiCorp Vault Transit | ✅ | ⚠️ | ✅ | D (token) | ❌ not covered |
| Cloudflare Keyless SSL / Turnstile | ✅ | ⚠️ | ✅ | D | ❌ |
| PKCS 11 HSM (Thales, YubiHSM, SoftHSMv2) | ❌ | ⚠️ | ✅ | D | ❌ not covered |
| AWS Nitro Enclaves / GCP Confidential Space / Azure Confidential | ✅ | ⚠️ | ✅ | D + attestation | ❌ |
10. Password managers / personal vaults
Out of scope for on-* — users compose them upstream by storing their secret there. Listed for completeness; not a wrap-key target.
| Tool | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| 1Password | ⚠️ sync | ✅ | ❌ | K + D + B | ❌ |
| Bitwarden / Vaultwarden | ⚠️ sync | ✅ | ⚠️ self-host kiosk | K + D + B | ❌ |
| Dashlane / LastPass / NordPass / Proton Pass | ⚠️ sync | ✅ | ❌ | K + D + B | ❌ |
| Apple Passwords / Google Password Manager | ⚠️ sync | ✅ | ❌ | K/B (device) | indirectly via Keychain |
| KeePass / KeePassXC (offline) | ❌ | ✅ | ⚠️ portable | K + D (key file) | ❌ |
11. Threat / context layers (modify, don't replace, the above)
| Mechanism | noy-db match |
|---|---|
| Lockout / duress code / honeypot vault | on-threat |
| Risk-based / adaptive auth (Okta Risk, Auth0 Anomaly, Cloudflare Turnstile) | ❌ (provider-side; layer above on-oidc) |
| Device attestation (Play Integrity, App Attest, ASWebAuthSession) | ❌ |
| Behavioral biometrics (typing cadence, mouse) | ❌ |
| Geofencing / IP allowlists | ❌ (policy-layer, not auth-layer) |
12. Emerging / specialized
| Method | Online? | Personal | Shared | Factor | noy-db match |
|---|---|---|---|---|---|
| Passkeys cross-device (BLE hybrid transport, FIDO CTAP 2.2) | partial | ✅ | ✅ via QR + phone | D + B | on-webauthn |
Decentralized Identifiers — DID/VC (W3C), did:key, did:web, did:ion | varies | ✅ | ✅ | D | ❌ |
| mDL (ISO/IEC 18013-5 mobile driver license) | ❌ BLE | ✅ | ✅ | D + B | ❌ |
| EUDI Wallet (EU Digital Identity, eIDAS 2) | varies | ✅ | ✅ | D + B + K | ❌ |
| BankID (SE/NO/DK/FI) / ItsMe (BE) | ✅ | ✅ | ✅ phone-borne | D + K + B | ❌ not covered |
| Web3 wallet (SIWE — Sign-In with Ethereum / Solana) | ✅ | ✅ | ⚠️ | D (priv key) + K (wallet PIN) | ❌ |
| WebOTP API (browser-mediated SMS auto-fill) | ✅ | ✅ | ⚠️ | D | ❌ |
What's covered today
- Coverage is strong on offline-first primitives (TOTP, WebAuthn, recovery codes, Shamir, PIN, password) — the parts where zero-knowledge actually buys you something. That is deliberate.
- Coverage is uniform on OIDC. One
on-oidcpackage handles every provider in section 6, because the protocol — not the brand — is the unit of abstraction. There is noon-cognito,on-okta, oron-google, and none is needed: they are issuer URLs in anon-oidcconfig. - Sealing coverage is host-first. The
at-*family ships providers for the host environment (at-env), macOS Keychain (at-macos-keychain), and the three major cloud KMSes (at-aws-kms,at-gcp-kms,at-azure-keyvault). There is no provider for Windows DPAPI, the iOS/Android keystores, Linux Secret Service, or HashiCorp Vault. - Not covered today: on-prem directory bind (LDAP / Kerberos), smart cards (roaming WebAuthn covers most of that ground), standalone push-notification factors (reachable via
on-oidc), and regional ID schemes (BankID, EUDI Wallet). - Deliberately omitted: SMS OTP, security questions, pattern locks — each breaks the security model in a way stated in its table row.
on-threatis structurally unique. It is the onlyon-*package that doesn't authenticate; it modifies how the others authenticate (lockout, duress, honeypot).
Why the hub and the on-* packages are separate
When you enroll recovery codes you install @noy-db/on-recovery and call db.team.enrollRecovery(...) on the hub — and the same two-package shape recurs for passwords and PINs. The split is deliberate: the hub owns the cryptosystem; the on-* package owns the user-facing credential format.
The shared "wrap a DEK set under a credential-derived key" primitive — mintWrappedDeksBlob / unwrapDeksFromBlob, exported from @noy-db/hub — derives an AES-GCM key from the credential string via PBKDF2-SHA256 (600,000 iterations) and encrypts the serialized DEK set. It is the same primitive whether the credential is a printed recovery code or a typed password. What differs is what counts as a well-formed credential: a Base32-with-checksum string (on-recovery), a validated password (on-password). (@noy-db/on-pin follows the same pattern but at 100,000 PBKDF2 iterations — a PIN slot's protection window is short and idle-timeout-bounded, and its wire format is deliberately incompatible with the 600K one.)
| Concern | Lives in | Why |
|---|---|---|
| Cryptosystem (PBKDF2-SHA256 600K → AES-GCM wrap of the DEK set) | @noy-db/hub (mintWrappedDeksBlob / unwrapDeksFromBlob) | One audited implementation. Every package calls it. A bug-fix or security review touches one place. |
On-disk format (PaperRecoveryEntry, KeyringFile.authenticators[], _meta/recovery-paper) | @noy-db/hub | The hub knows how to read every keyring it ever wrote; the on-* packages can come and go without changing the format. |
Orchestration (db.enrollRecovery, db.recoverSecret, db.enrollAuthenticator, db.unlockViaAuthenticator) | @noy-db/hub | These compose multiple primitives and run policy gates. They don't change per credential family. |
| User-facing string format (Base32 alphabet + checksum, password validation rules, PIN length policy) | The on-* package | Each consumer can swap. An app that needs BIP-39 word lists instead of Base32 can supply its own format without touching the hub. |
| Auto-rotation, burn-on-use, atomicity | @noy-db/hub | These are properties of the primitive, not the format. |
The classification rule behind the table: does the thing produce wrap-key material directly, or does it just shape user input?
- Produces wrap-key material directly (secret → PBKDF2 → KEK; KEK → AES-KW → DEKs; the wrap-DEKs primitive itself) → hub. There is one cryptosystem, and there is one of it.
- Shapes user input (Base32 codes with checksums, password length policies, 4-digit PINs, WebAuthn ceremonies, OIDC token flows) → an
on-*package. There are many possible shapes; each consumer picks one.
This is also why @noy-db/on-recovery stays a separate small package rather than a hub subpath: keeping the format outside the hub is what lets you swap Base32 for another code format without forking the cryptosystem.
Classifying a method that isn't in the tables
Evaluating an authentication method this map doesn't list? Walk the same checklist the map itself was built with:
- Is it an authenticator, an IdP, or a sealing-key store? Mis-classification means the wrong package family — and the wrong threat model. See "Three distinct functions" above.
- Does the protocol already have a generic package? A vendor-flavored OIDC provider is an
on-oidcconfig, not a missing package. A vendor-flavored OS keychain is a sealing concern (at-*), not an authenticator. - Can it carry wrap-key material on its own? If not (LDAP bind, Kerberos tickets, Cognito tokens), the only honest shape is split-key — the same pattern as
on-oidc— or gate-only composition with a real authenticator. - Does it work on shared devices? If only on personal devices, treat that as a hard constraint in your deployment. Tier 3 (
on-pin) is never safe on shared workstations regardless.
Common questions this map answers
| Question | Where to look | One-line answer |
|---|---|---|
| "Login with Google?" | §6 | on-oidc with Google issuer. |
| "Login with Apple?" | §6 | on-oidc with Apple issuer. Apple-ecosystem only on personal device. |
| "Login with Microsoft / work account?" | §6 | on-oidc with Entra ID issuer. |
| "Login with AWS Cognito?" | §6 | on-oidc with the Cognito hosted-UI issuer; state-machine sugar can live as a small helper inside the consumer app. |
| "Login with Active Directory?" | §6, §7 | Modern AD FS or Entra → on-oidc. Raw on-prem AD (LDAP/Kerberos) → not covered; it would need the split-key shape. |
| "Login with Windows / Windows Hello?" | §3, §4, §8 | Windows Hello is WebAuthn → on-webauthn. "Use my Windows account to unlock" (DPAPI sealing) → not covered; no at-* provider for Windows exists. |
| "Login with Touch ID / Face ID?" | §4 | Platform passkey via on-webauthn. |
| "Login with my YubiKey?" | §3 | Roaming WebAuthn via on-webauthn. |
| "SMS as a 2FA factor?" | §2 | Deliberately omitted. SIM-swap and SS7 attacks make it unfit for vault auth. Use on-totp or on-email-otp. |
| "BankID / EUDI Wallet?" | §12 | Not covered today. |
| "Decentralized identity (DID/VC, SIWE)?" | §12 | Not covered today. |
See also
- session-tiers — how the primitives compose into the three-tier session lifecycle and policy gates.
on-*family catalog — factor table and per-package summaries.at-*family overview — the sealing-provider family: trust boundary, managed-secret mode, per-package summaries.- Core 02 — Enclave — the key hierarchy (secret → KEK → DEKs) everything on this page ultimately unlocks.
- Core 06 — Permissions and keyring — the keyring: the per-user record of wrapped keys that every method on this page ultimately opens.
- Per-package READMEs:
on-webauthn,on-oidc,on-pin,on-totp,on-email-otp,on-recovery,on-shamir,on-magic-link,on-password,on-threat