From f55cb25b9bce14f1ea5146dec1b900fb80cd194e Mon Sep 17 00:00:00 2001 From: "Andrey A." <56412611+aantti@users.noreply.github.com> Date: Fri, 10 Jul 2026 11:03:20 +0200 Subject: [PATCH] docs(auth): add a section about user invites (#47774) --- .../guides/auth/auth-email-passwordless.mdx | 12 +++- .../guides/auth/auth-email-templates.mdx | 4 +- apps/docs/content/guides/auth/users.mdx | 56 +++++++++++++++++++ 3 files changed, 67 insertions(+), 5 deletions(-) diff --git a/apps/docs/content/guides/auth/auth-email-passwordless.mdx b/apps/docs/content/guides/auth/auth-email-passwordless.mdx index 56532c6dcbf..cb3bec49641 100644 --- a/apps/docs/content/guides/auth/auth-email-passwordless.mdx +++ b/apps/docs/content/guides/auth/auth-email-passwordless.mdx @@ -24,7 +24,7 @@ Magic Links are a form of passwordless login where users click on a link sent to Email authentication methods, including Magic Links, are enabled by default. -Configure the Site URL and any additional redirect URLs. These are the only URLs that are allowed as redirect destinations after the user clicks a Magic Link. You can change the URLs on the [URL Configuration page](/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. +Configure the Site URL and any additional redirect URLs. These are the only URLs that are allowed as redirect destinations after the user clicks a Magic Link. You can change the URLs on the [URL Configuration page](/dashboard/project/_/auth/url-configuration) for hosted projects, in the `config.toml` [file](/docs/guides/local-development/cli/config#auth.additional_redirect_urls) for local development, or in the `.env` configuration file for [self-hosted Supabase](/docs/guides/self-hosting/docker). By default, a user can only request a magic link once every auth.rate_limits.magic_link.period and they expire after auth.rate_limits.magic_link.validity. @@ -173,7 +173,7 @@ Email one-time passwords (OTP) are a form of passwordless login where users key Email authentication methods, including Email OTPs, are enabled by default. -Email OTPs share an implementation with Magic Links. To send an OTP instead of a Magic Link, alter the **Magic Link** email template. For a hosted Supabase project, go to [Email Templates](/dashboard/project/_/auth/templates) in the Dashboard. For a self-hosted project or local development, see the [Email Templates guide](/docs/guides/auth/auth-email-templates). +Email OTPs share an implementation with Magic Links. To send an OTP instead of a Magic Link, alter the **Magic Link** [email template](/dashboard/project/_/auth/templates/magic-link-or-otp). Refer to the [Email Templates guide](/docs/guides/auth/auth-email-templates) for more information. Modify the template to include the `{{ .Token }}` variable, for example: @@ -183,7 +183,13 @@ Modify the template to include the `{{ .Token }}` variable, for example:

Please enter this code: {{ .Token }}

``` -By default, a user can only request an OTP once every auth.rate_limits.otp.period and they expire after auth.rate_limits.otp.validity. This is configurable via `Auth > Providers > Email > Email OTP Expiration`. An expiry duration of more than 86400 seconds (one day) is disallowed to guard against brute force attacks. The longer an OTP remains valid, the more time an attacker has to attempt brute force attacks. If the OTP is valid for several days, an attacker might have more opportunities to guess the correct OTP through repeated attempts. +By default, a user can only request an OTP once every auth.rate_limits.otp.period, and they expire after auth.rate_limits.otp.validity. This is configurable via **Authentication > Sign In / Providers > Auth Providers > Email > Email OTP expiration**. An expiry duration of more than 86,400 seconds (one day) is strongly discouraged and can only be set via the [Management API](/docs/reference/api/v1-update-auth-service-config). Make sure to read the [security recommendations](/docs/guides/deployment/going-into-prod#security) before going into production. + + + +The **Email OTP Expiration** setting also governs the validity of Magic Links and other email links, including confirmation, password recovery, email change, and [invitation](/docs/guides/auth/users#inviting-users) links. + + ### Signing in with email OTP diff --git a/apps/docs/content/guides/auth/auth-email-templates.mdx b/apps/docs/content/guides/auth/auth-email-templates.mdx index f963ef84647..5be7d6d7384 100644 --- a/apps/docs/content/guides/auth/auth-email-templates.mdx +++ b/apps/docs/content/guides/auth/auth-email-templates.mdx @@ -57,7 +57,7 @@ Edit templates on the [Email Templates](/dashboard/project/_/auth/templates) pag ### Local development and self-hosted -The dashboard template builder does not apply when running Supabase locally or self-hosted. Customize templates in `supabase/config.toml` and HTML files instead. +The dashboard template builder **does not apply** when running [local development with CLI](/docs/guides/local-development) or [self-hosted Supabase](/docs/guides/self-hosting). Customize templates in `supabase/config.toml` and local HTML files instead. @@ -67,7 +67,7 @@ See [Customizing email templates](/docs/guides/local-development/customizing-ema - [Template variables](/docs/guides/local-development/customizing-email-templates#template-variables) — the same placeholders as the [terminology](#terminology) table above - Default subjects and behavior for each [authentication](/docs/guides/local-development/customizing-email-templates#available-authentication-email-templates) and [security notification](/docs/guides/local-development/customizing-email-templates#available-security-notification-email-templates) template -For production self-hosted deployments, see [Custom email templates](/docs/guides/self-hosting/custom-email-templates). +For self-hosted deployments, refer to [Custom email templates](/docs/guides/self-hosting/custom-email-templates). diff --git a/apps/docs/content/guides/auth/users.mdx b/apps/docs/content/guides/auth/users.mdx index 3157bbc88a1..0ad2d0c0eff 100644 --- a/apps/docs/content/guides/auth/users.mdx +++ b/apps/docs/content/guides/auth/users.mdx @@ -74,6 +74,62 @@ The user object contains the following attributes: | updated_at | `string` | The timestamp that the user was last updated. | | is_anonymous | `boolean` | Is true if the user is an anonymous user. | +## Inviting users + +You can invite someone to create an account by sending them an invitation email. The invited user receives an email containing a link that, when clicked, confirms their email address and lets them finish setting up their account (for example, by setting a password). + +Inviting a user is an admin action, so it must be performed from a trusted server environment using your secret key, or from the Dashboard. When you invite an email that doesn't yet belong to a user, a new unconfirmed user is created. Inviting an email that already belongs to a confirmed user returns an error. + +### Using the Dashboard + +1. Go to **Authentication > Users** in the Dashboard. +2. Click **Add user** and select **Send invitation**. +3. Enter the user's email address and click **Invite user**. + +{/* supa-mdx-lint-disable-next-line Rule001HeadingCase */} + +### Using the Auth Admin API + +Call [`inviteUserByEmail()`](/docs/reference/javascript/auth-admin-inviteuserbyemail) from the SDK's Auth Admin API in a server-side environment. This is part of Supabase Auth (accessed via `supabase.auth.admin` with your project's [secret key](/docs/guides/getting-started/api-keys)), and is distinct from the [Management API](/docs/reference/api/introduction) used to configure your project. You can optionally attach custom `user_metadata` and a redirect URL for the invite link. + +```js +import { createClient } from '@supabase/supabase-js' + +// Use your project's secret key (sb_secret_...), and only ever on a trusted server. +const supabase = createClient(process.env.SUPABASE_URL, process.env.SUPABASE_SECRET_KEY, { + auth: { + autoRefreshToken: false, + persistSession: false, + detectSessionInUrl: false, + }, +}) + +const { data, error } = await supabase.auth.admin.inviteUserByEmail('someone@example.com', { + data: { name: 'Jane' }, // optional, stored in user_metadata + redirectTo: 'https://example.com/welcome', // optional, where the invite link sends the user +}) +``` + + + +The secret key (`sb_secret_...`, which replaces the legacy `service_role` key) bypasses Row Level Security and must only be used in a secure server environment. Never expose it in a browser or any publicly accessible client. + + + + + +The `redirectTo` URL must be in your project's [allowed redirect URLs](/docs/guides/auth/redirect-urls) configuration. If it isn't, the `redirectTo` value is ignored and the invite link redirects to your Site URL instead (no error is raised). + + + +The invitation email uses the **Invite user** email template, which you can customize. Refer to [Email Templates](/docs/guides/auth/auth-email-templates) to learn more. + + + +Invitation links expire after the duration configured in [Email OTP Expiration](/dashboard/project/_/auth/providers?provider=Email), which defaults to 1 hour. This is the same value used for [email OTPs](/docs/guides/auth/auth-email-passwordless#enabling-email-otp), magic links, and other email confirmation links. If an invitation expires before it's accepted, send the user a new invite. + + + ## Resources - [User Management guide](/docs/guides/auth/managing-user-data)