Skip to content

ADR 0005: Clerk for Authentication

  • Status: Accepted
  • Date: 2026-04-14
  • Deciders: Ideony team

Ideony needs consumer and professional sign-up with social login (Google/Apple/Facebook), email/OTP flows, role-based access control, and webhook events for user lifecycle management. Building this from scratch would be a significant, security-critical investment that delays the product.

Use Clerk as the identity platform. The backend verifies JWTs via @clerk/backend verifyToken(). Webhooks are verified with svix signature using req.rawBody (not JSON.stringify(body)). The mobile app uses @clerk/clerk-expo (not @clerk/expo). Role is stored in Clerk public metadata and extracted via @CurrentUser() — never from request body.

  • Social login, OTP, MFA, and session management are handled out of the box.
  • Deep theming via appearance.elements (not just variables) enables Airbnb-quality UI.
  • Clerk BAPI session creation for E2E tests bypasses FAPI rate limits (429s).
  • Clerk webhooks via svix provide reliable user lifecycle events.
  • @clerk/clerk-expo v2.19.31 exposes old API (create/prepareFirstFactor/attemptFirstFactor/setActive); newer finalize/password/emailCode API not available in types.
  • ClerkAPIResponseError does not extend Error; requires a getClerkMessage() helper.
  • safeIdentifier in Clerk responses is obfuscated (e.g., j**n@example.com); match by strategy, not value.
  • Auth.js (NextAuth) — rejected: React Native support is limited; not designed for mobile-first.
  • Supabase Auth — rejected: couples auth to a specific database platform; Ideony uses its own PostgreSQL.
  • Custom JWT auth — rejected: security-critical, high maintenance, delays MVP.