Course lesson
Implement Authentication for Supabase with OAuth and Github
Supabase supports a collection of auth strategies - Email and password, passwordless and OAuth. In this lesson, we look at implementing OAuth with GitHub.
- Duration
- 9 min
- Access
- Free
- Transcript
- Retained from source evidence
Supabase supports a collection of auth strategies - Email and password, passwordless and OAuth. In this lesson, we look at implementing OAuth with GitHub.
In order to do this, we create a new GitHub OAuth app, and configure Supabase to use its Client ID and Secret. Additionally, we create a <Login /> component that uses the Supabase client to sign users in and out.
This identifies a problem that we don't have access to the environment variables required to create a Supabase client outside of loaders or actions. Therefore, we pipe through our SUPABASE_URL and SUPABASE_ANON_KEY from the Loader function, and create a singleton Supabase client, to use across our components.
Lastly, we look at sharing this single instance of Supabase through the Outlet Context and declare types to ensure we have TypeScript helping us out throughout the application.
Code Snippets
Expose environment variables from the server
export const loader = async ({}: LoaderArgs) => {
const env = {
SUPABASE_URL: process.env.SUPABASE_URL!,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
};
return json({ env });
};Access env in component
const { env } = useLoaderData<typeof loader>();Create a singleton Supabase client
const [supabase] = useState(() =>
createClient<Database>(env.SUPABASE_URL, env.SUPABASE_ANON_KEY)
);Share global variables with Outlet Context
<Outlet context={{ supabase }} />Consuming Outlet Context
const { supabase } = useOutletContext<SupabaseOutletContext>();Logging in with GitHub
await supabase.auth.signInWithOAuth({
provider: "github",
});Logging out
await supabase.auth.signOut();Entire root component
import { json, LoaderArgs, MetaFunction } from "@remix-run/node";
import {
Links,
LiveReload,
Meta,
Outlet,
Scripts,
ScrollRestoration,
useLoaderData,
} from "@remix-run/react";
import { createClient, SupabaseClient } from "@supabase/supabase-js";
import { useState } from "react";
import type { Database } from "db_types";
type TypedSupabaseClient = SupabaseClient<Database>;
export type SupabaseOutletContext = {
supabase: TypedSupabaseClient;
};
export const meta: MetaFunction = () => ({
charset: "utf-8",
title: "New Remix App",
viewport: "width=device-width,initial-scale=1",
});
export const loader = async ({}: LoaderArgs) => {
const env = {
SUPABASE_URL: process.env.SUPABASE_URL!,
SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!,
};
return json({ env });
};
export default function App() {
const { env } = useLoaderData<typeof loader>();
const [supabase] = useState(() =>
createClient<Database>(env.SUPABASE_URL, env.SUPABASE_ANON_KEY)
);
return (
<html lang="en">
<head>
<Meta />
<Links />
</head>
<body>
<Outlet context={{ supabase }} />
<ScrollRestoration />
<Scripts />
<LiveReload />
</body>
</html>
);
}