diff --git a/apps/docs/layouts/DefaultLayout.tsx b/apps/docs/layouts/DefaultLayout.tsx new file mode 100644 index 00000000000..7dff0d22711 --- /dev/null +++ b/apps/docs/layouts/DefaultLayout.tsx @@ -0,0 +1,89 @@ +import { MDXProvider } from '@mdx-js/react' + +import { useEffect, FC } from 'react' +import Head from 'next/head' +import NavBar from '../components/Navigation/NavBar' +import SideBar from '../components/Navigation/SideBar' +import Footer from '../components/Footer' +import TableOfContents from '~/components/TableOfContents' +import { useRouter } from 'next/router' +import { getPageType } from '../lib/helpers' +import components from '~/components' +import { menuItems } from '../components/Navigation/Navigation.constants' + +interface Props { + meta: { title: string; description?: string; hide_table_of_contents?: boolean } + children: any + toc?: any + currentPage: string +} + +const Layout: FC = ({ meta, children, toc, currentPage }) => { + const { asPath } = useRouter() + const page = getPageType(asPath) + + useEffect(() => { + const key = localStorage.getItem('supabaseDarkMode') + if (!key) { + // Default to dark mode if no preference config + document.documentElement.className = 'dark' + } else { + document.documentElement.className = key === 'true' ? 'dark' : '' + } + }, []) + + const hasTableOfContents = + toc !== undefined && toc.json.filter((item) => item.lvl !== 1 && item.lvl <= 3).length > 0 + console.log({ children }) + return ( + <> + + {meta?.title} | Supabase + + + + + + + + + +
+ +
+ +
+
+
+ {children} +
+
+ {hasTableOfContents && !meta?.hide_table_of_contents && ( + + )} +
+
+
+
+ + ) +} + +export default Layout diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index 14cfd9cecc2..b588ce78597 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -1,44 +1,19 @@ import nextMdx from '@next/mdx' -import bundleAnalyzer from '@next/bundle-analyzer' - import remarkGfm from 'remark-gfm' -import admonitions from 'remark-admonitions' import rehypeSlug from 'rehype-slug' import withTM from 'next-transpile-modules' -// import { remarkCodeHike } from '@code-hike/mdx' -// import theme from 'shiki/themes/dark-plus.json' assert { type: 'json' } -// import codeHikeTheme from './codeHikeTheme.js' - -/** - * Rewrites and redirects are handled by - * apps/www nextjs config - * - * Do not add them in this config - */ - const withMDX = nextMdx({ extension: /\.mdx?$/, options: { - remarkPlugins: [ - // [ - // remarkCodeHike, - // { theme: codeHikeTheme, autoImport: false }, - // ], - remarkGfm, - [admonitions, {}], - ], + remarkPlugins: [remarkGfm], rehypePlugins: [rehypeSlug], // This is required for `MDXProvider` component providerImportSource: '@mdx-js/react', }, }) -const withBundleAnalyzer = bundleAnalyzer({ - enabled: process.env.ANALYZE === 'true', -}) - // /** @type {NextConfig} */ const nextConfig = { // Append the default value with md extensions diff --git a/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx b/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx new file mode 100644 index 00000000000..b5aa5dbc86d --- /dev/null +++ b/apps/docs/pages/guides/auth/auth-helpers/auth-ui.mdx @@ -0,0 +1,281 @@ +import Layout from '~/layouts/DefaultLayout' + +export const meta = { + id: 'auth-ui', + title: 'Auth UI', + description: 'A prebuilt, customizable React component for authenticating users.', +} + +Auth UI is a pre-built React component for authenticating users. +It supports custom themes and extensible styles to match your brand and aesthetic. + + + +## Set up Auth UI + +Install the latest version of [supabase-js](/docs/reference/javascript) and the Auth UI package: + +```bash +npm install @supabase/supabase-js @supabase/auth-ui-react +``` + +### Import the Auth component + +Pass `supabaseClient` from `@supabase/supabase-js` as a prop to the component. + +```js title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => +``` + +This renders the Auth component without any styling. +We recommend using one of the predefined themes to style the UI. +Import the theme you want to use and pass it to the `appearence.theme` prop. + +```js lines=4,11 title=/src/index.js +import { + Auth, + // Import predefined theme + ThemeSupa, +} from '@supabase/auth-ui-react' + +const App = () => ( + +) +``` + +## Customization + +There are several ways to customize Auth UI: + +- Use one of the [predefined themes](#predefined-themes) that comes with Auth UI +- Extend a theme by [overriding the variable tokens](#override-themes) in a theme +- [Create your own theme](#create-theme) +- [Use your own CSS classes](#custom-css-classes) +- [Use inline styles](#custom-inline-styles) +- [Use your own labels](#custom-labels) + +### Predefined themes + +Auth UI comes with several themes to customize the appearance. Each predefined theme comes with at least two variations, a `default` variation, and a `dark` variation. You can switch between these themes using the `theme` prop. Import the theme you want to use and pass it to the `appearence.theme` prop. + +```js lines=2,10 title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => ( + +) +``` + + + +Currently there is only one predefined theme available, but we plan to add more. + + + +### Switch theme variations + +Auth UI comes with two theme variations: `default` and `dark`. You can switch between these themes with the `theme` prop. + +```js lines=11 title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => ( + +) +``` + +If you don't pass a value to `theme` it uses the `"default"` theme. You can pass `"dark"` to the theme prop to switch to the `dark` theme. If your theme has other variations, use the name of the variation in this prop. + +### Override themes + +Auth UI themes can be overridden using variable tokens. See the [list of variable tokens](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx). + +```js lines=11-18 title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => ( + +) +``` + +If you created your own theme, you may not need to override any of the them. + +### Create your own theme {#create-theme} + +You can create your own theme by following the same structure within a `appearance.theme` property. +See the list of [tokens within a theme](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/theming/Themes.tsx). + +```js title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient( + '', + '' +) + +const customTheme = { + default: { + colors: { + brand: 'hsl(153 60.0% 53.0%)', + brandAccent: 'hsl(154 54.8% 45.1%)', + brandButtonText: 'white', + // .. + }, + dark: { + colors: { + brandButtonText: 'white', + defaultButtonBackground: '#2e2e2e', + defaultButtonBackgroundHover: '#3e3e3e', + //.. + }, + }, + // You can also add more theme variations with different names. + evenDarker: { + colors: { + brandButtonText: 'white', + defaultButtonBackground: '#1e1e1e', + defaultButtonBackgroundHover: '#2e2e2e', + //.. + }, + }, +} + +const App = () => ( + +) +``` + +You can swich between different variations of your theme with the ["theme" prop](#switch-theme-variations). + +### Custom CSS classes {#custom-css-classes} + +You can use custom CSS classes for the following elements: +`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`. + +```js title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => ( + +) +``` + +### Custom inline CSS {#custom-inline-styles} + +You can use custom CSS inline styles for the following elements: +`"button"`, `"container"`, `"anchor"`, `"divider"`, `"label"`, `"input"`, `"loader"`, `"message"`. + +```js title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => ( + +) +``` + +### Custom labels {#custom-labels} + +You can use custom labels with `localization.variables`. See the [list of labels](https://github.com/supabase-community/auth-ui/blob/main/packages/react/common/lib/Localization/en.json) that can be overwritten. + +```js title=/src/index.js +import { createClient } from '@supabase/supabase-js' +import { Auth } from '@supabase/auth-ui-react' + +const supabase = createClient('', '') + +const App = () => ( + +) +``` + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx new file mode 100644 index 00000000000..9b1775de729 --- /dev/null +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -0,0 +1,843 @@ +import Layout from '~/layouts/DefaultLayout' + +export const meta = { + id: 'nextjs', + title: 'Supabase Auth with Next.js', + description: 'Authentication helpers for Next.js API routes, middleware, and SSR.', + sidebar_label: 'Next.js', +} + +This submodule provides convenience helpers for implementing user authentication in Next.js applications. + +## Install the Next.js helper library + + + + +```sh +npm install @supabase/auth-helpers-nextjs +``` + +This library supports the following tooling versions: + +- Node.js: `^10.13.0 || >=12.0.0` +- Next.js: `>=10` +- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341). + +Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks. + +```sh +npm install @supabase/auth-helpers-react +``` + + + + +```sh +yarn add @supabase/auth-helpers-nextjs +``` + +This library supports the following tooling versions: + +- Node.js: `^10.13.0 || >=12.0.0` +- Next.js: `>=10` +- Note: Next.js 13 is supported except for the new `app` directory approach. We're working on adding support for this and you can follow along [here](https://github.com/supabase/auth-helpers/issues/341). + +Additionally, install the **React Auth Helpers** for components and hooks that can be used across all React-based frameworks. + +```sh +yarn add @supabase/auth-helpers-react +``` + + + + +## Set up environment variables + +Retrieve your project URL and anon key in your project's [API settings](https://app.supabase.com/project/_/settings/api) in the Dashboard to set up the following environment variables. For local development you can set them in a `.env.local` file. See an [example](https://github.com/supabase/auth-helpers/blob/main/examples/nextjs/.env.local.example). + +```bash title=.env.local +NEXT_PUBLIC_SUPABASE_URL=YOUR_SUPABASE_URL +NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_SUPABASE_ANON_KEY +``` + +## Basic Setup + + + + +Wrap your `pages/_app.js` component with the `SessionContextProvider` component: + +```jsx title=pages/_app.js +import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { SessionContextProvider } from '@supabase/auth-helpers-react' + +function MyApp({ Component, pageProps }) { + const router = useRouter() + // Create a new supabase browser client on every first render. + const [supabaseClient] = useState(() => createBrowserSupabaseClient()) + + return ( + + + + ) +} +``` + + + + +Wrap your `pages/_app.tsx` component with the `SessionContextProvider` component: + +```tsx lines=2,8 title=pages/_app.tsx +import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { SessionContextProvider, Session } from '@supabase/auth-helpers-react' + +function MyApp({ + Component, + pageProps, +}: AppProps<{ + initialSession: Session +}>) { + // Create a new supabase browser client on every first render. + const [supabaseClient] = useState(() => createBrowserSupabaseClient()) + + return ( + + + + ) +} +``` + + + + +You can now determine if a user is authenticated by checking that the `user` object returned by the `useUser()` hook is defined. + +## Usage with TypeScript + +You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion: + +### Browser client + +Creating a new supabase client object: + +```tsx +import { createBrowserSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { Database } from '../database.types' + +const supabaseClient = createBrowserSupabaseClient() +``` + +Retrieving a supabase client object from the SessionContext: + +```tsx +import { useSupabaseClient } from '@supabase/auth-helpers-react' +import { Database } from '../database.types' + +const supabaseClient = useSupabaseClient() +``` + +### Server client + +```tsx +// Creating a new supabase server client object (e.g. in API route): +import type { NextApiRequest, NextApiResponse } from 'next' +import type { Database } from 'types_db' + +export default async (req: NextApiRequest, res: NextApiResponse) => { + const supabaseServerClient = createServerSupabaseClient({ + req, + res, + }) + const { + data: { user }, + } = await supabaseServerClient.auth.getUser() + + res.status(200).json({ name: user?.name ?? '' }) +} +``` + +## Client-side data fetching with RLS + +For [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) to work properly when fetching data client-side, you need to make sure to use the `supabaseClient` from the `useSupabaseClient` hook and only run your query once the user is defined client-side in the `useUser()` hook: + +```jsx lines=10-17 +import { Auth, ThemeSupa } from '@supabase/auth-ui-react' +import { useUser, useSupabaseClient } from '@supabase/auth-helpers-react' +import { useEffect, useState } from 'react' + +const LoginPage = () => { + const supabaseClient = useSupabaseClient() + const user = useUser() + const [data, setData] = useState() + + useEffect(() => { + async function loadData() { + const { data } = await supabaseClient.from('test').select('*') + setData(data) + } + // Only run query once user is logged in. + if (user) loadData() + }, [user]) + + if (!user) + return ( + + ) + + return ( + <> + +

user:

+
{JSON.stringify(user, null, 2)}
+

client-side data fetching with RLS

+
{JSON.stringify(data, null, 2)}
+ + ) +} + +export default LoginPage +``` + +## Server-side rendering (SSR) + +Create a server supabase client to retrieve the logged in user's session: + +```jsx title=pages/profile.js +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function Profile({ user }) { + return
Hello {user.name}
+} + +export const getServerSideProps = async (ctx) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + return { + props: { + initialSession: session, + user: session.user, + }, + } +} +``` + +## Server-side data fetching with RLS + +You can use the server supabase client to run [row level security](/docs/learn/auth-deep-dive/auth-row-level-security) authenticated queries server-side: + + + + +```jsx +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ user, data }) { + return ( + <> +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Run queries with RLS on the server + const { data } = await supabase.from('users').select('*') + + return { + props: { + initialSession: session, + user: session.user, + data: data ?? [], + }, + } +} +``` + +
+ + +```tsx +import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { GetServerSidePropsContext } from 'next' + +export default function ProtectedPage({ user, data }: { user: User; data: any }) { + return ( + <> +
Protected content for {user.email}
+
{JSON.stringify(data, null, 2)}
+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Run queries with RLS on the server + const { data } = await supabase.from('users').select('*') + + return { + props: { + initialSession: session, + user: session.user, + data: data ?? [], + }, + } +} +``` + +
+
+ +## Server-side data fetching to OAuth APIs using `provider token` {#oauth-provider-token} + +When using third-party auth providers, sessions are initiated with an additional `provider_token` field which is persisted in the auth cookie and can be accessed within the session object. The `provider_token` can be used to make API requests to the OAuth provider's API endpoints on behalf of the logged-in user. + + + + +```jsx +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +export default function ProtectedPage({ user, allRepos }) { + return ( + <> +
Protected content for {user.email}
+

Data fetched with provider token:

+
{JSON.stringify(allRepos, null, 2)}
+

user:

+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Retrieve provider_token & logged in user's third-party id from metadata + const { provider_token, user } = session + const userId = user.user_metadata.user_name + + const allRepos = await ( + await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, { + method: 'GET', + headers: { + Authorization: `token ${provider_token}`, + }, + }) + ).json() + + return { props: { user, allRepos } } +} +``` + +
+ + +```tsx +import { User, createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { GetServerSidePropsContext } from 'next' + +export default function ProtectedPage({ user, allRepos }: { user: User; allRepos: any }) { + return ( + <> +
Protected content for {user.email}
+

Data fetched with provider token:

+
{JSON.stringify(allRepos, null, 2)}
+

user:

+
{JSON.stringify(user, null, 2)}
+ + ) +} + +export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + // Retrieve provider_token & logged in user's third-party id from metadata + const { provider_token, user } = session + const userId = user.user_metadata.user_name + + const allRepos = await ( + await fetch(`https://api.github.com/search/repositories?q=user:${userId}`, { + method: 'GET', + headers: { + Authorization: `token ${provider_token}`, + }, + }) + ).json() + + return { props: { user, allRepos } } +} +``` + +
+
+ +## Protecting API routes + +Create a server supabase client to retrieve the logged in user's session: + + + + +```jsx title=pages/api/protected-route.js +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +const ProtectedRoute = async (req, res) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return res.status(401).json({ + error: 'not_authenticated', + description: 'The user does not have an active session or is not authenticated', + }) + + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +} + +export default ProtectedRoute +``` + + + + +```tsx title=pages/api/protected-route.ts +import { NextApiHandler } from 'next' +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +const ProtectedRoute: NextApiHandler = async (req, res) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return res.status(401).json({ + error: 'not_authenticated', + description: 'The user does not have an active session or is not authenticated', + }) + + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +} + +export default ProtectedRoute +``` + + + + +## Auth with Next.js Middleware + +As an alternative to protecting individual pages you can use a [Next.js Middleware](https://nextjs.org/docs/middleware) to protect the entire directory or those that match the config object. In the following example, all requests to `/middleware-protected/*` will check whether a user is signed in, if successful the request will be forwarded to the destination route, otherwise the user will be redirected: + +```ts title=middleware.ts +import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export async function middleware(req: NextRequest) { + // We need to create a response and hand it to the supabase client to be able to modify the response headers. + const res = NextResponse.next() + // Create authenticated Supabase Client. + const supabase = createMiddlewareSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + // Check auth condition + if (session?.user.email?.endsWith('@gmail.com')) { + // Authentication successful, forward request to protected route. + return res + } + + // Auth condition not met, redirect to home page. + const redirectUrl = req.nextUrl.clone() + redirectUrl.pathname = '/' + redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname) + return NextResponse.redirect(redirectUrl) +} + +export const config = { + matcher: '/middleware-protected', +} +``` + +## Migration Guide + +### Migrating to v0.5.X + +To make these helpers more flexible as well as more maintainable and easier to upgrade for new versions of Next.js, we're stripping them down to the most useful part which is managing the cookies and giving you an authenticated supabase-js client in any environment (client, server, middleware/edge). + +Therefore we're marking the `withApiAuth`, `withPageAuth`, and `withMiddlewareAuth` higher order functions as deprectaed and they will be removed in the next **minor** release (v0.6.X). + +Please follow the steps below to update your API routes, pages, and middleware handlers. Thanks! + +#### `withApiAuth` deprecated! + +Use `createServerSupabaseClient` within your `NextApiHandler`: + + + + +```tsx title=pages/api/protected-route.ts +import { withApiAuth } from '@supabase/auth-helpers-nextjs' + +export default withApiAuth(async function ProtectedRoute(req, res, supabase) { + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +}) +``` + + + + +```tsx title=pages/api/protected-route.ts +import { NextApiHandler } from 'next' +import { createServerSupabaseClient } from '@supabase/auth-helpers-nextjs' + +const ProtectedRoute: NextApiHandler = async (req, res) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return res.status(401).json({ + error: 'not_authenticated', + description: 'The user does not have an active session or is not authenticated', + }) + + // Run queries with RLS on the server + const { data } = await supabase.from('test').select('*') + res.json(data) +} + +export default ProtectedRoute +``` + + + + +#### `withPageAuth` deprecated! + +Use `createServerSupabaseClient` within `getServerSideProps`: + + + + +```tsx title=pages/profile.tsx +import { withPageAuth, User } from '@supabase/auth-helpers-nextjs' + +export default function Profile({ user }: { user: User }) { + return
{JSON.stringify(user, null, 2)}
+} + +export const getServerSideProps = withPageAuth({ redirectTo: '/' }) +``` + +
+ + +```tsx title=pages/profile.js +import { createServerSupabaseClient, User } from '@supabase/auth-helpers-nextjs' +import { GetServerSidePropsContext } from 'next' + +export default function Profile({ user }: { user: User }) { + return
{JSON.stringify(user, null, 2)}
+} + +export const getServerSideProps = async (ctx: GetServerSidePropsContext) => { + // Create authenticated Supabase Client + const supabase = createServerSupabaseClient(ctx) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + if (!session) + return { + redirect: { + destination: '/', + permanent: false, + }, + } + + return { + props: { + initialSession: session, + user: session.user, + }, + } +} +``` + +
+
+ +#### `withMiddlewareAuth` deprecated! + + + + +```tsx title=middleware.ts +import { withMiddlewareAuth } from '@supabase/auth-helpers-nextjs' + +export const middleware = withMiddlewareAuth({ + redirectTo: '/', + authGuard: { + isPermitted: async (user) => { + return user.email?.endsWith('@gmail.com') ?? false + }, + redirectTo: '/insufficient-permissions', + }, +}) + +export const config = { + matcher: '/middleware-protected', +} +``` + + + + +```tsx title=middleware.ts +import { createMiddlewareSupabaseClient } from '@supabase/auth-helpers-nextjs' +import { NextResponse } from 'next/server' +import type { NextRequest } from 'next/server' + +export async function middleware(req: NextRequest) { + // We need to create a response and hand it to the supabase client to be able to modify the response headers. + const res = NextResponse.next() + // Create authenticated Supabase Client. + const supabase = createMiddlewareSupabaseClient({ req, res }) + // Check if we have a session + const { + data: { session }, + } = await supabase.auth.getSession() + + // Check auth condition + if (session?.user.email?.endsWith('@gmail.com')) { + // Authentication successful, forward request to protected route. + return res + } + + // Auth condition not met, redirect to home page. + const redirectUrl = req.nextUrl.clone() + redirectUrl.pathname = '/' + redirectUrl.searchParams.set(`redirectedFrom`, req.nextUrl.pathname) + return NextResponse.redirect(redirectUrl) +} + +export const config = { + matcher: '/middleware-protected', +} +``` + + + + +### Migrating to v0.4.X and supabase-js v2 + +With the update to `supabase-js` v2 the `auth` API routes are no longer required, therefore you can go ahead and delete your `auth` directory under the `/pages/api/` directory. Please refer to the [v2 migration guide](/docs/reference/javascript/upgrade-guide) for the full set of changes within supabase-js. + +The `/api/auth/logout` API route has been removed, please use the `signout` method instead: + +```jsx + +``` + +The `supabaseClient` and `supabaseServerClient` have been removed in favor of the `createBrowserSupabaseClient` and `createServerSupabaseClient` methods. This allows you to provide the CLI-generated types to the client: + +```tsx +// client-side +import type { Database } from 'types_db' +const [supabaseClient] = useState(() => createBrowserSupabaseClient()) + +// server-side API route +import type { NextApiRequest, NextApiResponse } from 'next' +import type { Database } from 'types_db' + +export default async (req: NextApiRequest, res: NextApiResponse) => { + const supabaseServerClient = createServerSupabaseClient({ + req, + res, + }) + const { + data: { user }, + } = await supabaseServerClient.auth.getUser() + + res.status(200).json({ name: user?.name ?? '' }) +} +``` + +- The `UserProvider` has been replaced by the `SessionContextProvider`. Make sure to wrap your `pages/_app.js` componenent with the `SessionContextProvider`. Then, throughout your application you can use the `useSessionContext` hook to get the `session` and the `useSupabaseClient` hook to get an authenticated `supabaseClient`. +- The `useUser` hook now returns the `user` object or `null`. +- Usage with TypeScript: You can pass types that were [generated with the Supabase CLI](/docs/reference/javascript/typescript-support#generating-types) to the Supabase Client to get enhanced type safety and auto completion: + +Creating a new supabase client object: + +```tsx +import { Database } from '../database.types' + +const [supabaseClient] = useState(() => createBrowserSupabaseClient()) +``` + +Retrieving a supabase client object from the SessionContext: + +```tsx +import { useSupabaseClient } from '@supabase/auth-helpers-react' +import { Database } from '../database.types' + +const supabaseClient = useSupabaseClient() +``` + +export const Page = ({ children }) => + +export default Page