diff --git a/apps/docs/content/guides/auth/social-login/auth-google.mdx b/apps/docs/content/guides/auth/social-login/auth-google.mdx index fcacd776d7e37..85bd5813d8136 100644 --- a/apps/docs/content/guides/auth/social-login/auth-google.mdx +++ b/apps/docs/content/guides/auth/social-login/auth-google.mdx @@ -397,7 +397,7 @@ const OneTapComponent = () => { const supabase = createClient() const router = useRouter() - const initializeGoogleOneTap = () => { + const initializeGoogleOneTap = async () => { console.log('Initializing Google One Tap') const [nonce, hashedNonce] = await generateNonce() console.log('Nonce: ', nonce, hashedNonce) diff --git a/apps/docs/content/guides/database/postgres/row-level-security.mdx b/apps/docs/content/guides/database/postgres/row-level-security.mdx index 93e4ccf31e0ac..68056789ceaa3 100644 --- a/apps/docs/content/guides/database/postgres/row-level-security.mdx +++ b/apps/docs/content/guides/database/postgres/row-level-security.mdx @@ -425,7 +425,7 @@ $$; create policy "rls_test_select" on test_table to authenticated -using ( private.has_good_role() ); +using ( (select private.has_good_role()) ); ``` diff --git a/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx b/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx index c2b1702ebe8c5..032663d43fbe1 100644 --- a/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx +++ b/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx @@ -66,8 +66,8 @@ hideToc: true <$CodeTabs> ```text name=.env - VITE_PUBLIC_SUPABASE_URL= - VITE_PUBLIC_SUPABASE_ANON_KEY= + PUBLIC_SUPABASE_URL= + PUBLIC_SUPABASE_ANON_KEY= ``` @@ -89,16 +89,16 @@ hideToc: true ```js name=src/lib/supabaseClient.js import { createClient } from '@supabase/supabase-js'; - import { VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'; + import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'; - export const supabase = createClient(VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY) + export const supabase = createClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY) ``` ```ts name=src/lib/supabaseClient.ts import { createClient } from '@supabase/supabase-js'; - import { VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'; + import { PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY } from '$env/static/public'; - export const supabase = createClient(VITE_PUBLIC_SUPABASE_URL, VITE_PUBLIC_SUPABASE_ANON_KEY) + export const supabase = createClient(PUBLIC_SUPABASE_URL, PUBLIC_SUPABASE_ANON_KEY) ``` diff --git a/apps/docs/content/guides/platform/upgrading.mdx b/apps/docs/content/guides/platform/upgrading.mdx index 0460df6c339cf..5d001b186ba7f 100644 --- a/apps/docs/content/guides/platform/upgrading.mdx +++ b/apps/docs/content/guides/platform/upgrading.mdx @@ -164,6 +164,7 @@ In projects using Postgres 17, the following extensions are deprecated: - `plls` - `plv8` - `timescaledb` +- `pgjwt` Existing projects on lower versions of Postgres are not impacted, and the extensions will continue to be supported on projects using Postgres 15, until the end of life of Postgres 15 on the Supabase platform. diff --git a/apps/docs/public/humans.txt b/apps/docs/public/humans.txt index 1d2fe38b68bdf..7c8e85fa134b3 100644 --- a/apps/docs/public/humans.txt +++ b/apps/docs/public/humans.txt @@ -38,6 +38,7 @@ Deepthi Sigireddi Deji I Div Arora Divit D +Douglas Hunley Eduardo Gurgel Egor Romanov Eleftheria Trivyzaki diff --git a/apps/docs/spec/cli_v1_commands.yaml b/apps/docs/spec/cli_v1_commands.yaml index d799f35c9ceac..e5f3358609f28 100644 --- a/apps/docs/spec/cli_v1_commands.yaml +++ b/apps/docs/spec/cli_v1_commands.yaml @@ -1,7 +1,7 @@ clispec: '001' info: id: cli - version: 2.33.9 + version: 2.34.3 title: Supabase CLI language: sh source: https://github.com/supabase/cli @@ -74,7 +74,7 @@ flags: name: --workdir description: path to a Supabase project directory default_value: '' - - id: 'yes' + - id: "yes" name: --yes description: answer yes to all prompts default_value: 'false' @@ -1003,7 +1003,7 @@ commands: summary: Delete a Supabase project tags: [] links: [] - usage: supabase projects delete + usage: supabase projects delete [ref] subcommands: [] flags: [] - id: supabase-projects-create @@ -3353,9 +3353,10 @@ commands: subcommands: - supabase-branches-create - supabase-branches-delete - - supabase-branches-disable - supabase-branches-get - supabase-branches-list + - supabase-branches-pause + - supabase-branches-unpause - supabase-branches-update flags: [] - id: supabase-branches-update @@ -3364,7 +3365,7 @@ commands: description: Update a preview branch by its name or ID. tags: [] links: [] - usage: supabase branches update [branch-id] [flags] + usage: supabase branches update [name] [flags] subcommands: [] flags: - id: git-branch @@ -3399,11 +3400,30 @@ commands: - id: FUNCTIONS_FAILED name: FUNCTIONS_FAILED type: string - - id: experimental - name: --experimental - description: enable experimental features - required: true - default_value: 'false' + - id: project-ref + name: --project-ref + description: Project ref of the Supabase project. + default_value: '' + - id: supabase-branches-unpause + title: supabase branches unpause + summary: Unpause a preview branch + tags: [] + links: [] + usage: supabase branches unpause [name] + subcommands: [] + flags: + - id: project-ref + name: --project-ref + description: Project ref of the Supabase project. + default_value: '' + - id: supabase-branches-pause + title: supabase branches pause + summary: Pause a preview branch + tags: [] + links: [] + usage: supabase branches pause [name] + subcommands: [] + flags: - id: project-ref name: --project-ref description: Project ref of the Supabase project. @@ -3417,11 +3437,6 @@ commands: usage: supabase branches list subcommands: [] flags: - - id: experimental - name: --experimental - description: enable experimental features - required: true - default_value: 'false' - id: project-ref name: --project-ref description: Project ref of the Supabase project. @@ -3432,32 +3447,9 @@ commands: description: Retrieve details of the specified preview branch. tags: [] links: [] - usage: supabase branches get [branch-id] - subcommands: [] - flags: - - id: experimental - name: --experimental - description: enable experimental features - required: true - default_value: 'false' - - id: project-ref - name: --project-ref - description: Project ref of the Supabase project. - default_value: '' - - id: supabase-branches-disable - title: supabase branches disable - summary: Disable preview branching - description: Disable preview branching for the linked project. - tags: [] - links: [] - usage: supabase branches disable + usage: supabase branches get [name] subcommands: [] flags: - - id: experimental - name: --experimental - description: enable experimental features - required: true - default_value: 'false' - id: project-ref name: --project-ref description: Project ref of the Supabase project. @@ -3468,14 +3460,9 @@ commands: description: Delete a preview branch by its name or ID. tags: [] links: [] - usage: supabase branches delete [branch-id] + usage: supabase branches delete [name] subcommands: [] flags: - - id: experimental - name: --experimental - description: enable experimental features - required: true - default_value: 'false' - id: project-ref name: --project-ref description: Project ref of the Supabase project. @@ -3606,11 +3593,6 @@ commands: name: --with-data description: Whether to clone production data to the branch database. default_value: 'false' - - id: experimental - name: --experimental - description: enable experimental features - required: true - default_value: 'false' - id: project-ref name: --project-ref description: Project ref of the Supabase project. diff --git a/apps/docs/spec/supabase_dart_v2.yml b/apps/docs/spec/supabase_dart_v2.yml index 8bfbbc93ecd04..2264e2544e164 100644 --- a/apps/docs/spec/supabase_dart_v2.yml +++ b/apps/docs/spec/supabase_dart_v2.yml @@ -859,7 +859,7 @@ functions: - id: verify-otp title: 'verifyOtp()' notes: | - - The `verifyOtp` method takes in different verification types. If a phone number is used, the type can either be `sms` or `phone_change`. If an email address is used, the type can be one of the following: `signup`, `magiclink`, `recovery`, `invite` or `email_change`. + - The `verifyOtp` method takes in different verification types. If a phone number is used, the type can either be `sms` or `phone_change`. If an email address is used, the type can be one of the following: `email`, `recovery`, `invite` or `email_change` (`signup` and `magiclink` types are deprecated). - The verification type used should be determined based on the corresponding auth method called before `verifyOtp` to sign up or sign in a user. params: - name: token diff --git a/apps/docs/spec/supabase_py_v2.yml b/apps/docs/spec/supabase_py_v2.yml index a19afdbd019c2..661cf1e884e8d 100644 --- a/apps/docs/spec/supabase_py_v2.yml +++ b/apps/docs/spec/supabase_py_v2.yml @@ -925,6 +925,74 @@ functions: {"provider_id": "21648a9d-8d5a-4555-a9d1-d6375dc14e92"} ) ``` + - id: get-claims + title: 'get_claims' + params: + - name: jwt + isOptional: true + type: string + description: An optional specific JWT you wish to verify, not the one you can obtain from [`get_session`](/docs/reference/python/auth-getsession). + - name: jwks + isOptional: true + type: JWKSet + description: If set, this JSON Web Key Set is going to have precedence over the cached value available on the server. + subContent: + - name: keys + isOptional: false + type: list + subContent: + - name: key_opt + isOptional: false + type: list[string] + - name: kty + isOptional: false + type: RSA | EC | oct + - name: alg + isOptional: false + type: string + - name: kid + isOptional: false + type: string + notes: | + Extracts the JWT claims present in the access token by first verifying the JWT against the server's JSON Web Key Set endpoint /.well-known/jwks.json which is often cached, resulting in significantly faster responses. Prefer this method over [`get_user`](/docs/reference/python/auth-getuser) which always sends a request to the Auth server for each JWT. + examples: + - id: get-user-object + name: Get user object + isSpotlight: true + code: | + ``` + response = supabase.auth.get_claims() + ``` + response: | + ```json + { + "claims": { + "aal": "aal1", + "amr": [{ + "method": "email", + "timestamp": 1715766000 + }], + "app_metadata": {}, + "aud": "authenticated", + "email": "example@email.com", + "exp": 1715769600, + "iat": 1715766000, + "is_anonymous": false, + "iss": "https://api.supabase.com/auth/v1", + "phone": "+13334445555", + "role": "authenticated", + "session_id": "11111111-1111-1111-1111-111111111111", + "sub": "11111111-1111-1111-1111-111111111111", + "user_metadata": {} + }, + "header": { + "alg": "RS256", + "typ": "JWT", + "kid": "abcdefgh" + }, + "signature": [/** Uint8Array */], + } + ``` - id: sign-out title: 'sign_out()' params: diff --git a/apps/studio/components/interfaces/Connect/content/remix/supabasejs/content.tsx b/apps/studio/components/interfaces/Connect/content/remix/supabasejs/content.tsx index cff2d98ecc41f..ac40753c886d2 100644 --- a/apps/studio/components/interfaces/Connect/content/remix/supabasejs/content.tsx +++ b/apps/studio/components/interfaces/Connect/content/remix/supabasejs/content.tsx @@ -21,10 +21,10 @@ const ContentFile = ({ projectKeys }: ContentFileProps) => { {[ '', - `SUPABASE_URL=${projectKeys.apiUrl ?? 'your-project-url'}`, + `VITE_SUPABASE_URL=${projectKeys.apiUrl ?? 'your-project-url'}`, projectKeys?.publishableKey - ? `SUPABASE_PUBLISHABLE_DEFAULT_KEY=${projectKeys.publishableKey}` - : `SUPABASE_ANON_KEY=${projectKeys.anonKey ?? 'your-anon-key'}`, + ? `VITE_SUPABASE_PUBLISHABLE_DEFAULT_KEY=${projectKeys.publishableKey}` + : `VITE_SUPABASE_ANON_KEY=${projectKeys.anonKey ?? 'your-anon-key'}`, '', ].join('\n')} @@ -33,32 +33,39 @@ const ContentFile = ({ projectKeys }: ContentFileProps) => { {` -import { createServerClient, serialize, parse } from "@supabase/ssr"; +import { + createServerClient, + parseCookieHeader, + serializeCookieHeader, +} from "@supabase/ssr"; export function createClient(request: Request) { - const cookies = parse(request.headers.get("Cookie") ?? ""); const headers = new Headers(); - const supabaseUrl = process.env.SUPABASE_URL; - const supabaseKey = process.env.${projectKeys.publishableKey ? 'SUPABASE_PUBLISHABLE_DEFAULT_KEY' : 'SUPABASE_ANON_KEY'}; - - return createServerClient( - supabaseUrl!, - supabaseKey!, + const supabase = createServerClient( + process.env.VITE_SUPABASE_URL!, + process.env.VITE_${projectKeys.publishableKey ? 'SUPABASE_PUBLISHABLE_DEFAULT_KEY' : 'SUPABASE_ANON_KEY'};, { cookies: { - get(key) { - return cookies[key]; - }, - set(key, value, options) { - headers.append("Set-Cookie", serialize(key, value, options)); + getAll() { + return parseCookieHeader(request.headers.get("Cookie") ?? "") as { + name: string; + value: string; + }[]; }, - remove(key, options) { - headers.append("Set-Cookie", serialize(key, "", options)); + setAll(cookiesToSet) { + cookiesToSet.forEach(({ name, value, options }) => + headers.append( + "Set-Cookie", + serializeCookieHeader(name, value, options) + ) + ); }, }, - }, + } ); + + return { supabase, headers }; } `} @@ -67,27 +74,28 @@ export function createClient(request: Request) { {` -import { LoaderFunctionArgs, json } from "@remix-run/node"; -import { useLoaderData } from "@remix-run/react"; +import type { Route } from "./+types/home"; import { createClient } from "~/utils/supabase.server"; -export async function loader({ request }: LoaderFunctionArgs) { - const supabase = createClient(request); - const { data: todos } = await supabase.from('todos').select() +export async function loader({ request }: Route.LoaderArgs) { + const { supabase } = createClient(request); + const { data: todos } = await supabase.from("todos").select(); - return { todos } + return { todos }; } -export default function Index() { - const { todos } = useLoaderData(); +export default function Home({ loaderData }: Route.ComponentProps) { return ( -
    - {todos.map((todo) => ( -
  • {todo.name}
  • - ))} -
+ <> +
    + {loaderData.todos?.map((todo) => ( +
  • {todo.name}
  • + ))} +
+ ); } + `}
diff --git a/apps/studio/components/layouts/Tabs/Tabs.utils.ts b/apps/studio/components/layouts/Tabs/Tabs.utils.ts index de63834fda01b..f67aea0045675 100644 --- a/apps/studio/components/layouts/Tabs/Tabs.utils.ts +++ b/apps/studio/components/layouts/Tabs/Tabs.utils.ts @@ -31,7 +31,7 @@ export function useTableEditorTabsCleanUp() { tabsFilteredToSchemas.push( ...openTabsRef.current.filter((tabId) => { const tab = tabMapRef.current[tabId] - return tab.metadata?.schema === schema + return tab?.metadata?.schema === schema }) ) }