In the Supabase dashboard , go to Authorization > Providers
, and configure the provider you want with the necessary credentials
In the nextjs project, create env.local
in the root of the project and add:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
You can get these values from your Supabase dashboard Settings > API
In src/lib
directory, create a supabase
directory and add:
This file contains the function used to call the supabase client in a nextjs client component
This file contains 3 functions used to call the supabase client on the server
createSupabaseServerClient()
: used in server actions and route handlerscreateSupabaseServerComponentClient()
: used in server componentscreateSupabaseReqResClient()
: used in middlewareFor more information check out this video
Create the middleware.ts
in your src
directory. This intercepts any route specified in the matcher
and is used to refresh the supabase session cookies and also redirect users based on whether they're authenticated or not.
This can be used used for creating protected routes.
An alternative method of creating protected routes is highlighted here.
To run the middleware on every route, simply remove the matcher
object from the config.
In the app
directory, create the callback endpoint auth/callback/route.ts
.
This API endpoint uses the code returned from the OAuth provider to sign in the user. The authenticated user is then redirected to the specified URL.
If authentication fails, the user is redirected to an another page specified in the callback.
The user is redirected to this page when the authentication fails.
Create button components to handle login and logout. We need to interact with the button to call the authentication functions, hence we make them client components and use the supabase browser client.
You can specify the OAuth provider you're using in the provider
property in the login function.
The login button also accepts an optional nextUrl
prop which can be used to redirect the user to the specified URL after they have sign in.
Example:
<LoginButton nextUrl="/account" />
const {
data: { session },
error,
} = await createSupabaseServerComponentClient().auth.getSession();
// get user data from session object
const user = session?.user;
NOTE
This value comes directly from the storage medium (usually cookies on the server) and many not be authentic. You can usesupabase.auth.getUser()
instead which authenticates the data by contacting the Supabase Auth server.
Example in src/components/nav-bar.tsx
const {
data: { user },
error,
} = await createSupabaseServerComponentClient().auth.getUser();
Example in src/components/avatar.tsx
To prevent repeating code when fetching the session in client components, create a custom hook useSession()
which returns the user session object.
The custom hook: src/lib/supabase/use-session.ts
Example of usage in src/components/user-information.tsx
When dealing with a client component that dynamically renders elements based on user data, a common issue arises during the initial load or refresh. In such scenarios, where the session data may not be immediately available in the browser, the component tends to display a false value before rendering the true value, leading to an undesirable flickering effect and poor user experience.
To address this issue, we can implement the following solution:
Displaying a loading state until the user data is fetched. Example in src/components/user-information.tsx
If the client component has a server component as its parent, the session can be fetched at the parent level and passed down to the client component.
Creating a server component wrapper specifically for the client component. The server wrapper is responsible for fetching the session data and passing it down to the client. This setup allows reusability of the component. Example of this method;
src/components/details-button-server.tsx
src/components/details-button-client.tsx
For more information, check out this video
Routes can be protected by checking whether there is a supabase session. If there is no session, the user is redirected to the specified page.
// other imports...
import { redirect } from "next/navigation";
export default async function Page() {
const {
data: { user },
error,
} = await createSupabaseServerComponentClient().auth.getUser();
if (!user) {
redirect("/");
}
// ...
}
Login to the supabase CLI with your supabase access token
pnpm dlx supabasee login
Generate the types using your supabase project id:
pnpm dlx supabase gen types typescript --project-id your_supabase_project_id > src/lib/supabase/database.types.ts
If you're developing locally or on a self-hosted supabase instance, you can use the database URL instead of the project id:
pnpm dlx supabase gen types typescript --db-url your_supabase_database_url > src/lib/supabase/database.types.ts
You can then add the types to you project by including them in the browser-client.ts
and server-client.ts
files.
import { Database } from "@/lib/supabase/database.types";
// ...
export function createSupabaseBrowserClient() {
return createBrowserClient<Database>();
// ...
}
The project is primarily based on this course, which includes topics such as querying the database, setting up row-level security, optimistic updates, and many more. Although it utilizes the auth-helpers package, it can be easily modified using the contents of this project.
I would also like to give credit to the providers of the resources used in this project.