Skip to main content

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

DimensionQuestionWeight
TestingCan you test auth flows without hitting external APIs?High
Staging parityCan you replicate prod auth config in staging?High
CI reliabilityDo auth tests pass consistently without flakes?High
Type safetyDoes the SDK provide full TypeScript inference?Medium
Framework fitDoes it support App Router, middleware, RSC natively?High
Migration pathCan you switch away without losing user data?Medium

Operate Fitness

DimensionQuestionWeight
Multi-tenantOrgs, roles, permissions -- built-in or custom?High
MFATOTP, SMS, passkeys -- which are supported?Medium
Session controlCan admins revoke sessions, force logout?Medium
Rate limitingIs brute-force protection built-in or DIY?Medium
Webhook supportCan you react to auth events server-side?Medium
ComplianceSOC2, GDPR, data residency -- what's covered?Varies

Cost Fitness

DimensionQuestionWeight
Pricing modelFree tier limits? Per-seat? Per-MAU?High
Infra overheadSelf-hosted = your DB costs. Managed = their pricing.Medium
Vendor lock-inHow much custom code ties you to this provider?High
Scale ceilingAt 10K, 100K, 1M users -- what breaks or costs more?Medium

Trust Fitness

DimensionQuestionWeight
Data ownershipWhere do user credentials and sessions live?High
Key managementWho controls the signing keys?High
PrivacyWhat does the provider see about your users?Medium
DecentralizationCan 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.

#CheckSymptom If WrongFix
1Env vars present?Cryptic SDK init failure after 45s timeoutFail fast: validate keys exist before auth setup. Create .env.test from .env.test.sample
2Token before navigation?Blank page, no error (managed providers)setupClerkTestingToken() before page.goto(), not after
3Single auth setup call?Flaky intermittent failuresclerk.signIn() OR setupClerkTestingToken(), never both
4Storage state dir exists?Works locally, fails in CImkdir -p playwright/.clerk in CI setup step
5One test user per worker?Bot detection, account lockoutSeparate credentials per parallel shard
6Test DB running? (self-hosted)Connection refused, silent test skipHealth check before test suite: pg_isready -p 5433
7Correct mock layer?Tests pass but miss real bugsUnit/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.

ProviderModelStrengthTesting Story
ClerkManaged SaaSFastest setup, best DXRequires mocks + tokens
Better AuthSelf-hostedFull DB control, freeTest DB, no external deps
Auth.jsSelf-hostedLarge ecosystem, adaptersTest DB, callback-heavy
Auth0Managed SaaSEnterprise featuresRequires mocks
KindeManaged SaaSB2B focus, permissionsSimilar to Clerk
AuthentikSelf-hostedFull IdP, LDAP/SAMLComplex setup
OktaManaged SaaSEnterprise SSO standardEnterprise tooling

Decentralized (Web3)

User owns their identity. Verification without centralized authority. Zero-knowledge proofs preserve privacy.

ProviderMechanismPrivacy Model
Sui zkLoginOAuth + ZK proofsFull on-chain privacy
WorldcoinBiometric + ZK proofsProof of personhood
Polygon IDZK verifiable credentialsSelective disclosure
SpruceIDDID + Sign-In with EthereumSelf-sovereign
Dynamic.xyzMulti-chain wallet authWallet-based
zPassZK proofs on AleoFull privacy

Three Factors

FactorWhat It IsExamples
Knowledge (something you know)Secret only the user knowsPassword, PIN, security question
Possession (something you have)Device or token the user holdsPhone, hardware key, wallet
Inherence (something you are)Biometric traitFingerprint, 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

PropertyWhat It Means
On-chain privacyOnly ZK proof and ephemeral signature visible -- no personal data
UnlinkabilityThird parties cannot connect Sui address to OAuth identity
Optional disclosureUsers can opt-in to verify identity for a specific address
Two-factor securityAttacker 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

ComponentMysten-hostedSelf-hosted
ZK Proverprover-dev.mystenlabs.com/v1Deploy your own prover service
Salt serviceNone providedYour backend + database (required)
EnokiManaged zkLogin + invisible walletsN/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.

Hybrid Architecture

For platforms like Stackmates that bridge Web2 and Web3, the auth stack is layered:

LayerTechnologyPurpose
App authClerk or Better AuthUser signup, session, RBAC, multi-tenant
Chain identitySui zkLoginOn-chain transactions without wallet UX
Proof of personWorldcoin/Polygon IDSybil 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

Context

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?