Kinde and edge worker services
Integrations
User authentication and secure data access are critical components of modern web applications. Kinde simplifies the process by handling user authentication, managing session tokens, and offering robust user management features.
When combined with Supabase’s powerful database management and PostgreSQL’s Row-Level Security (RLS) policies, you can create a secure, scalable application that ensures user-specific data access.
In this guide, we will walk through integrating Kinde and Supabase. We’ll use Next.js as the application framework. You can then go on to build a to-do app following this doc.
Sign in to Kinde and on the front page, select Add application.
Enter a name for the application and select Back-end web as the application type.
Select Save. The Quick start page opens.
Select Next.js from the list of back-end SDKs, then select Save.
On the Quick Start page, select either Starter Kit or Existing codebase and follow the setup steps. For either path:
Select Set for each default callback URL to configure your application’s callback settings.
Copy the environment variables. We will use these later.
Select Authentication in the menu.
Enable the authentication types you want your users to sign in with (e.g. Email and Google), and select Save.
Sign in to your Supabase dashboard.
Select or add a new organization to add the project to.
Select New Project.
Enter a project name.
Set a secure password for your database.
Select a database region that best suits your application.
Select Create new project.
In the Project settings, go to API Keys and select Create new API keys.
Copy the Publishable key, we will need it in the upcoming steps.
Go to JWT Keys > JWT Signing Keys.
Select Migrate JWT secret.
You will see a pair of JWT keys in the page. The CURRENT KEY (Legacy HS256) and the STANDBY KEY (ECC P-256). We will mint our own JWT key with a shared secret.
Select the three dots next to the STANDBY KEY
and select Move to previously used.
This will enable you to create a new standby key.
Select Create Standby Key.
From the dropdown of algorithm selection, choose HS256 (Shared Secret).
Your new key is listed as a STANDBY KEY
Select Rotate keys.
Check both confirmation boxes and select Rotate signing key. You will have your shared secret key set as your CURRENT KEY
.
Navigate to SQL Editor and select New SQL Snippet.
Paste the following SQL code into the command window and select Run:
create or replace function get_user_id()returns textlanguage sql stableas $$ select nullif(current_setting('request.jwt.claims', true)::json->>'sub', '')::text;$$;
This function extracts the sub
field from the JSON Web Token (JWT) sent by Kinde auth. The sub
field contains the Kinde user ID, which allows Supabase to authenticate the correct Kinde user.
Run the following command in your terminal window to start a new project with Next.js and Supabase. Follow the on-screen instructions.
npx create-next-app -e with-supabase
Set a name for your project (e.g: kinde-with-supabase
)
Go into the project directory:
cd kinde-with-supabase
Install the Kinde dependency with this command:
npm install @kinde-oss/kinde-auth-nextjs jsonwebtokennpm install --save-dev @types/jsonwebtoken
Create the Kinde auth endpoint in this path app/api/auth/[kindeAuth]:
mkdir -p "app/api/auth/[kindeAuth]"touch "app/api/auth/[kindeAuth]/route.js"
Open the newly created route.js
file, enter the following code, and save the file:
import { handleAuth } from "@kinde-oss/kinde-auth-nextjs/server"export const GET = handleAuth()
Create an environment variables file .env.local
by typing:
touch .env.local
Add the following to your .env.local
file:
KINDE_CLIENT_ID=<kinde_client_id>KINDE_CLIENT_SECRET=<kinde_client_secret>KINDE_ISSUER_URL=https://<your_kinde_business>.kinde.comKINDE_SITE_URL=http://localhost:3000KINDE_POST_LOGOUT_REDIRECT_URL=http://localhost:3000KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000NEXT_PUBLIC_SUPABASE_URL=https://<supabase_project_id>.supabase.coNEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY=<supabase_publishable_key>
To ensure the user is redirected to the homepage after they sign in, update the KINDE_POST_LOGIN_REDIRECT_URL
in your .env.local
file to:
KINDE_POST_LOGIN_REDIRECT_URL=http://localhost:3000
Open the components/auth-button.tsx
file and replace the entire content with the following. This code will replace Supabase Auth functions with Kinde Auth.
import { RegisterLink, LoginLink, LogoutLink, } from "@kinde-oss/kinde-auth-nextjs/components" import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"
import { Button } from "./ui/button"
export async function AuthButton() { const { getUser } = getKindeServerSession() const user = await getUser()
return user ? ( <div className="flex items-center gap-4"> Hey, {user.email}!<LogoutLink className="text-subtle">Log out</LogoutLink> </div> ) : ( <div className="flex gap-2"> <Button asChild size="sm" variant={"outline"}> <LoginLink className="btn btn-ghost sign-in-btn">Sign in</LoginLink> </Button> <Button asChild size="sm" variant={"default"}> <RegisterLink className="btn btn-dark">Sign up</RegisterLink> </Button> </div> ) }
Replace lib/supabase/server.ts
with the following code:
import { getKindeServerSession } from "@kinde-oss/kinde-auth-nextjs/server"import { createServerClient } from "@supabase/ssr"import { cookies } from "next/headers"import jwt from "jsonwebtoken"
export const createClient = async () => { const cookieStore = await cookies()
const { getIdToken } = getKindeServerSession() const idToken = await getIdToken()
let token: string if (idToken) { token = jwt.sign(idToken, process.env.KINDE_CLIENT_SECRET!) } else { token = process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY! }
return createServerClient( process.env.NEXT_PUBLIC_SUPABASE_URL!, process.env.NEXT_PUBLIC_SUPABASE_PUBLISHABLE_OR_ANON_KEY!, { global: { headers: { Authorization: `Bearer ${token}`, }, }, cookies: { getAll() { return cookieStore.getAll() }, setAll(cookiesToSet) { try { cookiesToSet.forEach(({ name, value, options }) => { cookieStore.set(name, value, options) }) } catch (error) { // The `set` method was called from a Server Component. // This can be ignored if you have middleware refreshing // user sessions. } }, }, } )}
Replace lib/supabase/middleware.ts
with the following code:
import { NextResponse, type NextRequest } from "next/server"import { hasEnvVars } from "../utils"
export async function updateSession(request: NextRequest) { const supabaseResponse = NextResponse.next({ request, })
// If the env vars are not set, skip middleware check. You can remove this once you setup the project. if (!hasEnvVars) { return supabaseResponse }
// Do not run code between createServerClient and // supabase.auth.getUser(). A simple mistake could make it very hard to debug // issues with users being randomly logged out.
// IMPORTANT: DO NOT REMOVE auth.getUser()
// IMPORTANT: You *must* return the supabaseResponse object as it is. // If you're creating a new response object with NextResponse.next() make sure to: // 1. Pass the request in it, like so: // const myNewResponse = NextResponse.next({ request }) // 2. Copy over the cookies, like so: // myNewResponse.cookies.setAll(supabaseResponse.cookies.getAll()) // 3. Change the myNewResponse object to fit your needs, but avoid changing // the cookies! // 4. Finally: // return myNewResponse // If this is not done, you may be causing the browser and server to go out // of sync and terminate the user's session prematurely!
return supabaseResponse}
Start the development environment by typing the following in your terminal:
npm run dev
Go to http://localhost:3000 and sign up/sign in to your Kinde application to test the integration.
You’ve successfully integrated Kinde for authentication with Supabase for database management, creating a secure foundation for user-specific data access.
With this integration in place, your application is now equipped to handle user authentication and manage personalized data securely. You can extend this foundation by adding various features and functionalities specific to your application’s requirements, all while maintaining the security and scalability provided by this Kinde-Supabase integration.
Take this one step further by creating a to-do list application following the next guide.