Login redirects and subscription paywalls
Supacharger has three related settings, but they do different jobs:
| Setting | What it controls | What it does not control |
|---|---|---|
USER_REDIRECTS.AUTHED_USER.LOGIN_REDIRECT_DESTINATION | The normal destination after password sign-in and after a successful magic-link or social OAuth callback | General “home” links and access control |
USER_REDIRECTS.AUTHED_USER.HOME_PATH | The authenticated home used by general navigation and flows such as completed password reset | The PKCE callback destination |
BILLING_ACCESS.REQUIRED | Whether the magic-link/social callback checks billing access and diverts a user without access | A site-wide route guard or database authorisation policy |
Protected server routes use three access levels:
| Boundary | Checks | Appropriate routes |
|---|---|---|
requireVerifiedUser() | Verified, non-anonymous identity according to configuration | Profile setup and other identity recovery |
requireOnboardedUser() | Verified identity, then configured profile completion | Subscription acquisition |
requireAppAccess() | Verified identity, onboarding first, then configured billing access | Full product routes |
A recovery destination must not inherit the guard for the condition it recovers. Route groups can give /account/setup-profile a verified-only layout and /account/billing/subscribe an onboarded layout without changing either public URL.
Redirect order in the current core
For a magic link or social provider, Supabase first returns the browser to the allow-listed application callback, normally /auth/callback. Supacharger then processes the result in this order:
- Exchange the PKCE code for a session and verify that a user exists.
- If
POST_SIGN_IN_ONBOARDING.REQUIREDis enabled and the profile is incomplete, redirect toPOST_SIGN_IN_ONBOARDING.REDIRECT_PATH. - If
BILLING_ACCESS.REQUIREDis enabled, call the server-side billing-access function. A user without access is redirected toBILLING_ACCESS.REDIRECT_PATH. - Otherwise, redirect to
LOGIN_REDIRECT_DESTINATIONand add the one-time successful-login notice.
In compact form:
Supabase callback
-> valid session?
-> required profile complete?
-> required billing access present?
-> LOGIN_REDIRECT_DESTINATION
Password sign-in navigates directly to LOGIN_REDIRECT_DESTINATION; it does not run callback policy in /auth/callback. The matched protected server layout then enforces the appropriate verified, onboarded, or full-app boundary before rendering. Proxy remains claims-only and performs neither database check.
BILLING_ACCESS.REQUIRED: true protects the canonical authenticated layout and callback journey, but it is not a substitute for handler-specific authorisation. Enforce entitlement checks in protected APIs and Server Actions that do not render through that layout, and keep Supabase Row Level Security as the final database boundary where appropriate.
Recommended configurations
One authenticated landing page, no forced subscription
Use this when users may enter the product without paying:
USER_REDIRECTS: {
AUTHED_USER: {
HOME_PATH: '/app',
AUTHGUARD_REDIRECT_DESTINATION: '/app',
LOGIN_REDIRECT_DESTINATION: '/app',
},
},
BILLING_ACCESS: {
REQUIRED: false,
FEATURE_LOOKUP_KEY: null,
REDIRECT_PATH: '/account/billing/subscribe?full=1',
},
This is the simplest default. All normal authenticated navigation and successful sign-ins converge on /app. Paid features should check their own entitlement when used.
Public marketing home and authenticated product home
If / is a public marketing page, do not use / as the authenticated destination unless returning signed-in users to marketing is deliberate:
USER_REDIRECTS: {
UNAUTHED_USER: {
HOME_PATH: '/',
AUTHGUARD_REDIRECT_DESTINATION: '/account/login',
LOGOUT_REDIRECT_DESTINATON: '/',
},
AUTHED_USER: {
HOME_PATH: '/dashboard',
AUTHGUARD_REDIRECT_DESTINATION: '/dashboard',
LOGIN_REDIRECT_DESTINATION: '/dashboard',
},
},
Keeping the three authenticated destinations aligned avoids surprising differences between login, “home”, and attempts to revisit the login page.
LOGOUT_REDIRECT_DESTINATON must be an application-relative path beginning with one /, never an absolute or protocol-relative URL. The managed logout button receives this path as JSON from POST /account/logout after the SSR session is cleared. A developer-owned direct link may use GET /account/logout, which clears the same session and responds with 303 plus that relative path in Location. The browser resolves both forms against the origin it opened rather than NEXT_PUBLIC_SITE_URL.
Callback subscription detour
Use this only when passwordless/social callbacks should send users without the required access to the subscription page:
BILLING_ACCESS: {
REQUIRED: true,
FEATURE_LOOKUP_KEY: 'product_access',
REDIRECT_PATH: '/account/billing/subscribe?full=1',
},
FEATURE_LOOKUP_KEY should be a stable entitlement lookup key. A value of null uses the compatibility rule of any trialing or active Subscription. The redirect path must exist beneath an onboarded-only boundary and must remain reachable by a profile-complete authenticated user who does not yet have access. Placing it beneath requireAppAccess() creates a self-redirect loop.
If the whole product must be paywalled, also add server-side entitlement enforcement to protected page layouts, route handlers, Server Actions, and APIs. Apply the same policy to password sign-in so every authentication method behaves consistently. A successful Stripe Checkout return is not itself proof of access; use the local entitlement projection populated by webhooks and reconciliation.
Different post-login and home destinations
The two paths may deliberately differ:
AUTHED_USER: {
HOME_PATH: '/app',
AUTHGUARD_REDIRECT_DESTINATION: '/app',
LOGIN_REDIRECT_DESTINATION: '/welcome',
},
Use this only for an unconditional post-login landing page. For conditional profile setup, use POST_SIGN_IN_ONBOARDING instead; it runs before the billing check and normal callback destination. Ensure /welcome does not redirect an authenticated user back to login or create a loop.
Supabase URL Configuration is a separate layer
These Supacharger values are application paths after a session has been established. They do not replace the hosted Supabase settings under Authentication → URL Configuration.
- Set the Supabase Site URL to the production origin.
- Add the exact production callback URL, such as
https://example.com/auth/callback, to Redirect URLs. - Add the password-reset and confirmation destinations used by the project.
- Add localhost and preview URLs only for the environments that need them; prefer exact production paths over broad wildcards.
- Keep
NEXT_PUBLIC_SITE_URLaligned with the deployed origin so Supacharger builds the same callback origin that Supabase allows.
Supabase validates the full redirectTo URL before returning a passwordless or social authentication flow. After the browser reaches /auth/callback, Supacharger applies the onboarding, billing, and login-destination decisions described above. See the official Supabase Redirect URLs guide.
Release checklist
- Every configured path starts with
/and exists in the application. - The onboarding destination inherits only
requireVerifiedUser()and the subscription destination inherits onlyrequireOnboardedUser(). - No recovery response repeats the same effective URL after one recovery hop.
- All enabled authentication methods reach the intended product destination.
- Password, magic-link, OTP, and social login are tested separately because they do not all use
/auth/callback. - Paid pages and APIs reject missing entitlements on the server, independently of browser redirects.
- Supabase RLS protects paid or private database data where client access is possible.
- The hosted Supabase callback allow-list and
NEXT_PUBLIC_SITE_URLmatch production.