Skip to content

Fix sticky B2C paywall loop by using Clerk subscription state#31

Merged
codybmenefee merged 1 commit intomainfrom
codex/fix-b2c-subscription-source
Feb 9, 2026
Merged

Fix sticky B2C paywall loop by using Clerk subscription state#31
codybmenefee merged 1 commit intomainfrom
codex/fix-b2c-subscription-source

Conversation

@codybmenefee
Copy link
Copy Markdown
Owner

Root cause

The app gate relied on useAuth().has({ plan }) session claims, but prod sessions with an active org only exposed pla: "o:free_org" for this user. That made all B2C checks fail (early_access false) even when the user had a user subscription.

There was also a scope format mismatch in our helper: it expanded to u:/o: while Clerk expects user:/org: in has() checks.

Fix

  • Correct scope expansion/normalization to include user:/org: (plus short-form back-compat).
  • Add useResolvedBillingAccess hook that resolves access from Clerk Billing subscription (clerk.billing.getSubscription({})) using active user subscription items.
  • Keep session-based checks as fallback only.
  • Wire both /app and /subscribe to this shared resolved billing source so gating is consistent.

Validation

  • cd app && npx eslint src/lib/auth/billing.ts src/lib/auth/useResolvedBillingAccess.ts src/routes/app.tsx src/routes/subscribe.tsx
  • cd app && pnpm run build

@codybmenefee codybmenefee merged commit 135e828 into main Feb 9, 2026
1 check passed
@codybmenefee codybmenefee deleted the codex/fix-b2c-subscription-source branch February 9, 2026 05:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant