diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 40167c5036e..f3b6f7dccd5 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -10,4 +10,10 @@
/apps/www/public/images/blog @supabase/marketing
/apps/www/lib/redirects.js
-/docker/ @supabase/cli
+/docker/ @supabase/dev-workflows
+
+/apps/studio/next.config.js @supabase/security
+/apps/studio/components/interfaces/Billing/Payment @supabase/security
+/apps/studio/components/interfaces/Organization/BillingSettings/ @supabase/security
+/apps/studio/components/interfaces/Organization/Documents/ @supabase/security
+/apps/studio/pages/new/index.tsx @supabase/security
\ No newline at end of file
diff --git a/.github/workflows/autofix_linters.yml b/.github/workflows/autofix_linters.yml
index fa02d5c9f8d..d181e750d80 100644
--- a/.github/workflows/autofix_linters.yml
+++ b/.github/workflows/autofix_linters.yml
@@ -18,10 +18,10 @@ jobs:
runs-on: ubuntu-latest
if: ${{ github.event_name == 'pull_request' && (github.event.label.name == 'autofix') }}
steps:
-
- uses: actions/checkout@v4
with:
sparse-checkout: apps
+ ref: ${{ github.head_ref }}
- uses: actions/setup-node@v4
with:
@@ -39,7 +39,7 @@ jobs:
git config --global user.email 'github-tidy-bot@supabase.com'
if [[ `git status --porcelain` ]]; then
echo "[bot] Changes detected, committing."
-
+
echo "[bot] Running in non-squash mode."
git commit -am "ci: Autofix updates from GitHub workflow"
git push
diff --git a/.github/workflows/config-preview.yaml b/.github/workflows/config-preview.yaml
deleted file mode 100644
index cca3c2d7de3..00000000000
--- a/.github/workflows/config-preview.yaml
+++ /dev/null
@@ -1,63 +0,0 @@
-name: Config (Preview)
-
-on:
- pull_request:
- types:
- - opened
- - reopened
- - synchronize
- branches:
- - master
- paths:
- - "supabase/**"
- workflow_dispatch:
-
-jobs:
- wait:
- runs-on: ubuntu-latest
- outputs:
- status: ${{ steps.check.outputs.conclusion }}
- steps:
- - uses: fountainhead/action-wait-for-check@v1.2.0
- id: check
- with:
- checkName: Supabase
- ref: ${{ github.event.pull_request.head.sha }}
- token: ${{ secrets.GITHUB_TOKEN }}
-
- apply:
- needs:
- - wait
- if: ${{ needs.wait.outputs.status == 'success' }}
- runs-on: ubuntu-latest
- env:
- SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
- TF_VAR_linked_project: xguihxuzqibwxjnimxev
- TF_VAR_git_branch: ${{ github.head_ref }}
- TF_CLI_ARGS_apply: -target=supabase_settings.preview
- defaults:
- run:
- working-directory: supabase/remotes
- outputs:
- db_user: ${{ steps.branch.outputs.user }}
- db_pass: ${{ steps.branch.outputs.password }}
- db_host: ${{ steps.branch.outputs.host }}
- db_port: ${{ steps.branch.outputs.port }}
- jwt_secret: ${{ steps.branch.outputs.jwt_secret }}
- ref: ${{ steps.branch.outputs.id }}
- status: ${{ steps.branch.outputs.status }}
- version: ${{ steps.branch.outputs.version }}
-
- steps:
- - uses: actions/checkout@v4
- - uses: hashicorp/setup-terraform@v3
- with:
- terraform_wrapper: false
-
- - run: terraform init
- - run: terraform apply -auto-approve -no-color
- - id: branch
- run: |
- terraform output -json branch_database \
- | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" \
- >> "$GITHUB_OUTPUT"
diff --git a/.github/workflows/config-production.yaml b/.github/workflows/config-production.yaml
deleted file mode 100644
index b7f3dd3d63c..00000000000
--- a/.github/workflows/config-production.yaml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Config (Production)
-
-on:
- push:
- branches:
- - master
- paths:
- - "supabase/remotes/**"
- workflow_dispatch:
-
-jobs:
- apply:
- runs-on: ubuntu-latest
- env:
- SUPABASE_ACCESS_TOKEN: ${{ secrets.SUPABASE_ACCESS_TOKEN }}
- TF_VAR_linked_project: xguihxuzqibwxjnimxev
- defaults:
- run:
- working-directory: supabase/remotes
-
- steps:
- - uses: actions/checkout@v4
- - uses: hashicorp/setup-terraform@v3
- with:
- terraform_wrapper: false
-
- - run: terraform init
- - run: terraform apply -auto-approve -no-color
diff --git a/apps/docs/app/api/ai/docs/route.ts b/apps/docs/app/api/ai/docs/route.ts
index 3b1df3ee2a7..b88d7837f82 100644
--- a/apps/docs/app/api/ai/docs/route.ts
+++ b/apps/docs/app/api/ai/docs/route.ts
@@ -6,7 +6,7 @@ import OpenAI from 'openai'
export const runtime = 'edge'
/* To avoid OpenAI errors, restrict to the Vercel Edge Function regions that
overlap with the OpenAI API regions.
-
+
Reference for Vercel regions: https://vercel.com/docs/edge-network/regions#region-list
Reference for OpenAI regions: https://help.openai.com/en/articles/5347006-openai-api-supported-countries-and-territories
*/
diff --git a/apps/docs/app/guides/(with-sidebar)/ai/python/[slug]/page.tsx b/apps/docs/app/guides/(with-sidebar)/ai/python/[slug]/page.tsx
index 578df9c3119..d6cc049c849 100644
--- a/apps/docs/app/guides/(with-sidebar)/ai/python/[slug]/page.tsx
+++ b/apps/docs/app/guides/(with-sidebar)/ai/python/[slug]/page.tsx
@@ -1,9 +1,9 @@
-import { type SerializeOptions } from 'next-mdx-remote/dist/types'
+import type { SerializeOptions } from 'next-mdx-remote/dist/types'
import { notFound } from 'next/navigation'
import { relative } from 'path'
import rehypeSlug from 'rehype-slug'
-import { genGuideMeta } from '~/features/docs/GuidesMdx.utils'
+import { genGuideMeta, removeRedundantH1 } from '~/features/docs/GuidesMdx.utils'
import { GuideTemplate, newEditLink } from '~/features/docs/GuidesMdx.template'
import { fetchRevalidatePerDay } from '~/features/helpers.fetch'
import { UrlTransformFunction, linkTransform } from '~/lib/mdx/plugins/rehypeLinkTransform'
@@ -84,7 +84,8 @@ const getContent = async ({ slug }: Params) => {
`https://raw.githubusercontent.com/${org}/${repo}/${branch}/${docsDir}/${remoteFile}`
)
- const content = await response.text()
+ let content = await response.text()
+ content = removeRedundantH1(content)
return {
pathname: `/guides/ai/python/${slug}` satisfies `/${string}`,
diff --git a/apps/docs/content/guides/auth/auth-email-templates.mdx b/apps/docs/content/guides/auth/auth-email-templates.mdx
index f185d2a5f90..265ffd32807 100644
--- a/apps/docs/content/guides/auth/auth-email-templates.mdx
+++ b/apps/docs/content/guides/auth/auth-email-templates.mdx
@@ -86,7 +86,7 @@ const {
## Customization
-Supabase Auth makes use of [Go Templates](https://pkg.go.dev/text/template). This means it is possible to conditionally render information based on template properties.You may wish to checkout this [guide by Hugo](https://gohugo.io/templates/introduction/) for a guide on the templating language.
+Supabase Auth makes use of [Go Templates](https://pkg.go.dev/text/template). This means it is possible to conditionally render information based on template properties.
### Send different email to early access users
diff --git a/apps/docs/content/guides/auth/auth-hooks.mdx b/apps/docs/content/guides/auth/auth-hooks.mdx
index cee056a29f6..9d35a938a5e 100644
--- a/apps/docs/content/guides/auth/auth-hooks.mdx
+++ b/apps/docs/content/guides/auth/auth-hooks.mdx
@@ -241,7 +241,7 @@ secrets = "env(SEND_SMS_HOOK_SECRET)"
Fill in the Hook Secret in `supabase/functions/.env`
```bash
-SEND_SMS_HOOK_SECRETS='v1,whsec_'
+SEND_SMS_HOOK_SECRET='v1,whsec_'
```
Start the function locally:
diff --git a/apps/docs/content/guides/auth/enterprise-sso/auth-sso-saml.mdx b/apps/docs/content/guides/auth/enterprise-sso/auth-sso-saml.mdx
index 59a5c388ae4..7e41fc0adb1 100644
--- a/apps/docs/content/guides/auth/enterprise-sso/auth-sso-saml.mdx
+++ b/apps/docs/content/guides/auth/enterprise-sso/auth-sso-saml.mdx
@@ -421,3 +421,47 @@ If you really need access to the key, please [open a support ticket](https://sup
Yes, Supabase supports multi-tenant Single Sign-On (SSO) using SAML 2.0. While the dashboard displays only one SAML field, you can set up multiple SAML connections using the Supabase CLI.
Each connection is assigned a unique `sso_provider_id`, which is included in the user's JWT and can be used in Row Level Security (RLS) policies. You can configure custom attribute mappings for each connection to include tenant-specific information, such as roles.
This setup allows you to implement multi-tenant SSO for multiple clients or organizations within a single application. For example, if you have an app with multiple clients using different Azure Active Directories, you can create separate SAML connections for each and use the `sso_provider_id` to manage access and apply appropriate security policies.
+
+### Is multi-subdomain SSO with SAML supported?
+
+Yes, also referred to as [cross-origin authentication within the same site](https://web.dev/articles/same-site-same-origin). To redirect to a URL other than the [Site URL](https://supabase.com/docs/guides/auth/redirect-urls), following the SAML response from the IdP, the `redirectTo` option can be added to [`signInWithSSO`](https://supabase.com/docs/reference/javascript/auth-signinwithsso).
+
+```ts
+ const { data, error } = await supabase.auth.signInWithSSO({
+ domain: 'company.com'
+ options: {
+ redirectTo: `https://app.company.com/callback`,
+ },
+ })
+```
+
+When redirecting to a URL other than the Site URL, a `/callback` endpoint is necessary to process the auth code from the IdP and exchange it for a session. This assumes the [Supabase SSR client](https://supabase.com/docs/guides/auth/server-side/creating-a-client) has already been configured.
+
+
+
+
+
+```ts
+import { error, redirect } from '@sveltejs/kit'
+import type { RequestHandler } from './$types'
+
+export const GET: RequestHandler = async ({ url, locals }) => {
+ const code = url.searchParams.get('code')
+
+ if (!code) {
+ error(400, 'No authorization code provided')
+ }
+
+ const { error: tokenExchangeError } = await locals.supabase.auth.exchangeCodeForSession(code)
+
+ if (tokenExchangeError) {
+ error(400, 'Failed to exchange authorization code for session')
+ }
+
+ redirect(303, '/')
+}
+```
+
+
+
+
diff --git a/apps/docs/content/guides/auth/passwords.mdx b/apps/docs/content/guides/auth/passwords.mdx
index 892c127e233..25ffbaea936 100644
--- a/apps/docs/content/guides/auth/passwords.mdx
+++ b/apps/docs/content/guides/auth/passwords.mdx
@@ -142,7 +142,7 @@ The PKCE flow allows for server-side authentication. Unlike the implicit flow, w
##### Step 1: Update signup confirmation email
-Update your signup email template to send the token hash. See [Email Templates](/docs/guides/auth/auth-email-templates) for how to configure your email templates.
+Update your signup email template to send the token hash. For detailed instructions on how to configure your email templates, including the use of variables like `{{ .SiteURL }}`, `{{ .TokenHash }}`, and `{{ .RedirectTo }}`, please refer to our [Email Templates](/docs/guides/auth/auth-email-templates) guide.
Your signup email template should contain the following HTML:
@@ -151,7 +151,8 @@ Your signup email template should contain the following HTML:
@@ -170,18 +171,16 @@ Create a new file at `app/auth/confirm/route.ts` and populate with the following
```ts app/auth/confirm/route.ts
import { type EmailOtpType } from '@supabase/supabase-js'
-import { cookies } from 'next/headers'
-import { NextRequest, NextResponse } from 'next/server'
-// The client you created from the Server-Side Auth instructions
+import { type NextRequest } from 'next/server'
+
import { createClient } from '@/utils/supabase/server'
+import { redirect } from 'next/navigation'
export async function GET(request: NextRequest) {
const { searchParams } = new URL(request.url)
const token_hash = searchParams.get('token_hash')
const type = searchParams.get('type') as EmailOtpType | null
const next = searchParams.get('next') ?? '/'
- const redirectTo = request.nextUrl.clone()
- redirectTo.pathname = next
if (token_hash && type) {
const supabase = await createClient()
@@ -191,13 +190,13 @@ export async function GET(request: NextRequest) {
token_hash,
})
if (!error) {
- return NextResponse.redirect(redirectTo)
+ // redirect user to specified redirect URL or root of app
+ redirect(next)
}
}
- // return the user to an error page with some instructions
- redirectTo.pathname = '/auth/auth-code-error'
- return NextResponse.redirect(redirectTo)
+ // redirect the user to an error page with some instructions
+ redirect('/auth/auth-code-error')
}
```
@@ -381,11 +380,18 @@ app.get("/auth/confirm", async function (req, res) {
To sign up the user, call [signUp()](/docs/reference/javascript/auth-signup) with their email address and password:
+You can optionally specify a URL to redirect to after the user clicks the confirmation link. This URL must be configured as a [Redirect URL](/docs/guides/auth/redirect-urls), which you can do in the [dashboard](/dashboard/project/_/auth/url-configuration) for hosted projects, or in the [configuration file](/docs/guides/cli/config#auth.additional_redirect_urls) for self-hosted projects.
+
+If you don't specify a redirect URL, the user is automatically redirected to your site URL. This defaults to `localhost:3000`, but you can also configure this.
+
```js
async function signUpNewUser() {
const { data, error } = await supabase.auth.signUp({
email: 'example@email.com',
password: 'example-password',
+ options: {
+ emailRedirectTo: 'https://example.com/welcome',
+ },
})
}
```
diff --git a/apps/docs/content/guides/auth/quickstarts/react-native.mdx b/apps/docs/content/guides/auth/quickstarts/react-native.mdx
index 4a0176049f3..220a8db979a 100644
--- a/apps/docs/content/guides/auth/quickstarts/react-native.mdx
+++ b/apps/docs/content/guides/auth/quickstarts/react-native.mdx
@@ -219,7 +219,6 @@ hideToc: true
import { useState, useEffect } from 'react'
import { supabase } from './lib/supabase'
import Auth from './components/Auth'
- import Account from './components/Account'
import { View, Text } from 'react-native'
import { Session } from '@supabase/supabase-js'
diff --git a/apps/docs/content/guides/auth/social-login/auth-apple.mdx b/apps/docs/content/guides/auth/social-login/auth-apple.mdx
index df5ba7c745b..5463db69e7d 100644
--- a/apps/docs/content/guides/auth/social-login/auth-apple.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-apple.mdx
@@ -111,7 +111,7 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
1. Have an **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple for the App ID you created or already have, in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._)
2. Obtain a **Services ID** attached to the App ID that uniquely identifies the website. Use this value as the client ID when initializing Sign in with Apple JS. You can create a new Services ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/serviceId) section in the Apple Developer Console (use the filter menu in the upper right side to see all Services IDs). These usually are a reverse domain name string, for example `com.example.app.website`.
3. Configure Website URLs for the newly created **Services ID**. The web domain you should use is the domain your website is hosted on. The redirect URL must also point to a page on your website that will receive the callback from Apple.
- 4. Register the Services ID you created to your project's [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Authorized Client IDs_.
+ 4. Register the Services ID you created to your project's [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Client IDs_.
If you're using Sign in with Apple JS you do not need to configure the OAuth settings.
@@ -184,12 +184,12 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
- When testing with Expo Go, the Expo App ID `host.exp.Exponent` will be used. Make sure to add this to the "Authorized Client IDs" list in your [Supabase dashboard Apple provider configuration](https://supabase.com/dashboard/project/_/auth/providers)!
+ When testing with Expo Go, the Expo App ID `host.exp.Exponent` will be used. Make sure to add this to the "Client IDs" list in your [Supabase dashboard Apple provider configuration](https://supabase.com/dashboard/project/_/auth/providers)!
1. Have an **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple for the App ID you created or already have, in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._)
- 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Authorized Client IDs_.
+ 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Client IDs_.
@@ -243,7 +243,7 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
### Configuration [#flutter-configuration-native-app]
1. Have an **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple for the App ID you created or already have, in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._)
- 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Authorized Client IDs_.
+ 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Client IDs_.
## Apple sign in on Android, Web, Windows and Linux
@@ -339,7 +339,7 @@ When developing with Expo, you can test Sign in with Apple via the Expo Go app,
### Configuration [#swift-configuration-native-app]
1. Have an **App ID** which uniquely identifies the app you are building. You can create a new App ID from the [Identifiers](https://developer.apple.com/account/resources/identifiers/list/bundleId) section in the Apple Developer Console (use the filter menu in the upper right side to see all App IDs). These usually are a reverse domain name string, for example `com.example.app`. Make sure you configure Sign in with Apple for the App ID you created or already have, in the Capabilities list. At this time Supabase Auth does not support Server-to-Server notification endpoints, so you should leave that setting blank. (In the past App IDs were referred to as _bundle IDs._)
- 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Authorized Client IDs_.
+ 2. Register all of the App IDs that will be using your Supabase project in the [Apple provider configuration in the Supabase dashboard](https://supabase.com/dashboard/project/_/auth/providers) under _Client IDs_.
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 d7500402e8b..11b24c66efd 100644
--- a/apps/docs/content/guides/auth/social-login/auth-google.mdx
+++ b/apps/docs/content/guides/auth/social-login/auth-google.mdx
@@ -69,7 +69,7 @@ To use Google's pre-built signin buttons:
1. Click `Create credentials` and choose `OAuth Client ID`.
1. For application type, choose `Web application`.
1. Under **Authorized JavaScript origins** and **Authorized redirect URLs**, add your site URL. This is the URL of the website where the signin button will appear, _not_ your Supabase project domain. If you're testing in localhost, ensure that you have `http://localhost` set in the **Authorized JavaScript origins** section as well. This is important when integrating with Google One-Tap to ensure you can use it locally.
-1. When you finish configuring your credentials, you will be shown your client ID. Add this to the **Authorized Client IDs** field in the [Google Auth Provider section of the Supabase Dashboard](/dashboard/project/_/auth/providers). Leave the OAuth client ID and secret blank. You don't need them when using Google's pre-built approach.
+1. When you finish configuring your credentials, you will be shown your client ID. Add this to the **Client IDs** field in the [Google Auth Provider section of the Supabase Dashboard](/dashboard/project/_/auth/providers). Leave the OAuth client ID and secret blank. You don't need them when using Google's pre-built approach.
@@ -80,7 +80,7 @@ To use Google's pre-built signin buttons:
- You will have a different set of SHA-1 certificate fingerprint for testing locally and going to production. Make sure to add both to the Google Cloud Console. and add all of the Client IDs to Supabase dashboard.
- For iOS, use the instructions on screen to provide the app Bundle ID, and App Store ID and Team ID if the app is already published on the Apple AppStore.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
- 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
+ 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_.
Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in.
@@ -96,7 +96,7 @@ To use Google's pre-built signin buttons:
- You will have a different set of SHA-1 certificate fingerprint for testing locally and going to production. Make sure to add both to the Google Cloud Console. and add all of the Client IDs to Supabase dashboard.
- For iOS, use the instructions on screen to provide the app Bundle ID, and App Store ID and Team ID if the app is already published on the Apple AppStore.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
- 3. Add only the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_. If you need iOS support, enable the `Skip nonce check` option.
+ 3. Add only the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_. If you need iOS support, enable the `Skip nonce check` option.
4. For iOS, add the `CFBundleURLTypes` attributes below into the `/ios/Runner/Info.plist` file.
```xml
@@ -168,7 +168,7 @@ To use Google's pre-built signin buttons:
1. Follow the integration instructions on the [get started with Google Sign-In](https://developers.google.com/identity/sign-in/ios/start-integrating) for iOS guide.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
- 3. Add only the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_. Enable the `Skip nonce check` option.
+ 3. Add only the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_. Enable the `Skip nonce check` option.
@@ -178,7 +178,7 @@ To use Google's pre-built signin buttons:
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. You need two client IDs, a web client ID and Android client ID. When creating a new Android OAuth client ID, use the instructions on screen to provide the SHA-1 certificate fingerprint used to sign your Android app.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
- 3. Finally, add the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
+ 3. Finally, add the web client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_.
Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in.
@@ -190,7 +190,7 @@ To use Google's pre-built signin buttons:
- For iOS, use the instructions on screen to provide the app Bundle ID, and App Store ID and Team ID if the app is already published on the Apple AppStore.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app. In particular, make sure you have set up links to your app's privacy policy and terms of service.
- 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
+ 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_.
Note that you do not have to configure the OAuth flow in the Supabase Dashboard in order to use native sign in.
@@ -202,7 +202,7 @@ To use Google's pre-built signin buttons:
1. Configure OAuth credentials for your Google Cloud project in the [Credentials](https://console.cloud.google.com/apis/credentials) page of the console. When creating a new OAuth client ID, choose _Chrome extension_ for the application type. For _Item ID_ provide the unique ID of your Chrome extension. You can get this by calling `chrome.runtime.id` within the extension, or from the Web Store URL of the extension. For example, the [Google Translate extension](https://chrome.google.com/webstore/detail/google-translate/aapbdbdomjkkjkaonfhkkikfgjllcleb) has the Web Store URL `https://chrome.google.com/webstore/detail/google-translate/aapbdbdomjkkjkaonfhkkikfgjllcleb` and the last part `aapbdbdomjkkjkaonfhkkikfgjllcleb` is its unique ID.
2. Configure the [OAuth Consent Screen](https://console.cloud.google.com/apis/credentials/consent). This information is shown to the user when giving consent to your app.
- 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Authorized Client IDs_.
+ 3. Finally, add the client ID from step 1 in the [Google provider on the Supabase Dashboard](https://supabase.com/dashboard/project/_/auth/providers), under _Client IDs_.
Note that you do not have to configure the OAuth flow in the Supabase Dashboard to sign in with Google inside Chrome extensions.
@@ -439,6 +439,8 @@ Unlike the OAuth flow which requires the use of a web browser, the native Sign i
When the user provides consent, Google issues an identity token (commonly abbreviated as ID token) that is then sent to your project's Supabase Auth server. When valid, a new user session is started by issuing an access and refresh token from Supabase Auth.
+By default, Supabase Auth implements nonce validation during the authentication flow. This can be disabled in production under `Authentication > Providers > Google > Skip Nonce Check` in the Dashboard, or when developing locally by setting `auth.external..skip_nonce_check`. Only disable this if your client libraries cannot properly handle nonce verification.
+
When working with Expo, you can use the [`react-native-google-signin/google-signin` library](https://github.com/react-native-google-signin/google-signin#expo-installation) library to obtain an ID token that you can pass to supabase-js [`signInWithIdToken` method](/docs/reference/javascript/auth-signinwithidtoken).
Follow the [Expo installation docs](https://react-native-google-signin.github.io/docs/setting-up/expo) for installation and configuration instructions. See the [supabase-js reference](/docs/reference/javascript/initializing?example=react-native-options-async-storage) for instructions on initializing the supabase-js client in React Native.
diff --git a/apps/docs/content/guides/database/custom-postgres-config.mdx b/apps/docs/content/guides/database/custom-postgres-config.mdx
index 599f37e9810..59a41642bdd 100644
--- a/apps/docs/content/guides/database/custom-postgres-config.mdx
+++ b/apps/docs/content/guides/database/custom-postgres-config.mdx
@@ -53,6 +53,8 @@ Some settings can only be modified by a superuser. Supabase pre-enables the [`su
| `auto_explain.log_min_duration` | Logs query plans taking longer than this duration. |
| `auto_explain.log_nested_statements` | Log nested statements' plans. |
| `log_min_messages` | Minimum severity level of messages to log. |
+| `pg_net.ttl` | Sets how long the [pg_net extension](/docs/guides/database/extensions/pg_net) saves responses |
+| `pg_net.batch_size` | Sets how many requests the [pg_net extension](/docs/guides/database/extensions/pg_net) can make per second |
| `pgaudit.*` | Configures the [PGAudit extension](https://supabase.com/docs/guides/database/extensions/pgaudit). The `log_parameter` is still restricted to protect secrets |
| `pgrst.*` | [`PostgREST` settings](https://docs.postgrest.org/en/stable/references/configuration.html#db-aggregates-enabled) |
| `plan_filter.*` | Configures the [pg_plan_filter extension](https://supabase.com/docs/guides/database/extensions/pg_plan_filter) |
diff --git a/apps/docs/content/guides/database/extensions/pgsodium.mdx b/apps/docs/content/guides/database/extensions/pgsodium.mdx
index dbddf13b51f..5c3a9d4c92b 100644
--- a/apps/docs/content/guides/database/extensions/pgsodium.mdx
+++ b/apps/docs/content/guides/database/extensions/pgsodium.mdx
@@ -8,6 +8,12 @@ Supabase DOES NOT RECOMMEND any new usage of [`pgsodium`](https://github.com/mic
The [`pgsodium`](https://github.com/michelp/pgsodium) extension is expected to go through a deprecation cycle in the near future. We will reach out to owners of impacted projects to assist with migrations away from [`pgsodium`](https://github.com/michelp/pgsodium) once the deprecation process begins.
+
+
+The [Vault extension](/docs/guides/database/vault) won’t be impacted. Its internal implementation will shift away from pgsodium, but the interface and API will remain unchanged.
+
+
+
[`pgsodium`](https://github.com/michelp/pgsodium) is a Postgres extension which provides SQL access to [`libsodium`'s](https://doc.libsodium.org/) high-level cryptographic algorithms.
Supabase previously documented two features derived from pgsodium. Namely [Server Key Management](https://github.com/michelp/pgsodium#server-key-management) and [Transparent Column Encryption](https://github.com/michelp/pgsodium#transparent-column-encryption). At this time, we do not recommend using either on the Supabase platform due to their high level of operational complexity and misconfiguration risk.
diff --git a/apps/docs/content/guides/database/extensions/pgvector.mdx b/apps/docs/content/guides/database/extensions/pgvector.mdx
index b320a7e23a5..c505abe6991 100644
--- a/apps/docs/content/guides/database/extensions/pgvector.mdx
+++ b/apps/docs/content/guides/database/extensions/pgvector.mdx
@@ -102,6 +102,20 @@ const { data, error } = await supabase.from('posts').insert({
})
```
+## Specific usage cases
+
+### Queries with filtering
+
+If you use an IVFFlat or HNSW index and naively filter the results based on the value of another column, you may get fewer rows returned than requested.
+
+For example, the following query may return fewer than 5 rows, even if 5 corresponding rows exist in the database. This is because the embedding index may not return 5 rows matching the filter.
+
+```
+SELECT * FROM items WHERE category_id = 123 ORDER BY embedding <-> '[3,1,2]' LIMIT 5;
+```
+
+To get the exact number of requested rows, use [iterative search](https://github.com/pgvector/pgvector/?tab=readme-ov-file#iterative-index-scans) to continue scanning the index until enough results are found.
+
## More pgvector and Supabase resources
- [Supabase Clippy: ChatGPT for Supabase Docs](https://supabase.com/blog/chatgpt-supabase-docs)
diff --git a/apps/docs/content/guides/database/extensions/postgis.mdx b/apps/docs/content/guides/database/extensions/postgis.mdx
index 9c470366db1..72b85b09aff 100644
--- a/apps/docs/content/guides/database/extensions/postgis.mdx
+++ b/apps/docs/content/guides/database/extensions/postgis.mdx
@@ -58,7 +58,7 @@ Let’s create our table. Each row represents a restaurant with its location sto
create table if not exists public.restaurants (
id int generated by default as identity primary key,
name text not null,
- location geography(POINT) not null
+ location gis.geography(POINT) not null
);
```
diff --git a/apps/docs/content/guides/database/webhooks.mdx b/apps/docs/content/guides/database/webhooks.mdx
index 28297118008..93a17de9ed5 100644
--- a/apps/docs/content/guides/database/webhooks.mdx
+++ b/apps/docs/content/guides/database/webhooks.mdx
@@ -27,7 +27,7 @@ This video demonstrates how you can create a new customer in Stripe each time a
## Creating a webhook
-1. Create a new [Database Webhook](https://supabase.com/dashboard/project/_/database/hooks) in the Dashboard.
+1. Create a new [Database Webhook](https://supabase.com/dashboard/project/_/integrations/hooks) in the Dashboard.
1. Give your Webhook a name.
1. Select the table you want to hook into.
1. Select one or more events (table inserts, updates, or deletes) you want to hook into.
diff --git a/apps/docs/content/guides/functions/background-tasks.mdx b/apps/docs/content/guides/functions/background-tasks.mdx
index 2ad76d7028d..fbc1f2aebf8 100644
--- a/apps/docs/content/guides/functions/background-tasks.mdx
+++ b/apps/docs/content/guides/functions/background-tasks.mdx
@@ -3,27 +3,32 @@ id: 'function-background-tasks'
title: 'Background Tasks'
description: 'How to run background tasks in an Edge Function outside of the request handler'
subtitle: 'How to run background tasks in an Edge Function outside of the request handler'
+tocVideo: 'rSKBTJxG9VA'
---
Edge Function instances can process background tasks outside of the request handler. Background tasks are useful for asynchronous operations like uploading a file to Storage, updating a database, or sending events to a logging service. You can respond to the request immediately and leave the task running in the background.
-A background task can run until the Edge Function instance hits its [wall-clock limit](/docs/guides/functions/limits).
+### How long a background task can run
+
+A background task can run until the Edge Function instance hits its wall-clock limit or reaches CPU/Memory limit. Check [limits](/docs/guides/functions/limits) for current caps.
+
+### Example
Here's an example of defining a background task using a custom event.
```ts
-// define a custom event
+// Define a custom event type for the background task.
class MyBackgroundTaskEvent extends Event {
- readonly taskPromise: Promise
+ readonly taskPromise: Promise
- constructor(taskPromise) {
+ constructor(taskPromise: Promise) {
super('myBackgroundTask')
this.taskPromise = taskPromise
}
}
-globalThis.addEventListener('myBackgroundTask', async (event: MyBackgroundTaskEvent) => {
- const res = await event.taskPromise
+globalThis.addEventListener('myBackgroundTask', async (event) => {
+ const res = await (event as MyBackgroundTaskEvent).taskPromise
console.log(await res.json())
})
diff --git a/apps/docs/content/guides/functions/connect-to-postgres.mdx b/apps/docs/content/guides/functions/connect-to-postgres.mdx
index 12478874d5c..22b0ada259b 100644
--- a/apps/docs/content/guides/functions/connect-to-postgres.mdx
+++ b/apps/docs/content/guides/functions/connect-to-postgres.mdx
@@ -16,7 +16,7 @@ The `supabase-js` client is a great option for connecting to your Supabase datab
```ts index.ts
import { createClient } from 'jsr:@supabase/supabase-js@2'
-Deno.serve(async (_req) => {
+Deno.serve(async (req) => {
try {
const supabase = createClient(
Deno.env.get('SUPABASE_URL') ?? '',
diff --git a/apps/docs/content/guides/functions/examples/github-actions.mdx b/apps/docs/content/guides/functions/examples/github-actions.mdx
index 3298913f089..5b665d8f4c8 100644
--- a/apps/docs/content/guides/functions/examples/github-actions.mdx
+++ b/apps/docs/content/guides/functions/examples/github-actions.mdx
@@ -34,7 +34,7 @@ jobs:
PROJECT_ID: YOUR_SUPABASE_PROJECT_ID
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: supabase/setup-cli@v1
with:
diff --git a/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx b/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx
index 1b11196eaeb..88b705e3f90 100644
--- a/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx
+++ b/apps/docs/content/guides/getting-started/quickstarts/nextjs.mdx
@@ -9,53 +9,7 @@ hideToc: true
-
-
- Go to [database.new](https://database.new) and create a new Supabase project.
-
- When your project is up and running, go to the [Table Editor](https://supabase.com/dashboard/project/_/editor), create a new table and insert some 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.
-
-
-
-
-
- ```sql SQL_EDITOR
- -- Create the table
- create table notes (
- id bigint primary key generated always as identity,
- title text not null
- );
-
- -- Insert some sample data into the table
- insert into notes (title)
- values
- ('Today I created a Supabase project.'),
- ('I added some data and queried it from Next.js.'),
- ('It was awesome!');
-
- alter table notes enable row level security;
- ```
-
-
-
-
-
- Make the data in your table publicly readable by adding an RLS policy:
-
-
-
-
-
- ```sql SQL_EDITOR
- create policy "public can read notes"
- on public.notes
- for select to anon
- using (true);
- ```
-
-
+
@@ -104,9 +58,9 @@ hideToc: true
- Create a new file at `app/notes/page.tsx` and populate with the following.
+ Create a new file at `app/countries/page.tsx` and populate with the following.
- This will select all the rows from the `notes` table in Supabase and render them on the page.
+ This will select all the rows from the `countries` table in Supabase and render them on the page.
@@ -114,14 +68,14 @@ hideToc: true
- ```ts app/notes/page.tsx
+ ```ts app/countries/page.tsx
import { createClient } from '@/utils/supabase/server';
- export default async function Notes() {
+ export default async function Countries() {
const supabase = await createClient();
- const { data: notes } = await supabase.from("notes").select();
+ const { data: countries } = await supabase.from("countries").select();
- return
{JSON.stringify(notes, null, 2)}
+ return
{JSON.stringify(countries, null, 2)}
}
```
@@ -166,7 +120,7 @@ hideToc: true
- Run the development server, go to http://localhost:3000/notes in a browser and you should see the list of notes.
+ Run the development server, go to http://localhost:3000/countries in a browser and you should see the list of countries.
diff --git a/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx b/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx
index bcb65aca897..c78cc43a9b1 100644
--- a/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx
+++ b/apps/docs/content/guides/getting-started/quickstarts/sveltekit.mdx
@@ -24,7 +24,7 @@ hideToc: true
```bash Terminal
- npm create svelte@latest myapp
+ npx sv create my-app
```
@@ -43,7 +43,7 @@ hideToc: true
```bash Terminal
- cd myapp && npm install @supabase/supabase-js
+ cd my-app && npm install @supabase/supabase-js
```
@@ -53,7 +53,7 @@ hideToc: true
- Create a `/src/lib` directory in your SvelteKit app, create a file called `supabaseClient.js` and add the following code to initialize the Supabase client with your project URL and public API (anon) key:
+ Create a `src/lib` directory in your SvelteKit app, create a file called `supabaseClient.js` and add the following code to initialize the Supabase client with your project URL and public API (anon) key:
@@ -77,7 +77,7 @@ hideToc: true
Use `load` method to fetch the data server-side and display the query results as a simple list.
- Create `+page.server.js` file in the `routes` directory with the following code.
+ Create `+page.server.js` file in the `src/routes` directory with the following code.
@@ -98,7 +98,7 @@ hideToc: true
- Replace the existing content in your `+page.svelte` file in the `routes` directory with the following code.
+ Replace the existing content in your `+page.svelte` file in the `src/routes` directory with the following code.
diff --git a/apps/docs/content/guides/getting-started/tutorials/with-expo-react-native.mdx b/apps/docs/content/guides/getting-started/tutorials/with-expo-react-native.mdx
index a86e882cd3c..63a270a0ecb 100644
--- a/apps/docs/content/guides/getting-started/tutorials/with-expo-react-native.mdx
+++ b/apps/docs/content/guides/getting-started/tutorials/with-expo-react-native.mdx
@@ -40,7 +40,7 @@ npx expo install @supabase/supabase-js @react-native-async-storage/async-storage
Now let's create a helper file to initialize the Supabase client.
We need the API URL and the `anon` key that you copied [earlier](#get-the-api-keys).
These variables are safe to expose in your Expo app since Supabase has
-[Row Level Security](/docs/guides/auth#row-level-security) enabled on your Database.
+[Row Level Security](/docs/guides/database/postgres/row-level-security) enabled on your Database.
**Project** | | | | | |
| Project Management | Transfer | | | | |
@@ -188,7 +188,7 @@ The table below shows the actions each role can take on the resources belonging
| | Delete | | | | |
| | View | | | | |
| | List | | | | |
-| | Run | | | | [^5] |
+| | Run | | | | [^6] |
| **Database** | | | | | |
| Scheduled Backups | View | | | | |
| | Download | | | | |
@@ -261,4 +261,5 @@ The table below shows the actions each role can take on the resources belonging
[^2]: Invites sent from a SSO account can only be accepted by another SSO account coming from the same identity provider. This is a security measure that prevents accidental invites to accounts not managed by your company's enterprise systems.
[^3]: Available on the Enterprise Plan.
[^4]: Read-Only role is able to access secrets.
-[^5]: Limited to executing SELECT queries.
+[^5]: Listed permissions are for the API and Dashboard.
+[^6]: Limited to executing SELECT queries. SQL Query Snippets run by the Read-Only role are run against the database using the **supabase_read_only_user**. This role has the [predefined Postgres role pg_read_all_data](https://www.postgresql.org/docs/current/predefined-roles.html).
diff --git a/apps/docs/content/guides/platform/database-size.mdx b/apps/docs/content/guides/platform/database-size.mdx
index 3ddc6cb224c..bb9174b5f9f 100644
--- a/apps/docs/content/guides/platform/database-size.mdx
+++ b/apps/docs/content/guides/platform/database-size.mdx
@@ -16,7 +16,7 @@ This SQL query will show the size of all databases in your Postgres cluster:
```sql
select
- sum(pg_database_size(pg_database.datname)) / (1024 * 1024) as db_size_mb
+ pg_size_pretty(sum(pg_database_size(pg_database.datname)))
from pg_database;
```
@@ -30,6 +30,16 @@ Depending on your billing plan, your database can go into read-only mode which c
+### Disk space usage
+
+Your database size is part of the disk usage for your Supabase project, there are many components to Postgres that consume additional disk space. One of the primary components, is the [Write Ahead Log (WAL)](https://www.postgresql.org/docs/current/wal-intro.html). Postgres will store database changes in log files that are cleared away after they are applied to the database. These same files are also used by [Read Replicas](/docs/guides/platform/read-replicas) or other replication methods.
+
+If you would like to determine the size of the WAL files stored on disk, Postgres provides `pg_ls_waldir` as a helper function; the following query can be run:
+
+```sql
+select pg_size_pretty(sum(size)) as wal_size from pg_ls_waldir();
+```
+
### Vacuum operations
Postgres does not immediately reclaim the physical space used by dead tuples (i.e., deleted rows) in the DB. They are marked as "removed" until a [vacuum operation](https://www.postgresql.org/docs/current/routine-vacuuming.html) is executed. As a result, deleting data from your database may not immediately reduce the reported disk usage. You can use the [Supabase CLI](https://supabase.com/docs/guides/cli/getting-started) `inspect db bloat` command to view all dead tuples in your database. Alternatively, you can run the [query](https://github.com/supabase/cli/blob/c9cce58025fded16b4c332747f819a44f45c3b83/internal/inspect/bloat/bloat.go#L17) found in the CLI's GitHub repo in the [SQL Editor](https://supabase.com/dashboard/project/_/sql/)
diff --git a/apps/docs/content/guides/platform/ipv4-address.mdx b/apps/docs/content/guides/platform/ipv4-address.mdx
index bae6317423f..7a3988ca1b9 100644
--- a/apps/docs/content/guides/platform/ipv4-address.mdx
+++ b/apps/docs/content/guides/platform/ipv4-address.mdx
@@ -1,5 +1,5 @@
---
-title: 'Dedicated IPv4 Address'
+title: 'Dedicated IPv4 Address for Ingress'
description: 'Attach an IPv4 address to your database'
subtitle: 'Attach an IPv4 address to your database'
---
@@ -15,6 +15,12 @@ The Internet Protocol (IP) addresses devices on the internet. There are two main
## When you need the IPv4 add-on:
+
+
+IPv4 addresses are guaranteed to be static for ingress traffic. If your database is making outbound connections, the outbound IP address is not static and cannot be guaranteed.
+
+
+
- When using the direct connection string in an IPv6-incompatible network instead of Supavisor or client libraries.
- When you need a dedicated IP address for your direct connection string
diff --git a/apps/docs/content/guides/platform/upgrading.mdx b/apps/docs/content/guides/platform/upgrading.mdx
index aef800a9d67..1bdab44de90 100644
--- a/apps/docs/content/guides/platform/upgrading.mdx
+++ b/apps/docs/content/guides/platform/upgrading.mdx
@@ -22,6 +22,11 @@ This upgrade method is currently in Beta.
+
+ For security purposes, passwords for custom roles are not backed up and, following a restore, they
+ would need to be reset. See [here](/docs/guides/platform/backups#daily-backups) for more details
+
+
pg_upgrade performs an in-place upgrade on your database. For projects larger than 1GB, pg_upgrade is generally faster than a pause+restore cycle, and the speed advantage grows with the size of the database.
1. Plan for an appropriate downtime window, and ensure you have reviewed the [caveats](#caveats) section of this document before executing the upgrade.
diff --git a/apps/docs/spec/api_v1_openapi.json b/apps/docs/spec/api_v1_openapi.json
index f7387e4701c..75df6edc0d6 100644
--- a/apps/docs/spec/api_v1_openapi.json
+++ b/apps/docs/spec/api_v1_openapi.json
@@ -1540,6 +1540,7 @@
}
}
},
+ "403": { "description": "" },
"500": { "description": "Failed to retrieve project's service health status" }
},
"tags": ["Projects"],
@@ -3461,6 +3462,7 @@
"max_worker_processes": { "type": "integer", "minimum": 0, "maximum": 262143 },
"shared_buffers": { "type": "string" },
"statement_timeout": { "type": "string" },
+ "track_commit_timestamp": { "type": "boolean" },
"wal_keep_size": { "type": "string" },
"wal_sender_timeout": { "type": "string" },
"work_mem": { "type": "string" },
@@ -3487,6 +3489,7 @@
"max_worker_processes": { "type": "integer", "minimum": 0, "maximum": 262143 },
"shared_buffers": { "type": "string" },
"statement_timeout": { "type": "string" },
+ "track_commit_timestamp": { "type": "boolean" },
"wal_keep_size": { "type": "string" },
"wal_sender_timeout": { "type": "string" },
"work_mem": { "type": "string" },
diff --git a/apps/docs/spec/cli_v1_commands.yaml b/apps/docs/spec/cli_v1_commands.yaml
index fdd0d23c502..e07ad7fb852 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: 1.215.0
+ version: 1.223.10
title: Supabase CLI
language: sh
source: https://github.com/supabase/cli
@@ -3354,6 +3354,27 @@ commands:
name: --use-pgadmin
description: Use pgAdmin to generate schema diff.
default_value: 'false'
+ - id: supabase-config
+ title: supabase config
+ summary: Manage Supabase project configurations
+ tags:
+ - management-api
+ links: []
+ subcommands:
+ - supabase-config-push
+ flags: []
+ - id: supabase-config-push
+ title: supabase config push
+ summary: Pushes local config.toml to the linked project
+ tags: []
+ links: []
+ usage: supabase config push
+ subcommands: []
+ flags:
+ - id: project-ref
+ name: --project-ref
+ description: Project ref of the Supabase project.
+ default_value: ''
- id: supabase-completion
title: supabase completion
summary: Generate the autocompletion script for the specified shell
diff --git a/apps/docs/spec/cli_v1_config.yaml b/apps/docs/spec/cli_v1_config.yaml
index c1c5657b914..8780895b8da 100644
--- a/apps/docs/spec/cli_v1_config.yaml
+++ b/apps/docs/spec/cli_v1_config.yaml
@@ -779,6 +779,16 @@ parameters:
links:
- name: 'Auth Server configuration'
link: 'https://supabase.com/docs/reference/auth'
+
+ - id: 'auth.external.provider.skip_nonce_check'
+ title: 'auth.external..skip_nonce_check'
+ tags: ['auth']
+ required: false
+ description: |
+ Disables nonce validation during OIDC authentication flow for the specified provider. Enable only when client libraries cannot properly handle nonce verification. Be aware that this reduces security by allowing potential replay attacks with stolen ID tokens.
+ links:
+ - name: 'Auth Server configuration'
+ link: 'https://supabase.com/docs/reference/auth'
- id: 'functions.function_name.enabled'
title: 'functions..enabled'
diff --git a/apps/docs/spec/common-cli-sections.json b/apps/docs/spec/common-cli-sections.json
index 81a29efb105..6e2aaff44be 100644
--- a/apps/docs/spec/common-cli-sections.json
+++ b/apps/docs/spec/common-cli-sections.json
@@ -357,6 +357,30 @@
}
]
},
+ {
+ "type": "category",
+ "title": "Organizations",
+ "items": [
+ {
+ "id": "supabase-orgs",
+ "title": "Manage organizations",
+ "slug": "supabase-orgs",
+ "type": "cli-command"
+ },
+ {
+ "id": "supabase-orgs-create",
+ "title": "Create an organization",
+ "slug": "supabase-orgs-create",
+ "type": "cli-command"
+ },
+ {
+ "id": "supabase-orgs-list",
+ "title": "List all organizations",
+ "slug": "supabase-orgs-list",
+ "type": "cli-command"
+ }
+ ]
+ },
{
"type": "category",
"title": "Projects",
@@ -393,6 +417,24 @@
}
]
},
+ {
+ "type": "category",
+ "title": "Config",
+ "items": [
+ {
+ "id": "supabase-config",
+ "title": "Manage project configurations",
+ "slug": "supabase-config",
+ "type": "cli-command"
+ },
+ {
+ "id": "supabase-config-push",
+ "title": "Push config from a local file",
+ "slug": "supabase-config-push",
+ "type": "cli-command"
+ }
+ ]
+ },
{
"type": "category",
"title": "Branches",
@@ -441,30 +483,6 @@
}
]
},
- {
- "type": "category",
- "title": "Organizations",
- "items": [
- {
- "id": "supabase-orgs",
- "title": "Manage organizations",
- "slug": "supabase-orgs",
- "type": "cli-command"
- },
- {
- "id": "supabase-orgs-create",
- "title": "Create an organization",
- "slug": "supabase-orgs-create",
- "type": "cli-command"
- },
- {
- "id": "supabase-orgs-list",
- "title": "List all organizations",
- "slug": "supabase-orgs-list",
- "type": "cli-command"
- }
- ]
- },
{
"type": "category",
"title": "Edge Functions",
diff --git a/apps/docs/spec/examples/examples.yml b/apps/docs/spec/examples/examples.yml
index 9a35a086b5e..77249cc8fa8 100644
--- a/apps/docs/spec/examples/examples.yml
+++ b/apps/docs/spec/examples/examples.yml
@@ -194,6 +194,7 @@ functions:
- If you're using an email, you can configure whether you want the user to receive a magiclink or a OTP.
- If you're using phone, you can configure whether you want the user to receive a OTP.
- The magic link's destination URL is determined by the [`SITE_URL`](https://supabase.com/docs/guides/auth/redirect-urls). You can modify the `SITE_URL` or add additional redirect URLs in [your project](https://supabase.com/dashboard/project/_/auth/url-configuration).
+ - If you are looking to send your own OTP emails, you can use the [Auth Admin command](https://supabase.com/docs/reference/javascript/auth-admin-generatelink) or the `Send Email` [Auth Hook](https://supabase.com/docs/guides/auth/auth-hooks)
examples:
- id: sign-in-with-email.
name: Sign in with email.
diff --git a/apps/docs/spec/supabase_dart_v2.yml b/apps/docs/spec/supabase_dart_v2.yml
index 565c92b924d..adbcca2ddec 100644
--- a/apps/docs/spec/supabase_dart_v2.yml
+++ b/apps/docs/spec/supabase_dart_v2.yml
@@ -594,7 +594,7 @@ functions:
- [Steps to obtain Android client ID](https://developers.google.com/identity/sign-in/android/start-integrating#configure_a_project)
- [Steps to obtain iOS client ID](https://developers.google.com/identity/sign-in/ios/start-integrating#get_an_oauth_client_id)
- Add the web client ID to the `Authentication -> Providers -> Google -> Authorized Client IDs` section in your Supabase dashboard
+ Add the web client ID to the `Authentication -> Providers -> Google -> Client IDs` section in your Supabase dashboard
code: |
```dart
import 'package:google_sign_in/google_sign_in.dart';
diff --git a/apps/docs/spec/transforms/api_v1_openapi_deparsed.json b/apps/docs/spec/transforms/api_v1_openapi_deparsed.json
index 3d07a743f9d..692ac2af2b2 100644
--- a/apps/docs/spec/transforms/api_v1_openapi_deparsed.json
+++ b/apps/docs/spec/transforms/api_v1_openapi_deparsed.json
@@ -4488,6 +4488,9 @@
}
}
},
+ "403": {
+ "description": ""
+ },
"500": {
"description": "Failed to retrieve project's service health status"
}
@@ -4720,6 +4723,9 @@
"statement_timeout": {
"type": "string"
},
+ "track_commit_timestamp": {
+ "type": "boolean"
+ },
"wal_keep_size": {
"type": "string"
},
@@ -4835,6 +4841,9 @@
"statement_timeout": {
"type": "string"
},
+ "track_commit_timestamp": {
+ "type": "boolean"
+ },
"wal_keep_size": {
"type": "string"
},
@@ -4927,6 +4936,9 @@
"statement_timeout": {
"type": "string"
},
+ "track_commit_timestamp": {
+ "type": "boolean"
+ },
"wal_keep_size": {
"type": "string"
},
@@ -11882,6 +11894,9 @@
"statement_timeout": {
"type": "string"
},
+ "track_commit_timestamp": {
+ "type": "boolean"
+ },
"wal_keep_size": {
"type": "string"
},
@@ -11963,6 +11978,9 @@
"statement_timeout": {
"type": "string"
},
+ "track_commit_timestamp": {
+ "type": "boolean"
+ },
"wal_keep_size": {
"type": "string"
},
diff --git a/apps/studio/components/grid/SupabaseGrid.tsx b/apps/studio/components/grid/SupabaseGrid.tsx
index 2ba8e5d0a03..7c996ca9108 100644
--- a/apps/studio/components/grid/SupabaseGrid.tsx
+++ b/apps/studio/components/grid/SupabaseGrid.tsx
@@ -149,10 +149,9 @@ const SupabaseGridLayout = (props: SupabaseGridProps) => {
const { project } = useProjectContext()
const { data, error, isSuccess, isError, isLoading, isRefetching } = useTableRowsQuery(
{
- queryKey: [props.table.schema, props.table.name],
projectRef: project?.ref,
connectionString: project?.connectionString,
- table: props.table,
+ tableId: props.table.id,
sorts,
filters,
page: snap.page,
diff --git a/apps/studio/components/grid/components/editor/SelectEditor.tsx b/apps/studio/components/grid/components/editor/SelectEditor.tsx
index 0aa6a08e6c2..3ea7cbe16b1 100644
--- a/apps/studio/components/grid/components/editor/SelectEditor.tsx
+++ b/apps/studio/components/grid/components/editor/SelectEditor.tsx
@@ -23,7 +23,6 @@ export function SelectEditor({
const value = row[column.key as keyof TRow] as unknown as string
function onChange(event: any) {
- debugger
if (!event.target.value || event.target.value == '') {
onRowChange({ ...row, [column.key]: null }, true)
} else {
diff --git a/apps/studio/components/grid/components/footer/pagination/Pagination.tsx b/apps/studio/components/grid/components/footer/pagination/Pagination.tsx
index bb32dd1a3e2..9c4384a8f14 100644
--- a/apps/studio/components/grid/components/footer/pagination/Pagination.tsx
+++ b/apps/studio/components/grid/components/footer/pagination/Pagination.tsx
@@ -44,7 +44,6 @@ const Pagination = () => {
const [{ filter }] = useUrlState({ arrayKeys: ['filter'] })
const filters = formatFilterURLParams(filter as string[])
const page = snap.page
- const table = state.table ?? undefined
const roleImpersonationState = useRoleImpersonationStateSnapshot()
const [isConfirmNextModalOpen, setIsConfirmNextModalOpen] = useState(false)
@@ -60,10 +59,9 @@ const Pagination = () => {
const { data, isLoading, isSuccess, isError, isFetching } = useTableRowsCountQuery(
{
- queryKey: [table?.schema, table?.name, 'count-estimate'],
projectRef: project?.ref,
connectionString: project?.connectionString,
- table,
+ tableId: id,
filters,
enforceExactCount: snap.enforceExactCount,
impersonatedRole: roleImpersonationState.role,
diff --git a/apps/studio/components/grid/components/header/Header.tsx b/apps/studio/components/grid/components/header/Header.tsx
index 292745a27af..45c69218f99 100644
--- a/apps/studio/components/grid/components/header/Header.tsx
+++ b/apps/studio/components/grid/components/header/Header.tsx
@@ -1,5 +1,4 @@
import { PermissionAction } from '@supabase/shared-types/out/constants'
-import clsx from 'clsx'
import saveAs from 'file-saver'
import { ArrowUp, ChevronDown, FileText, Trash } from 'lucide-react'
import Papa from 'papaparse'
@@ -196,7 +195,7 @@ const DefaultHeader = ({ table, onAddColumn, onAddRow, onImportData }: DefaultHe
className="-translate-x-[2px]"
/>
{
const [isExporting, setIsExporting] = useState(false)
const { data } = useTableRowsQuery({
- queryKey: [table.schema, table.name],
projectRef: project?.ref,
connectionString: project?.connectionString,
- table,
+ tableId: table.id,
sorts,
filters,
page: snap.page,
@@ -253,10 +251,9 @@ const RowHeader = ({ table, sorts, filters }: RowHeaderProps) => {
const { data: countData } = useTableRowsCountQuery(
{
- queryKey: [table?.schema, table?.name, 'count-estimate'],
projectRef: project?.ref,
connectionString: project?.connectionString,
- table,
+ tableId: table.id,
filters,
enforceExactCount: snap.enforceExactCount,
impersonatedRole: roleImpersonationState.role,
diff --git a/apps/studio/components/grid/components/header/RefreshButton.tsx b/apps/studio/components/grid/components/header/RefreshButton.tsx
index 0b43a2aa0b2..9bf63bf1b0c 100644
--- a/apps/studio/components/grid/components/header/RefreshButton.tsx
+++ b/apps/studio/components/grid/components/header/RefreshButton.tsx
@@ -2,20 +2,18 @@ import { useQueryClient } from '@tanstack/react-query'
import { RefreshCw } from 'lucide-react'
import { useParams } from 'common'
-import type { SupaTable } from 'components/grid/types'
-import { sqlKeys } from 'data/sql/keys'
-import { Entity } from 'data/table-editor/table-editor-types'
+import { tableRowKeys } from 'data/table-rows/keys'
import { Button } from 'ui'
export type RefreshButtonProps = {
- table: Entity | SupaTable
+ table: { id: number }
isRefetching?: boolean
}
const RefreshButton = ({ table, isRefetching }: RefreshButtonProps) => {
const { ref } = useParams()
const queryClient = useQueryClient()
- const queryKey = sqlKeys.query(ref, [table.schema, table.name])
+ const queryKey = tableRowKeys.tableRowsAndCount(ref, table.id)
async function onClick() {
await queryClient.invalidateQueries(queryKey)
diff --git a/apps/studio/components/interfaces/Auth/AuthProvidersForm/FormField.tsx b/apps/studio/components/interfaces/Auth/AuthProvidersForm/FormField.tsx
index e474cea8e5e..11fdbf2264f 100644
--- a/apps/studio/components/interfaces/Auth/AuthProvidersForm/FormField.tsx
+++ b/apps/studio/components/interfaces/Auth/AuthProvidersForm/FormField.tsx
@@ -3,6 +3,7 @@ import { Eye, EyeOff } from 'lucide-react'
import { useEffect, useState } from 'react'
import ReactMarkdown from 'react-markdown'
+import { Markdown } from 'components/interfaces/Markdown'
import { DatePicker } from 'components/ui/DatePicker'
import { BASE_PATH } from 'lib/constants'
import { Button, Input, InputNumber, Listbox, Toggle } from 'ui'
@@ -109,16 +110,15 @@ const FormField = ({
label={properties.title}
labelOptional={
properties.descriptionOptional ? (
-
- {properties.descriptionOptional}
-
+
) : null
}
descriptionText={
properties.description ? (
-
- {properties.description}
-
+
) : null
}
actions={
@@ -140,6 +140,7 @@ const FormField = ({
}
/>
)
+
case 'multiline-string':
return (
- {properties.description}
-
+
) : null
}
actions={
@@ -183,6 +182,7 @@ const FormField = ({
}
/>
)
+
case 'number':
return (
- {properties.description}
-
+
) : null
}
actions={
diff --git a/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx b/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx
index 1718070d3a5..dd66b17e3be 100644
--- a/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx
+++ b/apps/studio/components/interfaces/Auth/AuthProvidersForm/ProviderForm.tsx
@@ -28,6 +28,7 @@ import {
import { ProviderCollapsibleClasses } from './AuthProvidersForm.constants'
import type { Provider } from './AuthProvidersForm.types'
import FormField from './FormField'
+import { Markdown } from 'components/interfaces/Markdown'
export interface ProviderFormProps {
config: components['schemas']['GoTrueConfigResponse']
@@ -281,9 +282,10 @@ const ProviderForm = ({ config, provider }: ProviderFormProps) => {
: `${apiUrl}/auth/v1/callback`
}
descriptionText={
-
- {provider.misc.helper}
-
+
}
/>
>
diff --git a/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx b/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx
index f804a333cc3..dcb72820e2a 100644
--- a/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx
+++ b/apps/studio/components/interfaces/Auth/AuthProvidersFormValidation.tsx
@@ -399,23 +399,16 @@ const EXTERNAL_PROVIDER_APPLE = {
type: 'boolean',
},
EXTERNAL_APPLE_CLIENT_ID: {
- title: 'Service ID (for OAuth)',
- description: `Client identifier used in the OAuth flow on the web.
-[Learn more](https://developer.apple.com/documentation/sign_in_with_apple/configuring_your_environment_for_sign_in_with_apple)`,
+ title: 'Client IDs',
+ description: `Comma separated list of allowed Apple app (Web, OAuth, iOS, macOS, watchOS, or tvOS) bundle IDs for native sign in, or service IDs for Sign in with Apple JS. [Learn more](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js)`,
type: 'string',
},
EXTERNAL_APPLE_SECRET: {
title: 'Secret Key (for OAuth)',
- description: `Secret key used in the OAuth flow.
-[Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#generate-a-client_secret)`,
+ description: `Secret key used in the OAuth flow. [Learn more](https://supabase.com/docs/guides/auth/social-login/auth-apple#generate-a-client_secret)`,
type: 'string',
isSecret: true,
},
- EXTERNAL_APPLE_ADDITIONAL_CLIENT_IDS: {
- title: 'Authorized Client IDs (iOS, macOS, watchOS, tvOS bundle IDs or service IDs)',
- description: `Comma separated list of allowed Apple app bundle IDs for native sign in, or service IDs for Sign in with Apple JS. [Learn more](https://developer.apple.com/documentation/sign_in_with_apple/sign_in_with_apple_js)`,
- type: 'string',
- },
},
validationSchema: object().shape({
EXTERNAL_APPLE_ENABLED: boolean().required(),
@@ -426,7 +419,6 @@ const EXTERNAL_PROVIDER_APPLE = {
},
then: (schema) =>
schema
- .required('Secret key is required when using the OAuth flow.')
.matches(/^[a-z0-9_-]+([.][a-z0-9_-]+){2}$/i, 'Secret key should be a JWT.')
.test({
message: 'Secret key is not a correctly generated JWT.',
@@ -473,49 +465,27 @@ const EXTERNAL_PROVIDER_APPLE = {
},
}),
})
- .when(
- [
- 'EXTERNAL_APPLE_ENABLED',
- 'EXTERNAL_APPLE_ADDITIONAL_CLIENT_IDS',
- 'EXTERNAL_APPLE_CLIENT_ID',
- ],
- {
- is: (
- EXTERNAL_APPLE_ENABLED: boolean,
- EXTERNAL_APPLE_ADDITIONAL_CLIENT_IDS: string,
- EXTERNAL_APPLE_CLIENT_ID: string
- ) => {
- return (
- EXTERNAL_APPLE_ENABLED &&
- !!EXTERNAL_APPLE_ADDITIONAL_CLIENT_IDS &&
- !EXTERNAL_APPLE_CLIENT_ID
- )
- },
- then: (schema) =>
- schema.matches(
- /^$/,
- 'Secret Key should only be set if Service ID for OAuth is provided.'
- ),
- }
- ),
- EXTERNAL_APPLE_CLIENT_ID: string().matches(
- /^[a-z0-9.-]+$/i,
- 'Invalid characters. Apple recommends a reverse-domain name style string (e.g. com.example.app).'
- ),
- EXTERNAL_APPLE_ADDITIONAL_CLIENT_IDS: string()
- .matches(
- /^([.a-z0-9-]+(,\s*[.a-z0-9-]+)*,*\s*)?$/i,
- 'Invalid characters. Apple recommends a reverse-domain name style string (e.g. com.example.app). You must only use explicit bundle IDs, asterisks (*) are not allowed.'
- )
.when(['EXTERNAL_APPLE_ENABLED', 'EXTERNAL_APPLE_CLIENT_ID'], {
is: (EXTERNAL_APPLE_ENABLED: boolean, EXTERNAL_APPLE_CLIENT_ID: string) => {
return EXTERNAL_APPLE_ENABLED && !EXTERNAL_APPLE_CLIENT_ID
},
then: (schema) =>
- schema.required(
- 'At least one Authorized Client ID is required when not using the OAuth flow.'
+ schema.matches(
+ /^$/,
+ 'Secret Key should only be set if Service ID for OAuth is provided.'
),
}),
+ EXTERNAL_APPLE_CLIENT_ID: string()
+ .matches(/^\S+$/, 'Client IDs should not contain spaces.')
+ .matches(
+ /^([a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9-]+)*(,[a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9-]+)*)*)$/i,
+ 'Invalid characters. Each ID should follow a reverse-domain style string (e.g. com.example.app). Use commas to separate multiple IDs.'
+ )
+ .when('EXTERNAL_APPLE_ENABLED', {
+ is: true,
+ then: (schema) =>
+ schema.required('At least one Client ID is required when Apple sign-in is enabled.'),
+ }),
}),
misc: {
iconKey: 'apple-icon',
@@ -833,8 +803,9 @@ const EXTERNAL_PROVIDER_GOOGLE = {
type: 'boolean',
},
EXTERNAL_GOOGLE_CLIENT_ID: {
- title: 'Client ID (for OAuth)',
- description: 'Client ID to use with the OAuth flow on the web.',
+ title: 'Client IDs',
+ description:
+ 'Comma-separated list of client IDs for Web, OAuth, Android apps, One Tap, and Chrome extensions.',
type: 'string',
},
EXTERNAL_GOOGLE_SECRET: {
@@ -843,78 +814,34 @@ const EXTERNAL_PROVIDER_GOOGLE = {
type: 'string',
isSecret: true,
},
- EXTERNAL_GOOGLE_ADDITIONAL_CLIENT_IDS: {
- title: 'Authorized Client IDs (for Android, One Tap, and Chrome extensions)',
- description:
- 'Comma separated list of client IDs of Android apps, One Tap or Chrome extensions that are allowed to log in to your project.',
- type: 'string',
- },
EXTERNAL_GOOGLE_SKIP_NONCE_CHECK: {
title: 'Skip nonce checks',
description:
- "Allows ID tokens with any nonce to be accepted, which is less secure. Useful in situations where you don't have access to the nonce used to issue the ID token, such with iOS.",
+ "Allows ID tokens with any nonce to be accepted, which is less secure. Useful in situations where you don't have access to the nonce used to issue the ID token, such as with iOS.",
type: 'boolean',
},
},
validationSchema: object().shape({
EXTERNAL_GOOGLE_ENABLED: boolean().required(),
- EXTERNAL_GOOGLE_SECRET: string()
- .when(['EXTERNAL_GOOGLE_ENABLED', 'EXTERNAL_GOOGLE_CLIENT_ID'], {
- is: (EXTERNAL_GOOGLE_ENABLED: boolean, EXTERNAL_GOOGLE_CLIENT_ID: string) => {
- return EXTERNAL_GOOGLE_ENABLED && !!EXTERNAL_GOOGLE_CLIENT_ID
- },
- then: (schema) =>
- schema
- .matches(
- /^[a-z0-9.\/_-]*$/i,
- 'Invalid characters. Google OAuth Client Secrets usually contain letters, numbers, dots, dashes and underscores.'
- )
- .required('Client Secret is required when using the OAuth flow.'),
- })
- .when(
- [
- 'EXTERNAL_GOOGLE_ENABLED',
- 'EXTERNAL_GOOGLE_ADDITIONAL_CLIENT_IDS',
- 'EXTERNAL_GOOGLE_CLIENT_ID',
- ],
- {
- is: (
- EXTERNAL_GOOGLE_ENABLED: boolean,
- EXTERNAL_GOOGLE_ADDITIONAL_CLIENT_IDS: string,
- EXTERNAL_GOOGLE_CLIENT_ID: string
- ) => {
- return (
- EXTERNAL_GOOGLE_ENABLED &&
- !!EXTERNAL_GOOGLE_ADDITIONAL_CLIENT_IDS &&
- !EXTERNAL_GOOGLE_CLIENT_ID
- )
- },
- then: (schema) =>
- schema.matches(
- /^$/,
- 'Client Secret should only be set when Client ID for OAuth is set.'
- ),
- }
- ),
- EXTERNAL_GOOGLE_CLIENT_ID: string().matches(
- /^([a-z0-9-]+([.][a-z0-9-]+)+)?$/i,
- 'Invalid characters. Google OAuth Client IDs are usually a domain-name (e.g. 01234567890-abcdefghijklmnopqrstuvwxyz012345.apps.googleusercontent.com).'
- ),
- EXTERNAL_GOOGLE_ADDITIONAL_CLIENT_IDS: string()
+ EXTERNAL_GOOGLE_CLIENT_ID: string()
+ .matches(/^\S+$/, 'Client IDs should not contain spaces.')
.matches(
- /^([a-z0-9-]+([.][a-z0-9-]+)*(,\s*[a-z0-9-]+([.][a-z0-9-]+)*)*,*\s*)?$/i,
- 'Invalid characters. Google Client IDs are usually a domain-name style string (e.g. com.example.com.app or *.apps.googleusercontent.com).'
+ /^([a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9-]+)*(,[a-z0-9-]+\.[a-z0-9-]+(\.[a-z0-9-]+)*)*)$/i,
+ 'Invalid characters. Google Client IDs should be a comma-separated list of domain-like strings.'
)
-
- .when(['EXTERNAL_GOOGLE_ENABLED', 'EXTERNAL_GOOGLE_CLIENT_ID'], {
- is: (EXTERNAL_GOOGLE_ENABLED: boolean, EXTERNAL_GOOGLE_CLIENT_ID: string) => {
- return EXTERNAL_GOOGLE_ENABLED && !EXTERNAL_GOOGLE_CLIENT_ID
- },
+ .when('EXTERNAL_GOOGLE_ENABLED', {
+ is: true,
then: (schema) =>
- schema.required(
- 'At least one Authorized Client ID is required when not using the OAuth flow.'
- ),
+ schema.required('At least one Client ID is required when Google sign-in is enabled.'),
}),
+ EXTERNAL_GOOGLE_SECRET: string().when('EXTERNAL_GOOGLE_ENABLED', {
+ is: true,
+ then: (schema) =>
+ schema.matches(
+ /^[a-z0-9.\/_-]*$/i,
+ 'Invalid characters. Google OAuth Client Secrets usually contain letters, numbers, dots, dashes, and underscores.'
+ ),
+ }),
EXTERNAL_GOOGLE_SKIP_NONCE_CHECK: boolean().required(),
}),
misc: {
diff --git a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/AIPolicyEditorPanel.utils.ts b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/AIPolicyEditorPanel.utils.ts
index e68356d2d98..937eaaa4f1d 100644
--- a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/AIPolicyEditorPanel.utils.ts
+++ b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/AIPolicyEditorPanel.utils.ts
@@ -1,7 +1,8 @@
import type { PostgresPolicy } from '@supabase/postgres-meta'
+import { isEqual } from 'lodash'
+
import type { Message } from 'ai/react'
import { uuidv4 } from 'lib/helpers'
-import { isEqual } from 'lodash'
export type MessageWithDebug = Message & { isDebug: boolean }
diff --git a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx
index 429de771a3e..5f4e045b7d1 100644
--- a/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx
+++ b/apps/studio/components/interfaces/Auth/Policies/AIPolicyEditorPanel/LockedQuerySection.tsx
@@ -1,29 +1,17 @@
import { PostgresPolicy } from '@supabase/postgres-meta'
import { Lock } from 'lucide-react'
-import { useRouter } from 'next/router'
-
-import { useParams } from 'common'
-import { Button } from 'ui'
-import { generateAlterPolicyQuery, generateCreatePolicyQuery } from './AIPolicyEditorPanel.utils'
interface LockedCreateQuerySection {
schema: string
selectedPolicy?: PostgresPolicy
formFields: { name: string; table: string; behavior: string; command: string; roles: string }
- editorOneRef: any
- editorTwoRef: any
}
export const LockedCreateQuerySection = ({
schema,
selectedPolicy,
formFields,
- editorOneRef,
- editorTwoRef,
}: LockedCreateQuerySection) => {
- const router = useRouter()
- const { ref } = useParams()
-
const isEditing = selectedPolicy !== undefined
const { name, table, behavior, command, roles } = formFields
@@ -38,41 +26,6 @@ export const LockedCreateQuerySection = ({
Use options above to edit