diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index c0806b47b33..65344b8992b 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -548,22 +548,21 @@ export const auth = { name: 'Server-side Auth', url: undefined, items: [ - { name: 'Overview', url: '/guides/auth/auth-helpers' }, + { name: 'Overview', url: '/guides/auth/server-side/overview' }, + { name: 'Creating a client', url: '/guides/auth/server-side/creating-a-client' }, { - name: 'Next.js', - url: '/guides/auth/auth-helpers/nextjs', - }, - { name: 'Remix', url: '/guides/auth/auth-helpers/remix' }, - { name: 'SvelteKit', url: '/guides/auth/auth-helpers/sveltekit' }, - { name: 'Server-side Rendering', url: '/guides/auth/server-side-rendering' }, - { - name: 'Email Auth with PKCE flow for SSR', + name: 'Email Auth with PKCE flow', url: '/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr', }, { - name: 'OAuth with PKCE flow for SSR', + name: 'OAuth with PKCE flow', url: '/guides/auth/server-side/oauth-with-pkce-flow-for-ssr', }, + { name: 'Server-side Rendering', url: '/guides/auth/server-side-rendering' }, + { + name: 'Migrating from Auth Helpers', + url: '/guides/auth/server-side/migrating-to-ssr-from-auth-helpers', + }, ], }, { diff --git a/apps/docs/pages/guides/auth/auth-helpers.mdx b/apps/docs/pages/guides/auth/auth-helpers.mdx index 041df7fa54b..064049fa14c 100644 --- a/apps/docs/pages/guides/auth/auth-helpers.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers.mdx @@ -2,11 +2,17 @@ import Layout from '~/layouts/DefaultGuideLayout' export const meta = { id: 'index', - title: 'Server-Side Auth Overview', + title: 'Auth Helpers', description: 'Server-Side Auth guides and utilities for working with Supabase.', sidebar_label: 'Overview', } + + +The `auth-helpers` packages have been deprecated in favor of the new `ssr` package. This takes the core concepts of the Auth Helpers package and makes them available to any server language or framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + + + Working with server-side frameworks is slightly different to client-side frameworks. In this section we cover the various ways of handling server-side authentication and demonstrate how to use the Supabase helper-libraries to make the process more seamless.
diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs-pages.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs-pages.mdx index 81f883336d9..c6a2f19b2c2 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs-pages.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs-pages.mdx @@ -8,6 +8,12 @@ export const meta = { sidebar_label: 'Next.js (pages)', } + + +The `auth-helpers` packages have been deprecated in favor of the new `ssr` package. This takes the core concepts of the Auth Helpers package and makes them available to any server language or framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + + + This submodule provides convenience helpers for implementing user authentication in Next.js applications using the pages directory. > Note: As of [Next.js 13.4](https://nextjs.org/blog/next-13-4), the App Router has reached stable status. This is now the recommended path for new Next.js app. Check out our guide on using [Auth Helpers with the Next.js App Directory](/docs/guides/auth/auth-helpers/nextjs). diff --git a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx index bcc3fec0ea1..eee1b28a5d5 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/nextjs.mdx @@ -8,6 +8,12 @@ export const meta = { sidebar_label: 'Next.js', } + + +The `auth-helpers` packages have been deprecated in favor of the new `ssr` package. This takes the core concepts of the Auth Helpers package and makes them available to any server language or framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + + + The [Next.js Auth Helpers package](https://github.com/supabase/auth-helpers) configures Supabase Auth to store the user's `session` in a `cookie`, rather than `localStorage`. This makes it available across the client and server of the App Router - [Client Components](/docs/guides/auth/auth-helpers/nextjs#client-components), [Server Components](/docs/guides/auth/auth-helpers/nextjs#server-components), [Server Actions](/docs/guides/auth/auth-helpers/nextjs#server-actions), [Route Handlers](/docs/guides/auth/auth-helpers/nextjs#route-handlers) and [Middleware](/docs/guides/auth/auth-helpers/nextjs#middleware). The `session` is automatically sent along with any requests to Supabase.
@@ -25,48 +31,13 @@ If you are using the `pages` directory, check out [Auth Helpers in Next.js Pages -## Automatic Configuration (recommended) - -Use the `create-next-app` command and the `with-supabase` template to automate the configuration of cookie-based auth with the Next.js Auth Helpers. - -```sh Terminal -npx create-next-app -e with-supabase -``` - -This creates a new Next.js app configured with: - -- [Cookie-based Auth](/docs/guides/auth/auth-helpers/nextjs#authentication) -- [Middleware to refresh user's session](/docs/guides/auth/auth-helpers/nextjs#managing-session-with-middleware) -- [Code Exchange Route](/docs/guides/auth/auth-helpers/nextjs#Managing-sign-in-with-code-exchange) -- [TypeScript](https://www.typescriptlang.org/) -- [Tailwind CSS](https://tailwindcss.com/) - -### Declare Environment Variables - -Retrieve your project's URL and anon key from your [API settings](https://supabase.com/dashboard/project/_/settings/api), and create a `.env.local` file with the following environment variables: - -```bash .env.local -NEXT_PUBLIC_SUPABASE_URL=your-supabase-url -NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key -``` - -### Run Next.js App - -Run the development server and navigate to http://localhost:3000. - -```sh Terminal -npm run dev -``` - -## Manual Configuration - -### Install Next.js Auth Helpers library +## Install Next.js Auth Helpers library ```sh Terminal npm install @supabase/auth-helpers-nextjs @supabase/supabase-js ``` -### Declare Environment Variables +## Declare Environment Variables Retrieve your project's URL and anon key from your [API settings](https://supabase.com/dashboard/project/_/settings/api), and create a `.env.local` file with the following environment variables: @@ -75,7 +46,7 @@ NEXT_PUBLIC_SUPABASE_URL=your-supabase-url NEXT_PUBLIC_SUPABASE_ANON_KEY=your-supabase-anon-key ``` -### Managing session with Middleware +## Managing session with Middleware When using the Supabase client on the server, you must perform extra steps to ensure the user's auth session remains active. Since the user's session is tracked in a cookie, we need to read this cookie and update it if necessary. @@ -142,7 +113,7 @@ The `getSession` function must be called for any Server Component routes that us -### Managing sign-in with Code Exchange +## Managing sign-in with Code Exchange The Next.js Auth Helpers are configured to use the [server-side auth flow](/docs/guides/auth/server-side-rendering) to sign users into your application. This requires you to setup a `Code Exchange` route, to exchange an auth `code` for the user's `session`, which is set as a cookie for future requests made to Supabase. diff --git a/apps/docs/pages/guides/auth/auth-helpers/remix.mdx b/apps/docs/pages/guides/auth/auth-helpers/remix.mdx index e002fae5c83..0f9a7b1c46d 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/remix.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/remix.mdx @@ -7,6 +7,12 @@ export const meta = { sidebar_label: 'Remix', } + + +The `auth-helpers` packages have been deprecated in favor of the new `ssr` package. This takes the core concepts of the Auth Helpers package and makes them available to any server language or framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + + + This submodule provides convenience helpers for implementing user authentication in Remix applications.
diff --git a/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx b/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx index f097a1b9f47..0902643362c 100644 --- a/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx +++ b/apps/docs/pages/guides/auth/auth-helpers/sveltekit.mdx @@ -7,6 +7,12 @@ export const meta = { sidebar_label: 'SvelteKit', } + + +The `auth-helpers` packages have been deprecated in favor of the new `ssr` package. This takes the core concepts of the Auth Helpers package and makes them available to any server language or framework. Check out the [migration doc](/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers) to learn more. + + + This submodule provides convenience helpers for implementing user authentication in [SvelteKit](https://kit.svelte.dev/) applications. ## Configuration diff --git a/apps/docs/pages/guides/auth/quickstarts/nextjs.mdx b/apps/docs/pages/guides/auth/quickstarts/nextjs.mdx index f57d831b083..05ff464107c 100644 --- a/apps/docs/pages/guides/auth/quickstarts/nextjs.mdx +++ b/apps/docs/pages/guides/auth/quickstarts/nextjs.mdx @@ -12,9 +12,9 @@ export const meta = { - [Launch a new project](https://supabase.com/dashboard) in the Supabase Dashboard. + Head over to [database.new](https://database.new) and create a new Supabase project. - Your new database has a table for storing your users. You can see that this table is currently empty by running some SQL in the [SQL Editor](https://supabase.com/dashboard/project/_/sql). + Your new database has a table for storing your users. You can see that this table is currently empty by running some SQL in the [SQL Editor](https://supabase.com/dashboard/project/_/sql/new). @@ -33,7 +33,7 @@ export const meta = { Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with: - - [Supabase Auth](https://supabase.com/docs/guides/auth/auth-helpers/nextjs) + - [Cookie-based Auth](https://supabase.com/docs/guides/auth/auth-helpers/nextjs) - [TypeScript](https://www.typescriptlang.org/) - [Tailwind CSS](https://tailwindcss.com/) @@ -42,7 +42,7 @@ export const meta = { ```bash Terminal - npx create-next-app -e with-supabase my-app && cd my-app + npx create-next-app -e with-supabase ``` diff --git a/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx b/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx new file mode 100644 index 00000000000..1b9a71bb79f --- /dev/null +++ b/apps/docs/pages/guides/auth/server-side/creating-a-client.mdx @@ -0,0 +1,817 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + title: 'Creating a Supabase client for SSR', + description: 'Configure Supabase client to use Cookies', + sidebar_label: 'Creating a client', +} + +### Install Supabase packages + +The `ssr` package configures Supabase to use Cookies, which is required for server-side languages and frameworks. + +```bash +npm install @supabase/ssr @supabase/supabase-js +``` + +### Set environment variables + + + + + +Create a `.env.local` file in your project root directory. You can get your `SUPABASE_URL` and `SUPABASE_ANON_KEY` from inside [your Supabase project's dashboard](https://supabase.com/dashboard/project/_/settings/api). + +```bash .env.local +NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url +NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key +``` + + + + +Create a `.env.local` file in your project root directory. You can get your `SUPABASE_URL` and `SUPABASE_ANON_KEY` from inside [your Supabase project's dashboard](https://supabase.com/dashboard/project/_/settings/api). + +```bash .env.local +PUBLIC_SUPABASE_URL=your_supabase_project_url +PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key +``` + + + + +Create a `.env` file in your project root directory. You can get your `SUPABASE_URL` and `SUPABASE_ANON_KEY` from inside [your Supabase project's dashboard](https://supabase.com/dashboard/project/_/settings/api). + +```bash .env +PUBLIC_SUPABASE_URL=your_supabase_project_url +PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key +``` + + + + +Create a `.env` file in your project root directory. You can get your `SUPABASE_URL` and `SUPABASE_ANON_KEY` from inside [your Supabase project's dashboard](https://supabase.com/dashboard/project/_/settings/api). + +```bash .env +SUPABASE_URL=your_supabase_project_url +SUPABASE_ANON_KEY=your_supabase_anon_key +``` + + + + +Create a `.env` file in your project root directory. You can get your `SUPABASE_URL` and `SUPABASE_ANON_KEY` from inside [your Supabase project's dashboard](https://supabase.com/dashboard/project/_/settings/api). + +```bash .env +SUPABASE_URL=your_supabase_project_url +SUPABASE_ANON_KEY=your_supabase_anon_key +``` + +Install [dotenv](https://www.npmjs.com/package/dotenv) + +```bash +npm i dotenv +``` + +and initialize it + +```js app.js +const express = require("express") +const dotenv = require("dotenv") +dotenv.config() +... +``` + + + + +### Creating a client + + + + +Creating a Supabase client with the `ssr` package automatically configures it to use cookies. This means your user's session is available throughout the entire Next.js stack - client, server, App Router, Pages Router. It just works! + + + + +```ts page.tsx +"use client"; + +import { createBrowserClient } from '@supabase/ssr' + +export default function Page () { + const supabase = createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ) + + return ... +} +``` + + + + + + + +Server Components only have read access to cookies. Check the `Middleware` tab for an example of refreshing expired sessions before loading a Server Component route. + + + +```ts page.tsx +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { cookies } from 'next/headers' + +export default async function Page () { + const cookieStore = cookies() + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value + }, + }, + } + ) + + return ... +} +``` + + + + + + + +Server Components only have read access to cookies. This `Middleware` example can be used to refresh expired sessions before loading Server Component routes. + + + +```ts middleware.ts +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { NextResponse, type NextRequest } from 'next/server' + +export async function middleware(request: NextRequest) { + let response = NextResponse.next({ + request: { + headers: request.headers, + }, + }) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return request.cookies.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + request.cookies.set({ + name, + value, + ...options, + }) + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }) + response.cookies.set({ + name, + value, + ...options, + }) + }, + remove(name: string, options: CookieOptions) { + request.cookies.set({ + name, + value: '', + ...options, + }) + response = NextResponse.next({ + request: { + headers: request.headers, + }, + }) + response.cookies.set({ + name, + value: '', + ...options, + }) + }, + }, + } + ) + + await supabase.auth.getSession() + + return response +} +``` + + + + + +```ts route.js +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { cookies } from 'next/headers' + +export async function POST(request: Request) { + const cookieStore = cookies() + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + cookieStore.set({ name, value, ...options }) + }, + remove(name: string, options: CookieOptions) { + cookieStore.set({ name, value: '', ...options }) + }, + }, + } + ) + + return ... +} +``` + + + + + +```ts page.tsx +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { cookies } from 'next/headers' + +export default async function Page () { + const serverAction = async () => { + 'use server' + + const cookieStore = cookies() + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + cookieStore.set({ name, value, ...options }) + }, + remove(name: string, options: CookieOptions) { + cookieStore.set({ name, value: '', ...options }) + }, + }, + } + ) + } + + return ... +} +``` + + + + + +Cookies have many edge cases when not using a helper function, therefore we recommend using the `cookies` package in `getServerSideProps` to provide a similar API to the Next.js `cookies` function in the App Router. + +```bash +npm install cookies +``` + +Types can optionally be installed as well. + +```bash +npm install --save-dev @types/cookies +``` + +```ts index.tsx +import { type GetServerSidePropsContext } from 'next' +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import Cookies from 'cookies' + +export const getServerSideProps = async (context: GetServerSidePropsContext) => { + const cookies = new Cookies(context.req, context.res) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookies.get(name) + }, + set(name: string, value: string, options: CookieOptions) { + cookies.set(name, value, options) + }, + remove(name: string, options: CookieOptions) { + cookies.set(name, '', options) + }, + }, + } + ) + + return {...} +} +``` + + + + + +The `getStaticProps` function gets executed at build time, rather than per request. At build time, +there is no user, session or cookies. Therefore, we can use the standard `createClient` function +from `supabase-js`. + +```ts page.tsx +import { createClient } from '@supabase/supabase-js' + +export const getStaticProps = async () => { + const cookies = new Cookies(context.req, context.res) + + const supabase = createClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + ) + + return {...} +} +``` + + + + + +Cookies have many edge cases when not using a helper function, therefore, we recommend using the `cookies` package in API Routes to provide a similar API to the Next.js `cookies` function in the App Router. + +```bash +npm install cookies +``` + +Types can optionally be installed as well. + +```bash +npm install --save-dev @types/cookies +``` + +```ts index.tsx +import { createServerClient, type CookieOptions } from "@supabase/ssr" +import { type NextApiRequest, type NextApiResponse } from "next" +import Cookies from "cookies" + +export default async function handler( + req: NextApiRequest, + res: NextApiResponse +) { + const cookies = new Cookies(req, res) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookies.get(name) + }, + set(name: string, value: string, options: CookieOptions) { + cookies.set(name, value, options) + }, + remove(name: string, options: CookieOptions) { + cookies.set(name, "", options) + }, + }, + } + ) + + res.send(...) +} +``` + + + + + +```ts index.tsx +import { createBrowserClient } from "@supabase/ssr" + +export default function Index () { + const supabase = createBrowserClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! + ) + + return ... +} +``` + + + + + + + +Creating a Supabase client with the `ssr` package automatically configures it to use Cookies. This means your user's session is available throughout the entire SvelteKit stack - page, layout, server, hooks. It just works! + + + + + + +API routes, server layout load and form actions can now access the supabase client from the `event` object due to this hook. + + + +```ts hooks.server.ts +import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public' +import { createServerClient } from '@supabase/ssr' +import type { Handle } from '@sveltejs/kit' + +export const handle: Handle = async ({ event, resolve }) => { + event.locals.supabase = createServerClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, { + cookies: { + get: (key) => event.cookies.get(key), + set: (key, value, options) => { + event.cookies.set(key, value, options) + }, + remove: (key, options) => { + event.cookies.delete(key, options) + }, + }, + }) + + /** + * a little helper that is written for convenience so that instead + * of calling `const { data: { session } } = await supabase.auth.getSession()` + * you just call this `await getSession()` + */ + event.locals.getSession = async () => { + const { + data: { session }, + } = await event.locals.supabase.auth.getSession() + return session + } + + return resolve(event, { + filterSerializedResponseHeaders(name) { + return name === 'content-range' + }, + }) +} +``` + + + + + + + +Page components can get access to the supabase client from the `data` object due to this load function. + + + +```ts +layout.ts +import { PUBLIC_SUPABASE_ANON_KEY, PUBLIC_SUPABASE_URL } from '$env/static/public' +import type { LayoutLoad } from './$types' +import { createBrowserClient, isBrowser, parse } from '@supabase/ssr' + +export const load: LayoutLoad = async ({ fetch, data, depends }) => { + depends('supabase:auth') + + const supabase = createBrowserClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY, { + global: { + fetch, + }, + cookies: { + get(key) { + if (!isBrowser()) { + return JSON.stringify(data.session) + } + + const cookie = parse(document.cookie) + return cookie[key] + }, + }, + }) + + const { + data: { session }, + } = await supabase.auth.getSession() + + return { supabase, session } +} +``` + + + + + +```svelte +page.svelte + + +.... +``` + + + + + +```ts +server.ts +import { redirect } from '@sveltejs/kit'; + +export const GET = async (event) => { + const { url, locals: { supabase } } = event + ... +} +``` + + + + + +```ts +page.server.ts +import type { Actions } from './$types' + +export const actions: Actions = { + default: async (event) => { + const { request, url, locals: { supabase } } = event + const formData = await request.formData() + const email = formData.get('email') as string + const password = formData.get('password') as string + ... + } +} +``` + + + + + + + + + + +```ts index.astro +--- +import { createServerClient, type CookieOptions } from "@suapbase/ssr"; + +const supabase = createServerClient( + import.meta.env.PUBLIC_SUPABASE_URL, + import.meta.env.PUBLIC_SUPABASE_ANON_KEY, + { + cookies: { + get(key: string) { + return Astro.cookies.get(key)?.value; + }, + set(key: string, value: string, options: CookieOptions) { + Astro.cookies.set(key, value, options); + }, + remove(key: string, options) { + Astro.cookies.delete(key, options); + }, + }, + } +); +--- +``` + + + + + +```html index.astro + +``` + + + + + + + + + + +```ts _index.tsx +import { type LoaderFunctionArgs } from '@remix-run/node' +import { createServerClient, parse, serialize } from '@supabase/ssr' + +export async function loader({ request }: LoaderFunctionArgs) { + const cookies = parse(request.headers.get('Cookie') ?? '') + const headers = new Headers() + + const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + get(key) { + return cookies[key] + }, + set(key, value, options) { + headers.append('Set-Cookie', serialize(key, value, options)) + }, + remove(key, options) { + headers.append('Set-Cookie', serialize(key, '', options)) + }, + }, + }) + + return new Response('...', { + headers, + }) +} +``` + + + + + +```ts _index.tsx +import { type ActionFunctionArgs } from '@remix-run/node' +import { createServerClient, parse, serialize } from '@supabase/ssr' + +export async function action({ request }: ActionFunctionArgs) { + const cookies = parse(request.headers.get('Cookie') ?? '') + const headers = new Headers() + + const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + get(key) { + return cookies[key] + }, + set(key, value, options) { + headers.append('Set-Cookie', serialize(key, value, options)) + }, + remove(key, options) { + headers.append('Set-Cookie', serialize(key, '', options)) + }, + }, + }) + + return new Response('...', { + headers, + }) +} +``` + + + + + +```ts _index.tsx +import { type LoaderFunctionArgs } from "@remix-run/node"; +import { useLoaderData } from "@remix-run/react"; +import { createBrowserClient } from "@supabase/ssr"; + +export async function loader({}: LoaderFunctionArgs) { + return { + env: { + SUPABASE_URL: process.env.SUPABASE_URL!, + SUPABASE_ANON_KEY: process.env.SUPABASE_ANON_KEY!, + }, + }; +} + +export default function Index() { + const { env } = useLoaderData(); + + const supabase = createBrowserClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY); + + return ... +} +``` + + + + + + + + + + + +```ts lib/supabase.js +const { createServerClient } = require('@supabase/ssr') + +exports.createClient = (context) => { + return createServerClient(process.env.SUPABASE_URL, process.env.SUPABASE_ANON_KEY, { + cookies: { + get: (key) => { + const cookies = context.req.cookies + const cookie = cookies[key] ?? '' + return decodeURIComponent(cookie) + }, + set: (key, value, options) => { + if (!context.res) return + context.res.cookie(key, encodeURIComponent(value), { + ...options, + sameSite: 'Lax', + httpOnly: true, + }) + }, + remove: (key, options) => { + if (!context.res) return + context.res.cookie(key, '', { ...options, httpOnly: true }) + }, + }, + }) +} +``` + + + + +```ts app.js +const express = require("express") +const dotenv = require("dotenv") + +const { createClient } = require("./lib/supabase") + +const app = express() + +app.post("/hello-world", async function (req, res, next) { + const { email, emailConfirm } = req.body + ... + + const supabase = createClient({ req, res }) +}) +``` + + + + + + + +## Next steps + +- Implement [Authentication using Email and Password](/docs/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr) +- Implement [Authentication using OAuth](/docs/guides/auth/server-side/oauth-with-pkce-flow-for-ssr) +- [Learn more about SSR](/docs/guides/auth/server-side-rendering) + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr.mdx b/apps/docs/pages/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr.mdx index 7365fa52fa6..beb54ed82d1 100644 --- a/apps/docs/pages/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr.mdx +++ b/apps/docs/pages/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr.mdx @@ -8,116 +8,9 @@ export const meta = { 'Learn how to configure email authentication in your server-side rendering (SSR) application to work with the PKCE flow.', } -### Install Supabase Auth Helpers +### Setting up SSR client -The Auth Helpers will assist you in implementing user authentication within your server-side rendering (SSR) framework. - - - - - -```bash -npm install @supabase/auth-helpers-nextjs @supabase/supabase-js -``` - - - - - -```bash -npm install @supabase/auth-helpers-sveltekit @supabase/supabase-js -``` - - - - - -### Set environment variables - -Create an `.env.local` file in your project root directory. You can get your `SITE_URL` and `ANON_KEY` from inside of the [dashboard](https://supabase.com/dashboard/project/_/settings/api). - - - - - -```bash .env.local -NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url -NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key -``` - - - - -```bash .env.local -PUBLIC_SUPABASE_URL=your_supabase_project_url -PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key -``` - - - - -### Setting up the Auth Helpers - -When using the Supabase client on the server, you must perform extra steps to ensure the user's auth session remains active. Since the user's session is tracked in a cookie, we need to read this cookie and update it if necessary. - - - -Next.js Server Components allow you to read a cookie but not write back to it. Middleware on the other hand allow you to both read and write to cookies. - -Next.js [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) runs immediately before each route is rendered. We'll use Middleware to refresh the user's session before loading Server Component routes. - -Create a new `middleware.js` file in the root of your project and populate with the following: - -```js middleware.js -import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' -import { NextResponse } from 'next/server' - -export async function middleware(req) { - const res = NextResponse.next() - const supabase = createMiddlewareClient({ req, res }) - await supabase.auth.getSession() - return res -} -``` - - - -Create a new `hooks.server.js` file in the root of your project and populate with the following: - -```ts src/hooks.server.js -import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public' -import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit' - -export const handle = async ({ event, resolve }) => { - event.locals.supabase = createSupabaseServerClient({ - supabaseUrl: PUBLIC_SUPABASE_URL, - supabaseKey: PUBLIC_SUPABASE_ANON_KEY, - event, - }) - - event.locals.getSession = async () => { - const { - data: { session }, - } = await event.locals.supabase.auth.getSession() - return session - } - - return resolve(event, { - filterSerializedResponseHeaders(name) { - return name === 'content-range' - }, - }) -} -``` - - - +Check out our [guide for creating a client](/docs/guides/auth/server-side/creating-a-client) to learn how to install the necessary packages, declare environment variables, and create a Supabase client configured for SSR in your framework. ### Create API endpoint for handling `token_hash` @@ -130,36 +23,59 @@ In order to use the updated email links we will need to setup a endpoint for ver defaultActiveId="nextjs" queryGroup="framework" > - -Create a new file at `app/auth/confirm/route.js` and populate with the following: + -```js app/auth/confirm/route.js -import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' +Create a new file at `app/auth/confirm/route.ts` and populate with the following: + +```ts app/auth/confirm/route.ts +import { createServerClient, type CookieOptions } from '@supabase/ssr' +import { type EmailOtpType } from '@supabase/supabase-js' import { cookies } from 'next/headers' import { NextResponse } from 'next/server' -export async function GET(req) { - const { searchParams } = new URL(req.url) +export async function GET(request: Request) { + const { searchParams } = new URL(request.url) const token_hash = searchParams.get('token_hash') - const type = searchParams.get('type') + const type = searchParams.get('type') as EmailOtpType | null const next = searchParams.get('next') ?? '/' if (token_hash && type) { const cookieStore = cookies() - const supabase = createRouteHandlerClient({ cookies: () => cookieStore }) - const { error } = await supabase.auth.verifyOtp({ type, token_hash }) + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + cookieStore.set({ name, value, ...options }) + }, + remove(name: string, options: CookieOptions) { + cookieStore.delete({ name, ...options }) + }, + }, + } + ) + + const { error } = await supabase.auth.verifyOtp({ + type, + token_hash, + }) if (!error) { - return NextResponse.redirect(new URL(`/${next.slice(1)}`, req.url)) + return NextResponse.redirect(new URL(`/${next.slice(1)}`, request.url)) } } // return the user to an error page with some instructions - return NextResponse.redirect(new URL('/auth/auth-code-error', req.url)) + return NextResponse.redirect(new URL('/auth/auth-code-error', request.url)) } ``` + Create a new file at `src/routes/auth/confirm/+server.js` and populate with the following: ```js src/routes/auth/confirm/+server.js @@ -186,6 +102,135 @@ export const GET = async (event) => { }; ``` + + + + +Create a new file at `src/pages/auth/confirm.ts` and populate with the following: + +```ts src/pages/auth/confirm.ts +import { createServerClient } from '@supabase/ssr' +import { type EmailOtpType } from '@supabase/supabase-js' +import { type APIRoute } from 'astro' + +export const GET: APIRoute = async ({ request, cookies, redirect }) => { + const requestUrl = new URL(request.url) + const token_hash = requestUrl.searchParams.get('token_hash') + const type = requestUrl.searchParams.get('type') as EmailOtpType | null + const next = requestUrl.searchParams.get('next') || '/' + + if (token_hash && type) { + const supabase = createServerClient( + import.meta.env.PUBLIC_SUPABASE_URL, + import.meta.env.PUBLIC_SUPABASE_ANON_KEY, + { + cookies: { + get(key) { + return cookies.get(key)?.value + }, + set(key, value, options) { + cookies.set(key, value, options) + }, + remove(key, options) { + cookies.delete(key, options) + }, + }, + } + ) + + const { error } = await supabase.auth.verifyOtp({ + type, + token_hash, + }) + + if (!error) { + return redirect(`/${next.slice(1)}`) + } + } + + // return the user to an error page with some instructions + return redirect('/auth/auth-code-error') +} +``` + + + + + +Create a new file at `app/routes/auth.confirm.tsx` and populate with the following: + +```ts app/routes/auth.confirm.tsx +import { redirect, type LoaderFunctionArgs } from '@remix-run/node' +import { createServerClient, parse, serialize } from '@supabase/ssr' +import { type EmailOtpType } from '@supabase/supabase-js' + +export async function loader({ request }: LoaderFunctionArgs) { + const requestUrl = new URL(request.url) + const token_hash = requestUrl.searchParams.get('token_hash') + const type = requestUrl.searchParams.get('type') as EmailOtpType | null + const next = requestUrl.searchParams.get('next') || '/' + + if (token_hash && type) { + const cookies = parse(request.headers.get('Cookie') ?? '') + const headers = new Headers() + + const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + get(key) { + return cookies[key] + }, + set(key, value, options) { + headers.append('Set-Cookie', serialize(key, value, options)) + }, + remove(key, options) { + headers.append('Set-Cookie', serialize(key, '', options)) + }, + }, + }) + + const { error } = await supabase.auth.verifyOtp({ + type, + token_hash, + }) + + if (!error) { + return redirect(`/${next.slice(1)}`) + } + } + + // return the user to an error page with instructions + return redirect('/auth/auth-code-error') +} +``` + + + + +Create a new route in your express app and populate with the following: + +```js app.js +... +app.get("/auth/confirm", async function (req, res) { + const token_hash = req.query.token_hash + const type = req.query.type + const next = req.query.next ?? "/" + + if (token_hash && type) { + const supabase = createClient({ req, res }) + const { error } = await supabase.auth.verifyOtp({ + type, + token_hash, + }) + if (!error) { + res.redirect(303, `/${next.slice(1)}`) + } + } + + // return the user to an error page with some instructions + res.redirect(303, '/auth/auth-code-error') +}) +``` + diff --git a/apps/docs/pages/guides/auth/server-side/migrating-to-ssr-from-auth-helpers.mdx b/apps/docs/pages/guides/auth/server-side/migrating-to-ssr-from-auth-helpers.mdx new file mode 100644 index 00000000000..4ff96642f8b --- /dev/null +++ b/apps/docs/pages/guides/auth/server-side/migrating-to-ssr-from-auth-helpers.mdx @@ -0,0 +1,56 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + title: 'Migrating to the SSR package from Auth Helpers', + description: 'Step-by-step guide to migrating your app to the new SSR package', + sidebar_label: 'Migrating to SSR from Auth Helpers', +} + +The new `ssr` package takes the core concepts of the Auth Helpers and makes them available to any server language or framework. This page will guide you through migrating from the Auth Helpers package to `ssr`. + +### Replacing Supabase packages + + + + + +```bash +npm uninstall @supabase/auth-helpers-nextjs +``` + + + + +```bash +npm uninstall @supabase/auth-helpers-sveltekit +``` + + + + +```bash +npm uninstall @supabase/auth-helpers-remix +``` + + + + +```bash +npm install @supabase/ssr +``` + +### Creating a client + +The new `ssr` package exports two functions for creating a Supabase client. The `createBrowserClient` function is used in the client, and the `createServerClient` function is used in the server. + +Check out the [Creating a client](/docs/guides/auth/server-side/creating-a-client) page for examples of creating a client in your framework. + +## Next steps + +- Implement [Authentication using Email and Password](/docs/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr) +- Implement [Authentication using OAuth](/docs/guides/auth/server-side/oauth-with-pkce-flow-for-ssr) +- [Learn more about SSR](/docs/guides/auth/server-side-rendering) + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx b/apps/docs/pages/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx index f6cdd532c22..526f09a73f9 100644 --- a/apps/docs/pages/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx +++ b/apps/docs/pages/guides/auth/server-side/oauth-with-pkce-flow-for-ssr.mdx @@ -8,127 +8,9 @@ export const meta = { 'Learn how to configure OAuth authentication in your server-side rendering (SSR) application to work with the PKCE flow.', } -### Install Supabase Auth Helpers +### Setting up SSR client -The Auth Helpers assist with user authentication within server-side rendering (SSR) frameworks. - - - - -```bash -npm install @supabase/auth-helpers-nextjs @supabase/supabase-js -``` - - - - -```bash -npm install @supabase/auth-helpers-sveltekit @supabase/supabase-js -``` - - - - -### Set environment variables - -Create an `.env.local` file in your project root directory. You can get your `SITE_URL` and `ANON_KEY` from inside of the [dashboard](https://supabase.com/dashboard/project/_/settings/api). - - - - -```bash .env.local -NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url -NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key -``` - - - - -```bash .env.local -PUBLIC_SUPABASE_URL=your_supabase_project_url -PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key -``` - - - - -### Setting up the Auth Helpers - -For SSR, the Supabase client requires extra steps to ensure the user's auth session remains active. Since the user's session is tracked in a cookie, we need to read this cookie and update it if necessary. - - - -Next.js Server Components allow you to read a cookie but not write back to it. Middleware on the other hand allow you to both read and write to cookies. - -Next.js [Middleware](https://nextjs.org/docs/app/building-your-application/routing/middleware) runs immediately before each route is rendered. We'll use Middleware to refresh the user's session before loading Server Component routes. - -Create a new `middleware.js` file in the root of your project and populate with the following: - -```js middleware.js -import { createMiddlewareClient } from '@supabase/auth-helpers-nextjs' -import { NextResponse } from 'next/server' - -export async function middleware(req) { - const res = NextResponse.next() - const supabase = createMiddlewareClient({ req, res }) - await supabase.auth.getSession() - return res -} -``` - - - -Create a new `hooks.server.js` file in the root of your project and populate with the following: - -```ts src/hooks.server.js -import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public' -import { createSupabaseServerClient } from '@supabase/auth-helpers-sveltekit' -import type { Handle } from '@sveltejs/kit' -import { dev } from '$app/environment' - -export const handle: Handle = async ({ event, resolve }) => { - event.locals.supabase = createSupabaseServerClient({ - supabaseUrl: PUBLIC_SUPABASE_URL, - supabaseKey: PUBLIC_SUPABASE_ANON_KEY, - event, - cookieOptions: { secure: !dev }, - }) - - event.locals.getSession = async () => { - const { - data: { session }, - } = await event.locals.supabase.auth.getSession() - return session - } - - return resolve(event, { - filterSerializedResponseHeaders(name) { - return name === 'content-range' - }, - }) -} -``` - - - +Check out our [guide for creating a client](/docs/guides/auth/server-side/creating-a-client) to learn how to install the necessary packages, declare environment variables, and create a Supabase client configured for SSR in your framework. ### Create API endpoint for handling the `code` exchange @@ -141,35 +23,55 @@ In order to use OAuth we will need to setup a endpoint for the `code` exchange, defaultActiveId="nextjs" queryGroup="framework" > - -Create a new file at `app/auth/callback/route.js` and populate with the following: + -```js app/auth/callback/route.js -import { createRouteHandlerClient } from '@supabase/auth-helpers-nextjs' +Create a new file at `app/auth/callback/route.ts` and populate with the following: + +```ts app/auth/callback/route.ts +import { createServerClient, type CookieOptions } from '@supabase/ssr' import { cookies } from 'next/headers' import { NextResponse } from 'next/server' -export async function GET(req) { - const { searchParams } = new URL(req.url) +export async function GET(request: Request) { + const { searchParams } = new URL(request.url) const code = searchParams.get('code') const next = searchParams.get('next') ?? '/' if (code) { const cookieStore = cookies() - const supabase = createRouteHandlerClient({ cookies: () => cookieStore }) + + const supabase = createServerClient( + process.env.NEXT_PUBLIC_SUPABASE_URL!, + process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, + { + cookies: { + get(name: string) { + return cookieStore.get(name)?.value + }, + set(name: string, value: string, options: CookieOptions) { + cookieStore.set({ name, value, ...options }) + }, + remove(name: string, options: CookieOptions) { + cookieStore.delete({ name, ...options }) + }, + }, + } + ) + const { error } = await supabase.auth.exchangeCodeForSession(code) if (!error) { - return NextResponse.redirect(new URL(`/${next.slice(1)}`, req.url)) + return NextResponse.redirect(new URL(`/${next.slice(1)}`, request.url)) } } // return the user to an error page with instructions - return NextResponse.redirect(new URL('/auth/auth-code-error', req.url)) + return NextResponse.redirect(new URL('/auth/auth-code-error', request.url)) } ``` + Create a new file at `src/routes/auth/callback/+server.js` and populate with the following: ```js src/routes/auth/callback/+server.js @@ -195,6 +97,117 @@ export const GET = async (event) => { }; ``` + + + + +Create a new file at `src/pages/auth/callback.ts` and populate with the following: + +```ts src/pages/auth/callback.ts +import { createServerClient } from '@supabase/ssr' +import { type APIRoute } from 'astro' + +export const GET: APIRoute = async ({ request, cookies, redirect }) => { + const requestUrl = new URL(request.url) + const code = requestUrl.searchParams.get('code') + const next = requestUrl.searchParams.get('next') || '/' + + if (code) { + const supabase = createServerClient( + import.meta.env.PUBLIC_SUPABASE_URL, + import.meta.env.PUBLIC_SUPABASE_ANON_KEY, + { + cookies: { + get(key) { + return cookies.get(key)?.value + }, + set(key, value, options) { + cookies.set(key, value, options) + }, + remove(key, options) { + cookies.delete(key, options) + }, + }, + } + ) + + const { error } = await supabase.auth.exchangeCodeForSession(code) + + if (!error) { + return redirect(`/${next.slice(1)}`) + } + } + + // return the user to an error page with instructions + return redirect('/auth/auth-code-error') +} +``` + + + + + +Create a new file at `app/routes/auth.callback.tsx` and populate with the following: + +```ts app/routes/auth.callback.tsx +import { redirect, type LoaderFunctionArgs } from '@remix-run/node' +import { createServerClient, parse, serialize } from '@supabase/ssr' + +export async function loader({ request }: LoaderFunctionArgs) { + const requestUrl = new URL(request.url) + const code = requestUrl.searchParams.get('code') + const next = requestUrl.searchParams.get('next') || '/' + + if (code) { + const cookies = parse(request.headers.get('Cookie') ?? '') + const headers = new Headers() + + const supabase = createServerClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!, { + cookies: { + get(key) { + return cookies[key] + }, + set(key, value, options) { + headers.append('Set-Cookie', serialize(key, value, options)) + }, + remove(key, options) { + headers.append('Set-Cookie', serialize(key, '', options)) + }, + }, + }) + + const { error } = await supabase.auth.exchangeCodeForSession(code) + + if (!error) { + return redirect(`/${next.slice(1)}`) + } + } + + // return the user to an error page with instructions + return redirect('/auth/auth-code-error') +} +``` + + + + +Create a new route in your express app and populate with the following: + +```js app.js +... +app.get("/auth/callback", async function (req, res) { + const code = req.query.code + const next = req.query.next ?? "/" + + if (code) { + const supabase = createClient({ req, res }) + await supabase.auth.exchangeCodeForSession(code) + } + + res.redirect(303, `/${next.slice(1)}`) +}) +``` + diff --git a/apps/docs/pages/guides/auth/server-side/overview.mdx b/apps/docs/pages/guides/auth/server-side/overview.mdx new file mode 100644 index 00000000000..71d93ecb89c --- /dev/null +++ b/apps/docs/pages/guides/auth/server-side/overview.mdx @@ -0,0 +1,53 @@ +import Layout from '~/layouts/DefaultGuideLayout' + +export const meta = { + id: 'index', + title: 'Server-Side Auth Overview', + description: 'Configure Supabase Auth to use Cookies', + sidebar_label: 'Overview', +} + +When using Supabase with server-side languages and frameworks - such as Next.js, SvelteKit and Remix - it is important to configure your Supabase client to use cookies for storing user sessions. We have developed an `@supabase/ssr` package to make this process as simple as possible. This package is currently in `beta`, and is likely to have breaking changes in the future. + +## Framework Quickstarts + +
+ {quickstarts.map((item) => { + return ( + + + + {item.description} + + + + ) + })} +
+ + + +If you're currently using the [Auth Helpers package](https://github.com/supabase/auth-helpers), the [docs are still available](/docs/guides/auth/auth-helpers), however we recommend migrating to the new `@supabase/ssr` package as this will be the recommended path moving forward. + + + +## Next steps + +- [Create a Supabase client for SSR](/docs/guides/auth/server-side/creating-a-client) +- [Email Auth with PKCE flow for SSR](/docs/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr) +- [OAuth with PKCE flow for SSR](/docs/guides/auth/server-side/oauth-with-pkce-flow-for-ssr) +- [Learn more about SSR](/docs/guides/auth/server-side-rendering) + +export const quickstarts = [ + { + title: 'Next.js', + href: '/guides/auth/quickstarts/nextjs', + description: + 'Automatically configure Supabase to use cookies, making your user and their session available on the client and server.', + icon: '/docs/img/icons/nextjs-icon', + }, +] + +export const Page = ({ children }) => + +export default Page diff --git a/apps/docs/pages/guides/getting-started.mdx b/apps/docs/pages/guides/getting-started.mdx index 0097c94bbb9..59eb91b933a 100644 --- a/apps/docs/pages/guides/getting-started.mdx +++ b/apps/docs/pages/guides/getting-started.mdx @@ -137,10 +137,10 @@ export const quickstarts = [ icon: '/docs/img/icons/react-icon', }, { - title: 'NextJS', + title: 'Next.js', href: '/guides/getting-started/quickstarts/nextjs', description: - 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a NextJS app.', + 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Next.js app.', icon: '/docs/img/icons/nextjs-icon', }, { diff --git a/apps/docs/pages/guides/getting-started/quickstarts/nextjs.mdx b/apps/docs/pages/guides/getting-started/quickstarts/nextjs.mdx index 3fc3687f201..9debfcdf84b 100644 --- a/apps/docs/pages/guides/getting-started/quickstarts/nextjs.mdx +++ b/apps/docs/pages/guides/getting-started/quickstarts/nextjs.mdx @@ -4,20 +4,20 @@ import StepHikeCompact from '~/components/StepHikeCompact' export const meta = { title: 'Use Supabase with Next.js', subtitle: - 'Learn how to create a Supabase project, add some sample data to your database, and query the data from a Next.js app.', + 'Learn how to create a Supabase project, add some sample data, and query from a Next.js app.', breadcrumb: 'Framework Quickstarts', } - + - [Create a new project](https://supabase.com/dashboard) in the Supabase Dashboard. + Head over to [database.new](https://database.new) and create a new Supabase project. - After your project is ready, create a table in your Supabase database using the [SQL Editor](https://supabase.com/dashboard/project/_/sql) in the Dashboard. + When your project is up and running, navigate to the [Table Editor](https://supabase.com/dashboard/project/_/editor), create a new table and insert some data. - Use the following SQL statement to create a `countries` table with some sample data. + Alternatively, you can run the following snippet in your project's [SQL Editor](https://supabase.com/dashboard/project/_/sql/new). This will create a `notes` table with some sample data. @@ -25,15 +25,17 @@ export const meta = { ```sql SQL_EDITOR -- Create the table - create table countries ( + create table notes ( id serial primary key, - name text not null + title text ); - -- Insert some sample data into the table - insert into countries (name) values ('United States'); - insert into countries (name) values ('Canada'); - insert into countries (name) values ('Mexico'); + -- Insert some sample data + insert into notes (title) + values + ('Today I created a Supabase project.'), + ('I added some data and queried it from Next.js.'), + ('It was awesome!'); ```` @@ -45,7 +47,7 @@ export const meta = { Use the `create-next-app` command and the `with-supabase` template, to create a Next.js app pre-configured with: - - [Supabase Auth](https://supabase.com/docs/guides/auth/auth-helpers/nextjs) + - [Cookie-based Auth](https://supabase.com/docs/guides/auth/auth-helpers/nextjs) - [TypeScript](https://www.typescriptlang.org/) - [Tailwind CSS](https://tailwindcss.com/) @@ -54,7 +56,7 @@ export const meta = { ```bash Terminal - npx create-next-app -e with-supabase my-app && cd my-app + npx create-next-app -e with-supabase ``` @@ -82,31 +84,24 @@ export const meta = { - Create a new file at `app/countries/page.tsx` and populate with the following. + Create a new file at `app/notes/page.tsx` and populate with the following. - This will select all the rows from the `countries` table in Supabase and render them on the page. + This will select all the rows from the `notes` table in Supabase and render them on the page. - ```ts app/countries/page.tsx - import { createServerComponentClient } from "@supabase/auth-helpers-nextjs"; - import { cookies } from "next/headers"; + ```ts app/notes/page.tsx + import { createClient } from '@/utils/supabase/server'; - export default async function Index() { - const cookieStore = cookies() - const supabase = createServerComponentClient({ cookies: () => cookieStore }) + export const dynamic = "force-dynamic"; - const { data: countries } = await supabase.from("countries").select(); + export default async function Notes() { + const supabase = createClient(); + const { data: notes } = await supabase.from("notes").select(); - return ( -
    - {countries?.map((country) => ( -
  • {country.name}
  • - ))} -
- ); + return
{JSON.stringify(notes, null, 2)}
} ``` @@ -117,7 +112,7 @@ export const meta = { - Run the development server, go to http://localhost:3000/countries in a browser and you should see the list of countries. + Run the development server, go to http://localhost:3000/notes in a browser and you should see the list of notes. diff --git a/apps/docs/public/sitemap.xml b/apps/docs/public/sitemap.xml index 7d6d2734095..2265c0df0bd 100644 --- a/apps/docs/public/sitemap.xml +++ b/apps/docs/public/sitemap.xml @@ -978,6 +978,22 @@ 0.5 + + https://supabase.com/docs/guides/auth/server-side/overview + weekly + 0.5 + + + + https://supabase.com/docs/guides/auth/server-side/creating-a-client + weekly + 0.5 + + https://supabase.com/docs/guides/auth/server-side/email-based-auth-with-pkce-flow-for-ssr0.5 + + https://supabase.com/docs/guides/auth/server-side/migrating-to-ssr-from-auth-helpers + weekly + 0.5 + + https://supabase.com/docs/guides/auth/concepts/redirect-urls weekly