new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Supabase · Auth · all subjects

authentication/methods

414 notes in this subject, read out of this brain and free to use. This is page 6 of 7.

Vercel preview URL configuration

For deployments with Vercel, set SITE_URL to your official site URL. Add the following additional redirect URLs for local development and deployment previews: 'http://localhost:3000/**' and 'https://*-<team-or-account-slug>.vercel.app/**'. Vercel provides an environment variable for the URL of the deployment called NEXT_PUBLIC_VERCEL_URL. You should also set the environment variable NEXT_PUBLIC_SITE_URL to your site URL in production environment to ensure that redirects function correctly.

Vercel dynamic redirect URL example

This code shows how to dynamically set the redirect URL depending on the environment in Vercel: const getURL = () => { let url = process?.env?.NEXT_PUBLIC_SITE_URL ?? process?.env?.NEXT_PUBLIC_VERCEL_URL ?? 'http://localhost:3000/'; url = url.startsWith('http') ? url : `https://${url}`; url = url.endsWith('/') ? url : `${url}/`; return url; }; const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'github', options: { redirectTo: getURL(), }, });

Web3 sign-in and redirect URL message signing

When using Sign in with Web3, the message signed by the user in the Web3 wallet application will indicate the URL on which the signature took place. Supabase Auth will reject messages that are signed for URLs that are not on the allowed redirect URL list.

Mobile deep linking URIs

For mobile applications you can use deep linking URIs. For example, for SITE_URL you can specify something like com.supabase://login-callback/ and for additional redirect URLs something like com.supabase.staging://login-callback/ if needed.

Error handling in redirected URLs

When authentication fails, the user will still be redirected to the redirect URL provided. The error details will be returned as query fragments in the URL. You can parse these query fragments and show a custom error message to the user.

Error handling in redirect URL example

This code shows how to parse error details from query fragments when redirected after authentication failure: const params = new URLSearchParams(window.location.hash.slice()); if (params.get('error_code').startsWith('4')) { window.alert(params.get('error_description')); }

Email template redirectTo replacement

When using a redirectTo option in sign-in methods, you may need to replace {{ .SiteURL }} with {{ .RedirectTo }} in your email templates. For example, change from: <a href="{{ .SiteURL }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Confirm email address</a> to: <a href="{{ .RedirectTo }}/auth/confirm?token_hash={{ .TokenHash }}&type=email">Confirm email address</a>

SSR package replaces Auth Helpers

The @supabase/ssr package replaces the framework-specific Auth Helpers packages (@supabase/auth-helpers-nextjs, @supabase/auth-helpers-sveltekit, @supabase/auth-helpers-remix). The ssr package makes the core concepts of Auth Helpers available to any server language or framework.

Migration: uninstall framework Auth Helpers, install @supabase/ssr

To migrate from Auth Helpers to the SSR package, first uninstall the framework-specific package (such as @supabase/auth-helpers-nextjs, @supabase/auth-helpers-sveltekit, or @supabase/auth-helpers-remix), then install @supabase/ssr via npm install @supabase/ssr.

SSR package exports createBrowserClient and createServerClient

The @supabase/ssr package exports two functions: createBrowserClient for creating a Supabase client on the client side, and createServerClient for creating a Supabase client on the server side.

Implicit flow returns tokens in URL fragment

After a successful signin with implicit flow, the user is redirected to the app with tokens in the URL fragment (hash). The format is: https://yourapp.com/...#access_token=<...>&refresh_token=<...>&... Client libraries detect this URL, extract the access token, refresh token, and extra information, then persist this information to local storage.

Implicit flow works only on client, not server

The implicit flow only works on the client. Web browsers do not send the URL fragment to the server by design. This is a security feature that prevents third-party servers from accessing user credentials and prevents credentials from being leaked in request or access logs.

Use PKCE flow to obtain tokens on server

If you need to obtain access tokens and refresh tokens on a server, you must use the PKCE flow instead of implicit flow.

Difference between implicit and PKCE flow

Implicit flow and PKCE flow are two different ways for a user to authenticate and receive access and refresh tokens. Understanding the difference is important for understanding the difference between client-only and server-side auth.

PKCE auth code validity and exchange limits

For security purposes, the auth code has a validity of 5 minutes and can only be exchanged for an access token once. If a new access token is needed, the authentication flow must be restarted from scratch.

PKCE flow overview

The Proof Key for Code Exchange (PKCE) flow is one of two ways that a user can authenticate and an app can receive access and refresh tokens. It is an implementation detail handled by Supabase Auth and differs from implicit flow in how it relates to client-only versus server-side auth.

PKCE auth code parameter

After successful verification in PKCE flow, the user is redirected to the app with a URL containing a code parameter: https://yourapp.com/...?code=<...>. This code parameter is the Auth Code and can be exchanged for an access token by calling exchangeCodeForSession(code).

detectSessionInUrl option for PKCE flow

