> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hexclave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Supabase

> Integrate Hexclave with Supabase RLS

This guide shows how to integrate Hexclave with Supabase row level security (RLS).

> [!NOTE]
>
> This guide only focuses on the RLS/JWT integration and does not sync user data between Supabase and Stack. You should use [webhooks](https://docs.hexclave.com/guides/apps/webhooks/overview.md) to achieve data sync.

## Setup

Let's create a sample table and some RLS policies to demonstrate how to integrate Hexclave with Supabase RLS. You can apply the same logic to your own tables and policies.

**1. Setup Supabase**

First, let's create a Supabase project, then go to the [SQL Editor](https://supabase.com/dashboard/project/_/sql/new) and create a new table with some sample data and RLS policies.

```sql title="Supabase SQL Editor" theme={null}
-- Create the 'data' table
CREATE TABLE data (
  id bigint PRIMARY KEY,
  text text NOT NULL,
  user_id UUID
);

-- Insert sample data
INSERT INTO data (id, text, user_id) VALUES
  (1, 'Everyone can see this', NULL),
  (2, 'Only authenticated users can see this', NULL),
  (3, 'Only user with specific id can see this', NULL);

-- Enable Row Level Security
ALTER TABLE data ENABLE ROW LEVEL SECURITY;

-- Allow everyone to read the first row
CREATE POLICY "Public read" ON "public"."data" TO public
USING (id = 1);

-- Allow authenticated users to read the second row
CREATE POLICY "Authenticated access" ON "public"."data" TO authenticated
USING (id = 2);

-- Allow only the owner of the row to read it
CREATE POLICY "User access" ON "public"."data" TO authenticated
USING (id = 3 AND auth.uid() = user_id);
```

**2. Setup a new Next.js project**

Now let's create a new Next.js project and install Hexclave and Supabase client. (more details on [Next.js setup](https://nextjs.org/docs/getting-started/installation), [Hexclave setup](https://docs.hexclave.com/guides/getting-started/setup.md), and [Supabase setup](https://supabase.com/docs/guides/getting-started/quickstarts/nextjs))

```bash title="Terminal" theme={null}
npx create-next-app@latest -e with-supabase stack-supabase
cd stack-supabase
```

Then follow the [Hexclave setup prompt](https://docs.hexclave.com/guides/getting-started/setup.md). Choose **Next.js** and **Supabase** in the setup builder, then copy the generated prompt into your coding agent.

Now copy the environment variables from the Supabase dashboard to the `.env.local` file:

* `NEXT_PUBLIC_SUPABASE_URL`
* `NEXT_PUBLIC_SUPABASE_ANON_KEY`
* `SUPABASE_JWT_SECRET`

Copy environment variables from the Hexclave dashboard to the `.env.local` file.

* `NEXT_PUBLIC_HEXCLAVE_PROJECT_ID`
* `NEXT_PUBLIC_HEXCLAVE_PUBLISHABLE_CLIENT_KEY`
* `HEXCLAVE_SECRET_SERVER_KEY`

**3. Set up Supabase client**

Now let's create a server action that mints a supabase JWT with the Hexclave user ID if the user is authenticated.

```tsx title="/utils/actions.ts" theme={null}
'use server';

import { hexclaveServerApp } from "@/hexclave/server";
import * as jose from "jose";

export const getSupabaseJwt = async () => {
  const user = await hexclaveServerApp.getUser();

  if (!user) {
    return null;
  }

  const token = await new jose.SignJWT({
    sub: user.id,
    role: "authenticated",
  })
    .setProtectedHeader({ alg: "HS256" })
    .setIssuedAt()
    .setExpirationTime('1h')
    .sign(new TextEncoder().encode(process.env.SUPABASE_JWT_SECRET));

  return token;
};
```

And now create a helper function to create a Supabase client with the JWT signed by the server action

```tsx title="/utils/supabase-client.ts" theme={null}
import { createBrowserClient } from "@supabase/ssr";
import { getSupabaseJwt } from "./actions";

export const createSupabaseClient = () => {
  return createBrowserClient(
    process.env.NEXT_PUBLIC_SUPABASE_URL!,
    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
    { accessToken: async () => await getSupabaseJwt() || "" }
  );
}
```

**4. Fetch data from Supabase**

Let's create an example page that fetches data from Supabase and displays it.

```tsx title="/app/page.tsx" theme={null}
'use client';

import { createSupabaseClient } from "@/utils/supabase-client";
import { useHexclaveApp, useUser } from "@hexclave/next";
import { useEffect, useState } from "react";

export default function Page() {
  const app = useHexclaveApp();
  const user = useUser();
  const supabase = createSupabaseClient();
  const [data, setData] = useState<null | any[]>(null);

  useEffect(() => {
    supabase.from("data").select().then(({ data }) => setData(data ?? []));
  }, []);

  const listContent = data === null ?
    <p>Loading...</p> :
    data.length === 0 ?
      <p>No notes found</p> :
      data.map((note) => <li key={note.id}>{note.text}</li>);

  return (
    <div>
      {
        user ?
        <>
          <p>You are signed in</p>
          <p>User ID: {user.id}</p>
            <button onClick={async () => await app.redirectToSignOut()}>Sign Out</button>
        </> :
          <button onClick={async () => await app.redirectToSignIn()}>Sign In</button>
      }
      <h3>Supabase data</h3>
      <ul>{listContent}</ul>
    </div>
  )
}
```

Now you should be able to compare the data you can view with an anonymous user, an authenticated user. You can also add your user Id to the row 3 of the Supabase table, and you should be able to see the row if and only if you are signed in with that user.

You can find the full example [here on GitHub](https://github.com/hexclave/hexclave/tree/main/examples/supabase).
