FolioFOLIOdocs
AppApp
BackendBackend
Backend/Authentication
01 / 07

Authentication

Who's who

ClerkOAuthJWT

Overview

We use Clerk for everything authentication related. Users can sign in with Apple, Google, or email. Clerk gives us a JWT that we pass to Supabase in the Authorization header, and that JWT is what powers Row Level Security on every database query. We never built our own auth layer. No password hashing, no session table, no token refresh logic. Clerk does all of it. The app layout checks isSignedIn on every render and redirects accordingly.

How it works

1

The root _layout.tsx wraps the entire app in a ClerkProvider. It uses a token cache backed by SecureStore so sessions persist across app restarts.

2

The login screen offers three strategies: Apple (useOAuth), Google (useOAuth), and email with a verification code (useSignIn). No passwords anywhere. The email flow sends a 6 digit code to verify ownership.

3

After a successful sign in, Clerk provides a session token. We call getToken({ template: 'supabase' }) to get a Supabase compatible JWT. This token gets passed to the Supabase client and to all edge function calls.

4

The same Clerk user ID also gets linked to RevenueCat via Purchases.logIn(userId), so subscription state follows the user across devices.

5

Auth state changes are handled reactively. The (auth)/_layout.tsx checks useAuth().isSignedIn and either shows the auth screens or redirects to the main app. No manual navigation logic needed.

6

Onboarding completion is tracked separately in AsyncStorage. Once you have seen the welcome carousel, future opens skip straight to the login screen.

Key decisions

Clerk over rolling our own auth

Auth is one of those things that looks simple until you actually build it. Session management, token refresh, OAuth callback handling, email verification, rate limiting on login attempts. Clerk handles all of that out of the box. The React Native SDK gives us useAuth, useUser, and useOAuth hooks that just work. The tradeoff is a dependency on a third party service, but the time saved and the security guarantees are worth it.

JWT template for Supabase integration

Instead of having Supabase manage its own auth, we use a JWT template to generate tokens Supabase understands. This means one auth provider (Clerk) and one database (Supabase) without any auth sync issues. The JWT flows through to RLS policies, so every database query is automatically scoped to the authenticated user.

No separate user profile table

Clerk stores the user name, email, and avatar. We do not duplicate this in Supabase. That means no sync issues between auth data and profile data. If we ever need custom fields, Clerk supports user metadata. One less table to worry about.

CLERKAppleGoogleEmailJWT Token{ sub: user_id }SupabaseRLS filteringRevenueCatlogIn(userId)Session persisted

Quick Reference

Filesapp/_layout.tsx, app/(auth)/login.tsx, app/(auth)/email-login.tsx
TablesN/A (Clerk manages auth externally)
Edge FunctionsAll edge functions validate JWT from Authorization header
Components
ClerkProvideruseAuthuseOAuthuseSignInuseUser
NextDatabase