The client library can be configured to automatically exchange the auth code for a session after a successful redirect by setting the detectSessionInUrl option to true.

PKCE client initialization example

Example of initializing the Supabase client with PKCE flow configuration: ```js import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...', { // ... auth: { // ... detectSessionInUrl: true, flowType: 'pkce', storage: { getItem: () => Promise.resolve('FETCHED_TOKEN'), setItem: () => {}, removeItem: () => {}, }, }, // ... }) ```

PKCE code verifier requirement and limitation

The PKCE code exchange requires a code verifier that is created and stored locally when the Auth flow is initiated. Both the code in the URL and the code verifier are sent to the Auth server for a successful exchange. This means the code exchange must be initiated on the same browser and device where the flow was started.

SSR package default configuration

In the @supabase/ssr package, Supabase clients are initiated to use the PKCE flow by default and are automatically configured to handle saving and retrieval of session information in cookies.

PKCE flow code exchange process

In the PKCE flow, a redirect is made to your app with an Auth Code contained in the URL. When you exchange this code using exchangeCodeForSession, you receive the session information which contains the access and refresh tokens. These tokens must be stored in a storage medium securely shared between client and server, typically cookies.

PKCE flow required for SSR instead of implicit flow

For server-side rendering, you should change from the implicit flow to the PKCE flow, as the server cannot access tokens in the implicit flow. The flow type can be changed when initiating the Supabase client if the client library provides this option.

Next.js route prefetching can cause missing cookies on server

When using route prefetching in Next.js with Link href or Router.push APIs, server-side requests can be sent before the browser processes the access and refresh tokens, resulting in requests without cookies and unauthenticated content rendering.

Recommended flow after Next.js sign-in

To improve user experience with Next.js route prefetching, redirect users to one specific page after sign-in that does not include route prefetching. Once the Supabase client library obtains tokens from the URL fragment, users can be sent to any pages that use prefetching.

Stale refresh token errors in SSR

If the server receives invalid refresh token errors, it is likely that the refresh token sent from the browser is stale. Ensure the onAuthStateChange listener callback is free of bugs and registered early in the application's lifetime.

Defer rendering to browser for stale token recovery

When receiving invalid refresh token errors on the server-side, defer rendering to the browser where the client library can access an up-to-date refresh token and present the user with a better experience.

ISR can cause session leakage with Set-Cookie headers

If you use incremental static regeneration on pages that trigger a Supabase session refresh, the cached response will include the Set-Cookie header containing the refreshed JWT. When that cached response is served to a subsequent user, their browser stores the token and they are signed in as the wrong person.

Disable ISR on authenticated routes

Do not enable ISR on any route where authentication is handled or where a session refresh can occur. In Nuxt, avoid setting isr on authenticated routes. In Next.js, use export const dynamic = 'force-dynamic' on pages that require authentication.

CDN and reverse proxy caching can cause session leakage

When @supabase/ssr refreshes a session token server-side, it writes the updated JWT to the HTTP response via a Set-Cookie header. If a CDN caches that response and serves it to a different user, that user's browser will store the cached token and be signed in as the wrong person.

Automatic cache headers from @supabase/ssr v0.10.0+

As of @supabase/ssr v0.10.0, the library automatically passes necessary cache headers (Cache-Control, Expires, Pragma) to the setAll callback as a second argument whenever a token refresh occurs. If the setAll implementation applies those headers to the response, no additional manual configuration is needed for most CDNs.

Manual cache headers for older @supabase/ssr versions

If using an older version of @supabase/ssr or needing to set headers manually, add Cache-Control: private, no-store to responses from any route that handles authentication to prevent CDN caching of Set-Cookie headers.

Next.js middleware cache control header example

In Next.js middleware, set the Cache-Control header with: const response = NextResponse.next(); response.headers.set('Cache-Control', 'private, no-store'); return response;

Nuxt server middleware cache control header example

In Nuxt server middleware, set the Cache-Control header with: setHeader(event, 'Cache-Control', 'private, no-store');

CloudFront cache behavior with Cache-Control headers

CloudFront's behavior depends on its cache policy configuration and is not solely controlled by the Cache-Control response header. Even with Cache-Control: private, no-store, CloudFront can still cache the response and Set-Cookie header if its cache policy has a Minimum TTL greater than 0, or if cookies and Set-Cookie headers are not forwarded to the origin.

CloudFront protection strategies

To protect against session leakage on CloudFront, use one or more of the following: Set Minimum TTL to 0 in the cache policy to allow Cache-Control: no-store to take effect; use Cache-Control: no-cache="Set-Cookie" to prevent caching of the Set-Cookie header specifically; or disable caching entirely for authenticated routes by associating a cache policy with TTL set to 0 or using the managed CachingDisabled policy.

Selective caching for SSR pages

If caching SSR pages for performance, apply caching only to routes that do not write Set-Cookie headers, and always include the refresh token cookie value in the cache key for any routes that serve user-specific content.

