We’re using Next.js in this guide, but don’t worry, you can apply the same concepts to other frameworks or languages. We’re working on adding examples with different frameworks, so stay tuned!

1

Create an account on Supabase

Create an account on Supabase if you haven’t yet.

2

Create a new project

Once you’ve created an account, you’ll be redirected to the dashboard. Click on ‘New Project’ to create a new project.

create new project
3

Create users table

Now, on the project dashboard, choose ‘Database’ and create a new ‘users’ table. We’ll be using this table to add new user info on signup. In addition to the default ‘id’ column, add ‘user_id’ and ‘email’ columns.

create new project
4

Get URL and service_role key from Supabase and add it to your project

Now in the project dashboard, select ‘Project Settings’ from the left sidebar and then click on ‘API’. Copy the ‘URL’ and ‘service_role’ key and paste them in 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

Assuming you’ve already set up Hanko Auth, you’ll need to install supabase to your app.

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 an API

Next up, you’ll create an api to add new user info to the users table.

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

Use the API in HankoAuth component

Use the API to add a new user to the ‘users’ table, as soon as user is authenticated and onAuthFlowCompleted is triggered.

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(() => {
    import("@teamhanko/hanko-elements").then(({ Hanko }) =>
      setHanko(new Hanko(hankoApi))
    );
  }, []);

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

  useEffect(
    () =>
      hanko?.onAuthFlowCompleted(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 />;
}