Authgear and Supabase

Guide on using Authgear together with Supabase database to deliver a secure and scalable application

User authentication is a foundational part of any modern web application but getting it right is notoriously difficult. That’s where Authgear comes in. Authgear handles user registration, login flows, session management, and advanced security features like biometric login, 2FA, and social sign-ins out of the box.

Pairing Authgear with Supabase's Postgres database and powerful Row-Level Security (RLS) gives you a secure, scalable foundation for building user-specific applications.

In this guide, you’ll learn how to integrate Authgear and Supabase using React.js to build a basic CRUD application.

Simple instrument tracking app where users can manage their personal collection after logging in with Authgear
Simple instrument tracking app where users can manage their personal collection after logging in with Authgear

We will walkthrough how to authenticate users with Authgear, exchange tokens via a Supabase Edge Function, apply RLS policies based on Authgear-issued JWTs, and connect it all in a modern React frontend using Vite.

Full example code

The full example app source code is available on GitHub and can be used as a starting point for your own project: https://github.com/authgear/authgear-example-supabase

What you need

Step 1: Set up an Authgear project

First, configure Authgear to handle authentication for your app.

  1. Create an Authgear Application: Log in to the Authgear Portal and create a new application. Choose Single Page Application as the application type.

  2. Configure OAuth Redirects: In your Authgear app settings, set the redirect URIs:

    • Redirect URI: http://localhost:5173/auth-redirect – this is where Authgear will redirect the browser after a successful login (our React app will handle this route).

    • Post-Logout Redirect URI: http://localhost:5173/ – where to navigate after users log out.

  3. Note Your Authgear Credentials: After creation, note down:

    • The Authgear Endpoint for your app (it will look like https://<your-project>.authgear.cloud).

    • The Client ID of your Authgear application.

We will need these values when initializing Authgear in our React app and in the Supabase function.

Step 2: Set up a Supabase project

Next, prepare your Supabase backend.

  1. Create a Supabase Project: Log in to Supabase Dashboard, create a new project (choose an organization, project name, database password, and region).

  2. Retrieve Project Keys: In your Supabase project, go to Project Settings → API → API keys. Copy the Publishable Key and the URL of your project (e.g., https://xyzcompany.supabase.co).

  3. Get the JWT Secret: Still in Project settings, navigate to JWT Keys and find the Legacy JWT Secret for your project. This is a secret key that Supabase uses to sign and verify JWTs for RLS. Copy the JWT secret value – we will use it in our Edge Function config.\

    Copy the Legacy JWT Secret from the JWT Keys page
  4. (Optional) Install Supabase CLI: If you plan to use the CLI to deploy the Edge Function, install it by following Supabase’s instructions. Alternatively, you can deploy the function via the Dashboard UI.

Step 3: Create an Edge Function to exchange JWTs

Now we set up the critical piece: a Supabase Edge Function that will accept Authgear’s JWT and return a new JWT signed with Supabase’s secret.

  1. Navigate to "Edge Functions" -> "Secrets" and add the two secrets:

    1. AUTHGEAR_ENDPOINT = your Authgear app endpoint (e.g. https://myapp.authgear.cloud).

    2. SB_JWT_SECRET = your Supabase JWT secret (from Step 2 above).

  2. Deploy the Function

    1. Navigate to "Edge Functions" -> "Functions" in Supabase web UI. Copy-paste the following code and deploy it there. Name the function exchange-jwt.

    2. Alternatively, you can use Supabase CLI to build and deploy the Edge Function from your local machine to your Supabase project.

Once deployed, your function is accessible at:

Step 4: Create the database table and RLS policies

Now let’s set up the database table and RLS rules in Supabase. We’ll create a table (instruments) to store items owned by users, and use RLS to ensure each user can only manipulate their own rows.

Open the SQL editor in your Supabase project and run the following SQL commands:

We created a SQL function current_user_id() that returns the JWT’s sub claim (subject) from the current request’s JWT. Supabase’s Postgres has an auth.jwt() function that exposes the JWT claims of the requester; auth.jwt() ->> 'sub' extracts the sub field as text.

  • The instruments table has a user_id column which will store the Authgear user’s ID for each instrument.

  • We enabled RLS on the table, which means by default no rows can be accessed unless allowed by a policy.

We then defined four policies, one for each CRUD operation (SELECT, INSERT, UPDATE, DELETE). Each policy is limited to the authenticated role and uses a condition requiring that the row’s user_id matches the user’s id from the JWT.

Step 5. Build the React app with Supabase Client

Now for the frontend. We will create a React app using Vite, integrate Authgear’s SDK for authentication, and configure the Supabase client to use our token exchange flow automatically.

Dependencies

  1. Scaffold a React App by npm create vite@latest my-app -- --template react

  2. Follow the guide for build SPA in here: React to setup a basic react app with Authgear authentication

  3. Install the Supabase library by

  4. Configure the Environment Variables in .env and make the Supabase URL and Publishable key available. You .env.local should look like:

Configure the Supabase Client

Now we can set up the Supabase JS client to use our Authgear token. Create a new file my-app/src/lib/supabase.js and add the following:

In this configuration:

  • We disable autoRefreshToken and persistSession in Supabase’s client so that Authgear is the source of truth for the session.

  • We provide an accessToken async function. The Supabase Client will call this function every time it needs a JWT for an authenticated request. In our case, that is every query to our instruments table.

  • In accessToken(), we first ensure Authgear’s token is fresh by calling authgear.refreshAccessTokenIfNeeded().

  • We then get authgear.accessToken – this is the current JWT from Authgear’s SDK.

  • If the token exists, we call our exchangeToken() helper, which calls the Edge Function’s endpoint with the Authgear token and receives a Supabase JWT in response.

Build the CRUD functions

After login, use the Supabase client to fetch and manipulate data. For example, to load the current user’s instruments, you can call:

To add a new instrument, call

Similarly, to update or delete, similarly call .update(...) or .delete(...) in the Supabase Client with appropriate filters

6. Run and test the app

We’re ready to test the whole system. Start the development server:

Open http://localhost:5173 in your browser and test the integration.

That's it

You’ve successfully integrated Authgear for authentication with Supabase for secure, per-user data access using Row-Level Security.

With this setup, you can take full advantage of Authgear’s powerful authentication features like social logins, 2FA, and secure session management, while leveraging Supabase’s scalable database and built-in RLS to keep user data isolated and protected. This token exchange approach makes it easy to use Authgear (or any other JWT-based provider) with Supabase.

Last updated

Was this helpful?