Architecture decision ADR-003

Use Clerk for Authentication Over Custom Auth or Auth0

Accepted · 2026-05-10

Historical decision text is preserved. Accepted describes the decision, not deployment of every capability discussed. Consult the Architecture and Infrastructure tabs for the verified running system.

Date: 2026-05-10
Status: Accepted
Deciders: Daniel Meza


Context and Problem Statement

Urza's Wallet requires user authentication for saved comparisons, rate alerts, and personalized rankings. The authentication layer must:

The NerdWallet reference architecture recommends a dedicated CIAM (Customer Identity and Access Management) platform (Auth0, Okta, AWS Cognito, or self-hosted Keycloak) and explicitly warns against rolling custom session management. The question is which provider best fits the Urza's Wallet constraints: team size, Railway deployment model, Costa Rica market, and Phase 1 scope.


Decision Drivers


Considered Options

  1. Clerk — managed identity platform with Next.js-first SDK, Railway-compatible, no self-hosting.
  2. Auth0 (by Okta) — mature CIAM platform, broad ecosystem, Next.js SDK available.
  3. Supabase Auth — open-source auth built into the Supabase platform; can be used standalone.
  4. AWS Cognito — AWS-managed identity service; integrates well within AWS but is more complex outside it.
  5. Keycloak (self-hosted on Railway) — open-source OIDC server; full control; significant ops overhead.
  6. Custom session auth (Lucia, iron-session, jose) — custom-built session management using open-source libraries.

Decision Outcome

Option 1: Clerk is adopted as the authentication provider for Phase 1.

Rationale:

The integration model:

  1. clerkMiddleware() runs on every Next.js request. It validates the Clerk session cookie and attaches auth() to the request context.
  2. Protected Next.js routes use auth().protect() in the middleware config. Unauthenticated requests are redirected to Clerk's hosted login page.
  3. The Backend API Service validates Clerk tokens by calling clerkClient.verifyToken() in the Auth Adapter. The clerk_user_id from the validated token is used as the canonical user identifier throughout the system.
  4. The browser never receives a raw JWT. Clerk's SDK manages HttpOnly session cookies.

Positive Consequences

Negative Consequences / Trade-offs


Pros and Cons of the Options

Option Next.js App Router Railway Fit Ley 8968 DPA Ops Overhead MAU Cost (5k)
Clerk (chosen) Excellent (primary use case) SaaS (no Railway service) Available None Free (< 10k MAU)
Auth0 Good SaaS (no Railway service) Available None ~$23/month (Essentials)
Supabase Auth Good SaaS or self-hosted Available Low (if SaaS) Free (< 50k MAU)
AWS Cognito Adequate Requires AWS Available Low-medium ~$0 (< 50k MAU free tier)
Keycloak (self-hosted) Requires manual OIDC integration Moderate Railway overhead Full control High Infrastructure cost only
Custom session auth Manual implementation Zero Full control High (security risk) Zero

Auth0 was the closest alternative. Its Next.js SDK is mature and it offers a generous free tier. The deciding factors against Auth0 were: Clerk's deeper App Router integration (Auth0's Next.js SDK uses an older pattern that requires more boilerplate for RSC), and Clerk's lower barrier to getting a working flow in production (better quickstart docs, more active Next.js community).

Supabase Auth was also considered. It is a strong option if the team later adopts Supabase as the PostgreSQL provider. Since Urza's Wallet uses Railway-managed PostgreSQL, adding Supabase solely for auth would be a mixed-provider setup that adds complexity.

Custom session auth (e.g., iron-session + jose) was rejected. As the NerdWallet reference architecture notes: "Rolling custom session management without OIDC (OpenID Connect) is an anti-pattern. Non-standard session handling is a common source of security vulnerabilities." Building production-grade session management (rotation, revocation, MFA, breach detection) is a multi-week engineering effort that is not differentiated work for Urza's Wallet.


References