This guide uses Next.js, but you can apply the same concepts to other frameworks or languages. We’re expanding our framework examples, so stay tuned for more!
1

Create Supabase account

Sign up for a Supabase account if you don’t have one already.
2

Create new project

From the Supabase dashboard, click ‘New Project’ to create a project for your application.
create new project
3

Create users table

In your project dashboard, navigate to ‘Database’ and create a new ‘users’ table. This table will store user information from Hanko. Add these columns beyond the default ‘id’:
  • ‘user_id’ (to match Hanko’s user ID)
  • ‘email’ (to store user email addresses)
create new project
4

Configure environment variables

In your project dashboard, go to ‘Project Settings’ > ‘API’. Copy the ‘URL’ and ‘service_role’ key, then add them to your .env.local file.
.env.local
NEXT_PUBLIC_HANKO_API_URL=https://f4****-4802-49ad-8e0b-3d3****ab32.hanko.io

NEXT_PUBLIC_SUPABASE_PROJECT_URL=YOUR_SUPABASE_PROJECT_URL
SUPABASE_SERVICE_ROLE_KEY=YOUR_SUPABASE_SERVICE_ROLE_KEY
5

Install Supabase JavaScript Client

Add the Supabase client library to your application (assuming Hanko Auth is already configured).
npm install @supabase/supabase-js
6

Set up Supabase Client

lib/supabase.ts
import { createClient } from "@supabase/supabase-js";

export const supabase = createClient(
  process.env.NEXT_PUBLIC_SUPABASE_PROJECT_URL!,
  process.env.SUPABASE_SERVICE_ROLE_KEY!
);
7

Create user synchronization API

Build an API endpoint to sync user data between Hanko and Supabase.
app/api/create-user/route.ts
import { NextResponse } from "next/server";
import { supabase } from "@/lib/supabase";

export async function POST(req: Request, res: Response) {
  try {
    const user = await req.json();

    if (!user) {
      return new NextResponse("Unauthorized", { status: 401 });
    }

    let supauser;

    try {
      const { data, error } = await supabase
        .from("users")
        .select("*")
        .eq("user_id", user.id)
        .single();

      if (error) {
        console.error(error);
      }

      supauser = data;

      if (!supauser) {
        const { data, error } = await supabase
          .from("users")
          .insert([{ user_id: user.id, email: user.email }]);

        if (error) {
          console.error(error);
        }

        supauser = data;
      }
    } catch (error) {
      console.error(error);
    }

    const user_data = {
      ...user,
      id: supauser?.id,
    };

    return new NextResponse(JSON.stringify(user_data), { status: 200 });
  } catch (error) {
    console.error("[CREATEUSER_ERROR]", error);
    return new NextResponse("Internal Error", { status: 500 });
  }
}
8

Integrate with HankoAuth component

Modify your Hanko authentication component to automatically sync user data when onSessionCreated triggers.
components/hanko/HankoAuth.tsx
"use client";

import { useEffect, useCallback, useState } from "react";
import { useRouter } from "next/navigation";
import { register, Hanko } from "@teamhanko/hanko-elements";

const hankoApi = process.env.NEXT_PUBLIC_HANKO_API_URL || '';

export default function HankoAuth() {
  const router = useRouter();

  const [hanko, setHanko] = useState<Hanko>();

  useEffect(() => setHanko(new Hanko(hankoApi)), []);

  const redirectAfterLogin = useCallback(() => {
    // successfully logged in, redirect to a page in your application
    router.replace("/dashboard");
  }, [router]);

  useEffect(
    () =>
      hanko?.onSessionCreated(async () => {
        const user = await hanko.user.getCurrent()

        const fetchData = async () => {
          if (!user) {
            console.error('No user data')
            return
          }
          try {
            const response = await fetch('/api/create-user', {
              method: 'POST',
              body: JSON.stringify(user),
            })

            if (!response.ok)
              throw new Error(`HTTP error! status: ${response.status}`)
          } catch (error) {
            console.error('Fetch Error: ', error)
          }
        }
        await fetchData()
        redirectAfterLogin();
      }),
    [hanko, redirectAfterLogin]
  );

  useEffect(() => {
    register(hankoApi).catch((error) => {
      console.error(error);
    });
  }, []);

  return <hanko-auth />;
}