Vercel Fluid compute session leakage risk

Vercel's Fluid compute model can keep server instances warm and reuse them across requests. A Supabase client initialized in module scope or stored in a shared variable may be reused across requests from different users, causing one user's session to leak into another user's request.

Initialize Supabase client inside request handler

Always initialize the Supabase client inside the request handler, not at module level. Do not store the client or any user-specific state in a variable that persists between requests.

PKCE support across authentication flows

PKCE is supported on the Magic Link, OAuth, Sign Up, and Password Recovery routes, corresponding to the signInWithOtp, signInWithOAuth, signUp, and resetPasswordForEmail methods on the Supabase client library. When using PKCE with Phone and Email OTPs, there is no behavior change with respect to the implicit flow - an access token will be returned in the body when a request is successful.

Sign out method removes session and clears Auth data

Signing out a user works the same way regardless of the sign-in method used. Calling the sign out method from the client library removes the active session and clears Auth data from the storage medium.

JavaScript sign out example

The JavaScript sign out method is called as: await supabase.auth.signOut(). This removes the active session and clears Auth data from storage.

Dart sign out example

The Dart sign out method is called as: await supabase.auth.signOut(). By default it uses the local scope.

Swift sign out example

The Swift sign out method is called as: try await supabase.auth.signOut().

Python sign out example

The Python sign out method is called as: supabase.auth.sign_out().

C# sign out example

The C# sign out method is called as: await supabase.Auth.SignOut().

Sign out scopes: global, local, others

Supabase Auth supports three different scopes for sign out: global (default) terminates all sessions active for the user; local terminates only the current session while keeping sessions on other devices or browsers active; others terminates all sessions except the current one.

JavaScript sign out with scope parameter

JavaScript sign out can specify scope using: await supabase.auth.signOut() defaults to global scope; await supabase.auth.signOut({ scope: 'local' }) signs out from the current session only.

Dart sign out with scope parameter

Dart sign out can specify scope using: await supabase.auth.signOut() defaults to local scope; await supabase.auth.signOut(scope: SignOutScope.global) signs out from all sessions.

Kotlin sign out with scope parameter

Kotlin sign out can specify scope using: supabase.auth.signOut() defaults to local scope; supabase.auth.signOut(SignOutScope.GLOBAL) signs out from all sessions.

C# sign out with scope parameter

C# sign out can specify scope using: await supabase.Auth.SignOut() defaults to global scope; await supabase.Auth.SignOut(SignOutScope.Local) signs out from the current session only.

Sign out destroys refresh tokens and session data

Upon sign out, all refresh tokens and potentially other database objects related to the affected sessions are destroyed, and the client library removes the session stored in the local storage medium.

Sign in with Figma using JavaScript

Call supabase.auth.signInWithOAuth() with provider set to 'figma' to sign in a user with Figma OAuth. Example: ```js import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...') async function signInWithFigma() { const { data, error } = await supabase.auth.signInWithOAuth({ provider: 'figma', }) } ```

Sign in with Figma using Flutter

Call supabase.auth.signInWithOAuth() with OAuthProvider.figma to sign in a user with Figma OAuth. Optionally set redirectTo with a deeplink scheme for mobile, and set authScreenLaunchMode to LaunchMode.externalApplication on mobile or LaunchMode.platformDefault on web. Example: ```dart Future<void> signInWithFigma() async { await supabase.auth.signInWithOAuth( OAuthProvider.figma, redirectTo: kIsWeb ? null : 'my.scheme://my-host', authScreenLaunchMode: kIsWeb ? LaunchMode.platformDefault : LaunchMode.externalApplication, ); } ```

Sign in with Figma using Kotlin

Call supabase.auth.signInWith(Figma) to sign in a user with Figma OAuth. Example: ```kotlin suspend fun signInWithFigma() { supabase.auth.signInWith(Figma) } ```

Sign in with Figma using C#

Call supabase.Auth.SignIn() with Provider.Figma to initiate Figma OAuth sign in. The method returns a state object with a Uri property containing the sign-in URL. Example: ```c# var state = await supabase.Auth.SignIn(Provider.Figma); var signInUrl = state.Uri; ```

JavaScript sign-out example

import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...') async function signOut() { const { error } = await supabase.auth.signOut() }

Swift sign-out example

func signOut() async throws { try await supabase.auth.signOut() } This example shows how to call signOut() in Swift to remove the user from the browser session and any objects from localStorage.

signOut Flutter example

Dart code to sign out using Supabase: Future<void> signOut() async { await supabase.auth.signOut(); } This removes the user from the browser session and localStorage.

JavaScript sign-out example

To sign out in JavaScript, call supabase.auth.signOut() to remove the user from the browser session and any objects from localStorage: ```js import { createClient } from '@supabase/supabase-js' const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...') async function signOut() { const { error } = await supabase.auth.signOut() } ```

Give your agent this brain