Identity Auth and Security
How do you prove who someone is without becoming the single point of failure?
Essential component of Trust Architecture: Secure verifiable identity is critical to building trust and goodwill.
Evaluation Checklist
Score every auth solution against these dimensions before committing. Empty cells are the honest gaps.
Build Fitness
| Dimension | Question | Weight |
|---|---|---|
| Testing | Can you test auth flows without hitting external APIs? | High |
| Staging parity | Can you replicate prod auth config in staging? | High |
| CI reliability | Do auth tests pass consistently without flakes? | High |
| Type safety | Does the SDK provide full TypeScript inference? | Medium |
| Framework fit | Does it support App Router, middleware, RSC natively? | High |
| Migration path | Can you switch away without losing user data? | Medium |
Operate Fitness
| Dimension | Question | Weight |
|---|---|---|
| Multi-tenant | Orgs, roles, permissions -- built-in or custom? | High |
| MFA | TOTP, SMS, passkeys -- which are supported? | Medium |
| Session control | Can admins revoke sessions, force logout? | Medium |
| Rate limiting | Is brute-force protection built-in or DIY? | Medium |
| Webhook support | Can you react to auth events server-side? | Medium |
| Compliance | SOC2, GDPR, data residency -- what's covered? | Varies |
Cost Fitness
| Dimension | Question | Weight |
|---|---|---|
| Pricing model | Free tier limits? Per-seat? Per-MAU? | High |
| Infra overhead | Self-hosted = your DB costs. Managed = their pricing. | Medium |
| Vendor lock-in | How much custom code ties you to this provider? | High |
| Scale ceiling | At 10K, 100K, 1M users -- what breaks or costs more? | Medium |
Trust Fitness
| Dimension | Question | Weight |
|---|---|---|
| Data ownership | Where do user credentials and sessions live? | High |
| Key management | Who controls the signing keys? | High |
| Privacy | What does the provider see about your users? | Medium |
| Decentralization | Can users own their identity without your permission? | Low* |
*Low for most SaaS. Critical for Web3/DePIN applications.
Debug Checklist
Auth broke in CI. Work through this sequence before anything else.
| # | Check | Symptom If Wrong | Fix |
|---|---|---|---|
| 1 | Env vars present? | Cryptic SDK init failure after 45s timeout | Fail fast: validate keys exist before auth setup. Create .env.test from .env.test.sample |
| 2 | Token before navigation? | Blank page, no error (managed providers) | setupClerkTestingToken() before page.goto(), not after |
| 3 | Single auth setup call? | Flaky intermittent failures | clerk.signIn() OR setupClerkTestingToken(), never both |
| 4 | Storage state dir exists? | Works locally, fails in CI | mkdir -p playwright/.clerk in CI setup step |
| 5 | One test user per worker? | Bot detection, account lockout | Separate credentials per parallel shard |
| 6 | Test DB running? (self-hosted) | Connection refused, silent test skip | Health check before test suite: pg_isready -p 5433 |
| 7 | Correct mock layer? | Tests pass but miss real bugs | Unit/integration: mock at boundary. E2E: real auth only |
The 80/20: Issues 1-3 cause 80% of auth CI failures. Start there.
Self-hosted vs managed split:
- Managed (Clerk): Issues 1-5 apply. Bot detection is the recurring pain.
- Self-hosted (Better Auth): Issues 1, 6-7 apply. No bot detection, but you own the DB health.
See Clerk Auth for the full pitfall table and Better Auth for the self-hosted testing story.
Solution Landscape
Traditional (Web2)
Managed services or self-hosted libraries. Session-based or JWT. Provider controls the identity layer.
| Provider | Model | Strength | Testing Story |
|---|---|---|---|
| Clerk | Managed SaaS | Fastest setup, best DX | Requires mocks + tokens |
| Better Auth | Self-hosted | Full DB control, free | Test DB, no external deps |
| Auth.js | Self-hosted | Large ecosystem, adapters | Test DB, callback-heavy |
| Auth0 | Managed SaaS | Enterprise features | Requires mocks |
| Kinde | Managed SaaS | B2B focus, permissions | Similar to Clerk |
| Authentik | Self-hosted | Full IdP, LDAP/SAML | Complex setup |
| Okta | Managed SaaS | Enterprise SSO standard | Enterprise tooling |
Decentralized (Web3)
User owns their identity. Verification without centralized authority. Zero-knowledge proofs preserve privacy.
| Provider | Mechanism | Privacy Model |
|---|---|---|
| Sui zkLogin | OAuth + ZK proofs | Full on-chain privacy |
| Worldcoin | Biometric + ZK proofs | Proof of personhood |
| Polygon ID | ZK verifiable credentials | Selective disclosure |
| SpruceID | DID + Sign-In with Ethereum | Self-sovereign |
| Dynamic.xyz | Multi-chain wallet auth | Wallet-based |
| zPass | ZK proofs on Aleo | Full privacy |
Three Factors
| Factor | What It Is | Examples |
|---|---|---|
| Knowledge (something you know) | Secret only the user knows | Password, PIN, security question |
| Possession (something you have) | Device or token the user holds | Phone, hardware key, wallet |
| Inherence (something you are) | Biometric trait | Fingerprint, face, iris (Worldcoin) |
Proof of identity is ultimately a hardware problem. Software can verify claims. Hardware proves presence.
zkLogin
Sui's zkLogin bridges Web2 identity to Web3 accounts using zero-knowledge proofs. Users authenticate with Google/Apple/Facebook -- no wallet, no seed phrase -- and get a Sui address that's cryptographically unlinkable to their OAuth identity.
How It Works
User signs in with Google
|
v
OAuth JWT issued (contains nonce with ephemeral public key)
|
v
JWT + salt --> ZK Proving Service --> Groth16 proof
|
v
Proof + ephemeral key sign Sui transactions
|
v
On-chain: only proof visible, no identity revealed
Three components:
- OAuth JWT -- standard OpenID Connect token from Google/Apple/etc.
- Salt -- random value stored on your backend, used to derive stable Sui address
- ZK Proof -- Groth16 proof that you possess a valid JWT without revealing it on-chain
Supported providers: Google, Facebook, Apple, Kakao, Slack, Twitch (any OpenID Connect-compliant provider).
Privacy Properties
| Property | What It Means |
|---|---|
| On-chain privacy | Only ZK proof and ephemeral signature visible -- no personal data |
| Unlinkability | Third parties cannot connect Sui address to OAuth identity |
| Optional disclosure | Users can opt-in to verify identity for a specific address |
| Two-factor security | Attacker needs both compromised OAuth AND the salt |
Developer Integration
// 1. Construct OAuth URL with ephemeral key in nonce
const params = new URLSearchParams({
client_id: GOOGLE_CLIENT_ID,
redirect_uri: REDIRECT_URI,
response_type: "id_token",
scope: "openid",
nonce: nonce, // contains ephemeral public key
});
const loginURL = `https://accounts.google.com/o/oauth2/v2/auth?${params}`;
// 2. On callback: get proof from proving service
const proof = await fetch(ZK_PROVER_URL, {
method: "POST",
body: JSON.stringify({ jwt, salt }),
}).then((r) => r.json());
// 3. Compute zkLogin address
import { computeZkLoginAddressFromSeed } from "@mysten/zklogin";
const address = computeZkLoginAddressFromSeed({ iss, salt });
// 4. Sign and execute transactions
import { getZkLoginSignature } from "@mysten/zklogin";
const zkSig = getZkLoginSignature(sigInputs);
await suiClient.executeTransactionBlock({ transactionBlock: txBytes, signature: zkSig });
Infrastructure Choices
| Component | Mysten-hosted | Self-hosted |
|---|---|---|
| ZK Prover | prover-dev.mystenlabs.com/v1 | Deploy your own prover service |
| Salt service | None provided | Your backend + database (required) |
| Enoki | Managed zkLogin + invisible wallets | N/A |
Mysten-hosted prover for prototyping. Self-hosted for regulated or high-assurance workloads.
Account Recovery
Account ownership = OAuth identity (iss + sub) + salt. Recovery means recovering the salt:
- Store on your backend, keyed to user identity
- Optionally back up encrypted in user-controlled storage
- Re-derive address on new device: same salt + new JWT = same Sui address
For advanced recovery: KELP-style smart contracts accept zkLogin as one of several auth factors alongside multisig or social recovery.
Session Management
zkLogin is stateless at the chain level. Session semantics come from your app:
- Web2 layer: OAuth refresh tokens, HTTP-only cookies
- Sui layer: Short-lived ephemeral keypairs bound to the zkLogin proof
- Rotation: New ephemeral keys freely, same zkLogin identity
Worldcoin
Worldcoin was co-founded by Sam Altman to counter AI-driven erosion of trust. Hardware-based proof of personhood (iris scan via Orb) combined with ZK proofs for privacy-preserving verification. Solves the "are you human?" problem that software-only solutions cannot.
- Microsoft investor
Hybrid Architecture
For platforms like Stackmates that bridge Web2 and Web3, the auth stack is layered:
| Layer | Technology | Purpose |
|---|---|---|
| App auth | Clerk or Better Auth | User signup, session, RBAC, multi-tenant |
| Chain identity | Sui zkLogin | On-chain transactions without wallet UX |
| Proof of person | Worldcoin/Polygon ID | Sybil resistance for incentive systems |
The app auth layer handles day-to-day identity. zkLogin activates when users interact with on-chain assets. Proof of personhood gates high-value actions (token claims, governance votes).
Dig Deeper
📄️ Better Auth
What if your auth library lived in your database, not someone else's cloud?
📄️ Clerk Auth
How do you test authenticated flows without fighting the auth provider?
Context
- Web3 Identity -- The identity problem space
- Market Forces -- Why identity matters now
- Web3 Wallets -- Wallet integration
- Smart Contracts -- On-chain identity verification
- Sui Development -- zkLogin's home chain
- Zero Knowledge -- The cryptographic foundation
- Product Engineering -- Engineering standards
- Trust Architecture -- Trust infrastructure patterns
Links
- identity.foundation -- Decentralized identity standards
- Sui zkLogin Docs -- Official technical reference
- Sui zkLogin SDK -- @mysten/zklogin TypeScript utilities
- Better Auth Docs -- Self-hosted auth library
- Clerk Docs -- Managed auth service
Questions
At what point does "someone else manages identity" become "someone else owns your users"?
- Which evaluation dimensions in the checklist above matter most for your current build phase vs your next phase?
- If zkLogin eliminates the wallet UX barrier, what's left preventing Web3 auth from replacing Web2 auth entirely?
- When Better Auth now maintains Auth.js, does the "ecosystem size" argument for alternatives still hold?
- What breaks in your testing pipeline if your auth provider has an outage?