diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 6b5a82aa503..37a38306f94 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -773,6 +773,12 @@ export const auth: NavMenuConstant = { ], }, + { + name: 'Custom OAuth/OIDC Providers', + url: '/guides/auth/custom-oauth-providers', + enabled: allAuthProvidersEnabled, + }, + { name: 'Anonymous Sign-Ins', url: '/guides/auth/auth-anonymous', diff --git a/apps/docs/content/_partials/providers.mdx b/apps/docs/content/_partials/providers.mdx index 4f4fe7f2def..bb489af03d9 100644 --- a/apps/docs/content/_partials/providers.mdx +++ b/apps/docs/content/_partials/providers.mdx @@ -6,6 +6,12 @@ Supabase Auth works with many popular Auth methods, including Social and Phone A + + +You can also add any OAuth2 or OIDC-compatible identity provider using [Custom OAuth/OIDC Providers](/docs/guides/auth/custom-oauth-providers). + + + ### Phone Auth diff --git a/apps/docs/content/guides/auth/custom-oauth-providers.mdx b/apps/docs/content/guides/auth/custom-oauth-providers.mdx new file mode 100644 index 00000000000..3b44be70f32 --- /dev/null +++ b/apps/docs/content/guides/auth/custom-oauth-providers.mdx @@ -0,0 +1,321 @@ +--- +id: 'custom-oauth-providers' +title: 'Custom OAuth/OIDC Providers' +description: 'Add any OAuth2 or OIDC-compatible identity provider to your Supabase project' +--- + +Custom OAuth/OIDC providers let you integrate any standards-compliant identity provider with Supabase Auth, beyond the ones Supabase supports out of the box. + +Each custom provider uses a `custom:` prefix in its identifier (for example, `custom:my-idp` or `custom:github-enterprise`). This prefix distinguishes custom providers from built-in providers. + +There are two provider types: + +- **OAuth2**: for generic OAuth2 providers where you supply the authorization, token, and userinfo endpoints manually. +- **OIDC**: for providers that support [OpenID Connect](https://openid.net/connect/) discovery. You supply only the issuer URL and endpoints are resolved automatically. + + + +You can add up to 3 custom providers per project. If you need more, [contact support](/dashboard/support/new). + + + +## Creating a provider + +The create form displays a read-only **Callback URL**. Copy this URL and configure it as the redirect/callback URI in your external identity provider before completing setup. + +### OAuth2 provider + +Use an OAuth2 provider when your identity provider does not support OpenID Connect discovery. You must supply the authorization, token, and userinfo endpoint URLs explicitly. + + + + +1. Go to [Auth Providers](/dashboard/project/_/auth/providers) in the Dashboard. +2. Click **New Provider**. Select **Manual configuration** as the configuration method. +3. Enter a unique identifier (must start with `custom:`, for example `custom:my-oauth-provider`). +4. Enter the provider's **Client ID** and **Client Secret**. +5. Enter the **Authorization URL**, **Token URL**, and **UserInfo URL**. +6. Click **Create and enable provider**. + + + + +```js +const { data, error } = await supabase.auth.admin.customProviders.createProvider({ + provider_type: 'oauth2', + identifier: 'custom:my-oauth-provider', + name: 'My OAuth Provider', + client_id: 'your-client-id', + client_secret: 'your-client-secret', + authorization_url: 'https://provider.example.com/oauth/authorize', + token_url: 'https://provider.example.com/oauth/token', + userinfo_url: 'https://provider.example.com/oauth/userinfo', + scopes: ['profile', 'email'], +}) +``` + + + + +### OIDC provider + +Use an OIDC provider when your identity provider supports OpenID Connect. Supply the `issuer` URL and the discovery document, JWKS, and endpoints are resolved automatically. + + + + +1. Go to [Auth Providers](/dashboard/project/_/auth/providers) in the Dashboard. +2. Click **New Provider**. Select **Auto-discovery (OIDC)** as the configuration method. +3. Enter a unique identifier (must start with `custom:`, for example `custom:my-regional-provider`). +4. Enter the provider's **Client ID** and **Client Secret**. +5. Enter the **Issuer URL**. The discovery document and endpoints are resolved automatically. +6. Click **Create and enable provider**. + + + + +```js +const { data, error } = await supabase.auth.admin.customProviders.createProvider({ + provider_type: 'oidc', + identifier: 'custom:my-regional-provider', + name: 'Regional Provider', + client_id: 'your-client-id', + client_secret: 'your-client-secret', + issuer: 'https://auth.example.com', + scopes: ['openid', 'profile', 'email'], +}) +``` + + + + +OIDC providers have the following automatic behavior: + +- The discovery document is fetched from `{issuer}/.well-known/openid-configuration` (or from `discovery_url` if set). +- The `openid` scope is always included. It is automatically added if missing from the `scopes` array. +- ID tokens are verified against the provider's JWKS (fetched from the discovery document's `jwks_uri`). + +## Provider identifiers + +Every custom provider identifier must start with the `custom:` prefix. Identifiers are 2–50 characters, lowercase alphanumeric with hyphens and colons allowed. Examples: + +- `custom:my-provider` +- `custom:github-enterprise` + +## User sign-in + +Once a custom provider is created and enabled, users sign in via the standard OAuth authorize endpoint: + +``` +GET https://your-project.supabase.co/auth/v1/authorize?provider=custom:my-provider +``` + +Or using the Supabase client libraries: + + + + +```js +const { data, error } = await supabase.auth.signInWithOAuth({ + provider: 'custom:my-provider', +}) +``` + + + + +```dart +await supabase.auth.signInWithOAuth( + OAuthProvider('custom:my-provider'), +); +``` + + + + +```swift +try await supabase.auth.signInWithOAuth( + provider: "custom:my-provider", + redirectTo: URL(string: "my-custom-scheme://my-app-host") +) +``` + + + + +```kotlin +supabase.auth.signInWith(CustomProvider("custom:my-provider")) +``` + + + + +## Managing providers + +### List providers + + + + +Go to [Auth Providers](/dashboard/project/_/auth/providers) in the Dashboard. All custom providers are listed under **Custom OAuth Providers**. + + + + +```js +// List all custom providers +const { data, error } = await supabase.auth.admin.customProviders.listProviders() + +// Filter by provider type +const { data, error } = await supabase.auth.admin.customProviders.listProviders({ + type: 'oidc', +}) +``` + + + + +### Update a provider + +Update any provider fields except `provider_type` and `identifier`. Only provided fields are changed (partial update). To rotate a client secret, update only the `client_secret` field. + + + + +1. Go to [Auth Providers](/dashboard/project/_/auth/providers) in the Dashboard. +2. Click the three-dot menu (⋮) next to the provider and select **Update**. +3. Modify the fields you want to change. +4. Click **Update provider**. + + + + +```js +const { data, error } = await supabase.auth.admin.customProviders.updateProvider( + 'custom:my-provider', + { + name: 'Updated Provider Name', + scopes: ['profile', 'email', 'groups'], + enabled: false, + } +) +``` + + + + +### Delete a provider + + + + +1. Go to [Auth Providers](/dashboard/project/_/auth/providers) in the Dashboard. +2. Click the three-dot menu (⋮) next to the provider and select **Delete**. +3. Confirm the deletion. + + + + +```js +const { data, error } = await supabase.auth.admin.customProviders.deleteProvider( + 'custom:my-provider' +) +``` + + + + +## Advanced configuration + +### PKCE + +PKCE (Proof Key for Code Exchange) is enabled by default (`pkce_enabled: true`) for all custom providers. The auth server automatically generates a code challenge and verifier during the authorization flow, protecting against authorization code interception attacks. This is handled entirely server-side, no client-side PKCE logic is needed. + +To disable PKCE for a specific provider, set `pkce_enabled: false` when creating or updating it. This is not recommended unless the identity provider does not support PKCE. + +### Authorization params + +Extra query parameters appended to the provider's authorization URL during the OAuth flow. All values must be strings. + +```json +{ + "prompt": "consent", + "access_type": "offline", + "login_hint": "user@example.com" +} +``` + +The following reserved parameters are managed by the auth server and cannot be overridden: `client_id`, `client_secret`, `redirect_uri`, `response_type`, `state`, `code_challenge`, `code_challenge_method`, `code_verifier`, `nonce`. + +### Multi-platform apps + +If your app uses different client IDs for different platforms (for example, web vs mobile), use `acceptable_client_ids` to list additional client IDs that should be accepted for audience validation in OIDC ID tokens: + +```js +const { data, error } = await supabase.auth.admin.customProviders.createProvider({ + provider_type: 'oidc', + identifier: 'custom:multi-platform-app', + name: 'Multi-Platform App', + client_id: 'web-client-id', + client_secret: 'your-client-secret', + issuer: 'https://app.example.com', + scopes: ['openid', 'profile', 'email'], + acceptable_client_ids: ['ios-client-id', 'android-client-id'], +}) +``` + +### Email-optional providers + +By default, providers must return an email address. Set `email_optional` to `true` when creating or updating a provider to allow sign-in without an email. This applies to both OAuth2 and OIDC providers. + +### OIDC-specific options + +| Field | Type | Default | Description | +| --- | --- | --- | --- | +| `discovery_url` | `string` | `null` | Override the discovery document URL if the provider uses a non-standard location. | +| `skip_nonce_check` | `bool` | `false` | Skip nonce validation on ID tokens. Use only for providers that do not support nonce. | + +## Error reference + +| Error code | HTTP status | Description | +| --- | --- | --- | +| `validation_failed` | 400 | Invalid parameters: missing required fields, bad format, reserved params, or invalid URLs. | +| `conflict` | 400 | A provider with the same identifier already exists. | +| `over_custom_provider_quota` | 400 | Maximum number of custom providers reached. | +| `custom_provider_not_found` | 404 | No provider exists with the given identifier. | diff --git a/apps/docs/content/guides/auth/social-login.mdx b/apps/docs/content/guides/auth/social-login.mdx index 75a2b809d3c..c0b642296d3 100644 --- a/apps/docs/content/guides/auth/social-login.mdx +++ b/apps/docs/content/guides/auth/social-login.mdx @@ -45,6 +45,12 @@ Supabase supports a suite of social providers. Follow these guides to configure + + +Need to integrate with a provider not listed here? You can add any OAuth2 or OIDC-compatible provider using [Custom OAuth/OIDC Providers](/docs/guides/auth/custom-oauth-providers). + + + ## Provider tokens You can use the provider token and provider refresh token returned to make API calls to the OAuth provider. For example, you can use the Google provider token to access Google APIs on behalf of your user.