mirror of
https://github.com/supabase/supabase.git
synced 2026-10-08 10:55:06 +03:00
## What kind of change does this PR introduce? Docs update. Aligns documentation and style guides with the **Sign in / Sign out / Sign up** platform standard. Closes DOCS-1328. Related to [#49874](https://github.com/supabase/supabase/pull/49874). ## What is the current behavior? Docs style guides prefer _login_ / _log in_. Guide prose uses mixed login and sign in wording. ## What is the new behavior? - [WORD_LIST.md](apps/docs/WORD_LIST.md) and [copywriting.mdx](apps/design-system/content/docs/copywriting.mdx) document the sign in standard - Design-system auth examples updated - Guide prose and API reference spec descriptions updated ### Terminology **Standard:** Use _sign in_, _sign out_, and _sign up_ as verbs. Use _sign-in_, _sign-out_, and _sign-up_ as nouns and adjectives. Match Studio UI labels (**Sign in**, **Sign out**, **Sign up**). **Preserved intentionally:** | Category | Keep as-is | Example | | -------- | ---------- | ------- | | Feature name | social login | `/social-login`, `features.mdx` heading, OAuth provider section | | URL slugs | `login` in paths | `/phone-login`, `/login-flows`, `choosing-login-flow` | | CLI | `supabase login` / `supabase logout` | Reference ids `supabase-login` / `supabase-logout`; executable commands unchanged | | SDK methods | `logout()` | Kotlin/Swift method names in API reference titles and examples | | Third-party UI | Provider product labels | Facebook Login, Kakao Login, portal **Login** buttons | | Postgres | Database terminology | login privileges, login credentials, login via role | | Audit/logging | Log prose | "Generates the following **log** in the Postgres Logs" | | Code and routes | Paths and filenames | `app/login/`, `Login.tsx`, `demos/android-login` | | External URLs | Third-party login pages | `dash.cloudflare.com/login`, `console.neon.tech/login`, `vercel.com/login` | | API identifiers | Event and field names | Audit actions `login`/`logout`, `should_logout_user` | ## To test - Run `pnpm lint:mdx` in `apps/docs` - Spot-check `features.mdx`, `social-login.mdx`, and a provider guide (e.g. Facebook, Kakao) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Documentation** * Standardized authentication terminology across guides, reference material, CLI documentation, and copywriting guidance using “sign in,” “sign out,” and “sign up.” * Updated authentication instructions, headings, link text, examples, and SSO guidance for clearer, more consistent wording. * Corrected related grammar, spelling, hyphenation, and documentation links while preserving established product names and implementation commands. * **Style** * Refined code examples with consistent import ordering and spacing. * **Examples** * Updated authentication button and menu labels to “Sign in” and “Sign out.” <!-- end of auto-generated comment: release notes by coderabbit.ai -->
304 lines
12 KiB
Plaintext
304 lines
12 KiB
Plaintext
---
|
|
id: 'auth-identity-linking'
|
|
title: 'Identity Linking'
|
|
description: 'Manage the identities associated with your user'
|
|
subtitle: 'Manage the identities associated with your user'
|
|
---
|
|
|
|
## Identity linking strategies
|
|
|
|
Currently, Supabase Auth supports 2 strategies to link an identity to a user:
|
|
|
|
1. [Automatic Linking](#automatic-linking)
|
|
2. [Manual Linking](#manual-linking-beta)
|
|
|
|
<Admonition type="note" title="No identity linking for SSO accounts">
|
|
|
|
Users that signed up with [SAML SSO](/docs/guides/auth/enterprise-sso/auth-sso-saml) will not be considered as targets for identity linking (automatic or manual) for security reasons.
|
|
|
|
</Admonition>
|
|
|
|
### Automatic linking
|
|
|
|
Supabase Auth automatically links identities with the same email address to a single user. This helps to improve the user experience when multiple OAuth sign-in options are presented since the user does not need to remember which OAuth account they used to sign up with. When a new user signs in with OAuth, Supabase Auth will attempt to look for an existing user that uses the same email address. If a match is found, the new identity is linked to the user.
|
|
|
|
In order for automatic linking to correctly identify the user for linking, Supabase Auth needs to ensure that all user emails are unique. It would also be an insecure practice to automatically link an identity to a user with an unverified email address since that could lead to pre-account takeover attacks. To prevent this from happening, when a new identity can be linked to an existing user, Supabase Auth will remove any other unconfirmed identities linked to an existing user.
|
|
|
|
### Manual linking (beta)
|
|
|
|
<Tabs
|
|
scrollable
|
|
size="small"
|
|
type="underlined"
|
|
defaultActiveId="js"
|
|
queryGroup="language"
|
|
>
|
|
<TabPanel id="js" label="JavaScript">
|
|
|
|
Supabase Auth allows a user to initiate identity linking with a different email address when they are signed in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/javascript/auth-linkidentity):
|
|
|
|
```js
|
|
import { createClient } from '@supabase/supabase-js'
|
|
|
|
const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...')
|
|
|
|
// ---cut---
|
|
const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' })
|
|
```
|
|
|
|
</TabPanel>
|
|
<$Show if="sdk:dart">
|
|
<TabPanel id="dart" label="Dart">
|
|
|
|
Supabase Auth allows a user to initiate identity linking with a different email address when they are signed in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/dart/auth-linkidentity):
|
|
|
|
```dart
|
|
await supabase.auth.linkIdentity(OAuthProvider.google);
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:swift">
|
|
<TabPanel id="swift" label="Swift">
|
|
|
|
Supabase Auth allows a user to initiate identity linking with a different email address when they are signed in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/swift/auth-linkidentity):
|
|
|
|
```swift
|
|
try await supabase.auth.linkIdentity(provider: .google)
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:kotlin">
|
|
<TabPanel id="kotlin" label="Kotlin">
|
|
|
|
Supabase Auth allows a user to initiate identity linking with a different email address when they are signed in. To link an OAuth identity to the user, call [`linkIdentity()`](/docs/reference/kotlin/auth-linkidentity):
|
|
|
|
```kotlin
|
|
supabase.auth.linkIdentity(Google)
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:python">
|
|
<TabPanel id="python" label="Python">
|
|
|
|
Supabase Auth allows a user to initiate identity linking with a different email address when they are signed in. To link an OAuth identity to the user, call [`link_identity()`](/docs/reference/python/auth-linkidentity):
|
|
|
|
```python
|
|
response = supabase.auth.link_identity({'provider': 'google'})
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:csharp">
|
|
<TabPanel id="csharp" label="C#">
|
|
|
|
Supabase Auth allows a user to initiate identity linking with a different email address when they are signed in. To link an OAuth identity to the user, call [`LinkIdentity()`](/docs/reference/csharp/link-identity):
|
|
|
|
```c#
|
|
var state = await supabase.Auth.LinkIdentity(Provider.Google, new SignInOptions { FlowType = OAuthFlowType.PKCE });
|
|
var authorizeUrl = state.Uri;
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
</Tabs>
|
|
|
|
In the example above, the user will be redirected to Google to complete the OAuth2.0 flow. Once the OAuth2.0 flow has completed successfully, the user will be redirected back to the application and the Google identity will be linked to the user. You can enable manual linking from your project's authentication [configuration options](/dashboard/project/_/auth/providers) or by setting the environment variable `GOTRUE_SECURITY_MANUAL_LINKING_ENABLED: true` when self-hosting.
|
|
|
|
### Link identity with native OAuth (ID token)
|
|
|
|
<Tabs
|
|
scrollable
|
|
size="small"
|
|
type="underlined"
|
|
defaultActiveId="js"
|
|
queryGroup="language"
|
|
>
|
|
<TabPanel id="js" label="JavaScript">
|
|
|
|
For native mobile applications, you can link an identity using an ID token obtained from a third-party OAuth provider. This is useful when you want to use native OAuth flows (like Google Sign-In or Sign in with Apple) rather than web-based OAuth redirects.
|
|
|
|
```js
|
|
// Example with Google Sign-In (using a native Google Sign-In library)
|
|
const idToken = 'ID_TOKEN_FROM_GOOGLE'
|
|
const accessToken = 'ACCESS_TOKEN_FROM_GOOGLE'
|
|
|
|
const { data, error } = await supabase.auth.linkIdentity({
|
|
provider: 'google',
|
|
token: idToken,
|
|
access_token: accessToken,
|
|
})
|
|
```
|
|
|
|
</TabPanel>
|
|
<$Show if="sdk:dart">
|
|
<TabPanel id="dart" label="Dart">
|
|
|
|
For Flutter applications, you can link an identity using an ID token obtained from native OAuth packages like `google_sign_in` or `sign_in_with_apple`. Call [`linkIdentityWithIdToken()`](/docs/reference/dart/auth-linkidentitywithidtoken):
|
|
|
|
```dart
|
|
import 'package:google_sign_in/google_sign_in.dart';
|
|
import 'package:supabase_flutter/supabase_flutter.dart';
|
|
|
|
// First, obtain the ID token from the native provider
|
|
final GoogleSignIn googleSignIn = GoogleSignIn(
|
|
clientId: iosClientId,
|
|
serverClientId: webClientId,
|
|
);
|
|
final googleUser = await googleSignIn.signIn();
|
|
final googleAuth = await googleUser!.authentication;
|
|
|
|
// Link the Google identity to the current user
|
|
final response = await supabase.auth.linkIdentityWithIdToken(
|
|
provider: OAuthProvider.google,
|
|
idToken: googleAuth.idToken!,
|
|
accessToken: googleAuth.accessToken!,
|
|
);
|
|
```
|
|
|
|
This method supports the same OAuth providers as `signInWithIdToken()`: Google, Apple, Facebook, Kakao, and Keycloak.
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
</Tabs>
|
|
|
|
## Unlink an identity
|
|
|
|
<Tabs
|
|
scrollable
|
|
size="small"
|
|
type="underlined"
|
|
defaultActiveId="js"
|
|
queryGroup="language"
|
|
>
|
|
<TabPanel id="js" label="JavaScript">
|
|
|
|
You can use [`getUserIdentities()`](/docs/reference/javascript/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/javascript/auth-unlinkidentity) to unlink the identity. The user needs to be signed in and have at least 2 linked identities in order to unlink an existing identity.
|
|
|
|
```js
|
|
import { createClient } from '@supabase/supabase-js'
|
|
|
|
const supabase = createClient('https://your-project-id.supabase.co', 'sb_publishable_...')
|
|
|
|
// ---cut---
|
|
// retrieve all identities linked to a user
|
|
const { data: identities, error: identitiesError } = await supabase.auth.getUserIdentities()
|
|
|
|
if (!identitiesError) {
|
|
// find the google identity linked to the user
|
|
const googleIdentity = identities.identities.find((identity) => identity.provider === 'google')
|
|
|
|
if (googleIdentity) {
|
|
// unlink the google identity from the user
|
|
const { data, error } = await supabase.auth.unlinkIdentity(googleIdentity)
|
|
}
|
|
}
|
|
```
|
|
|
|
</TabPanel>
|
|
<$Show if="sdk:dart">
|
|
<TabPanel id="dart" label="Dart">
|
|
|
|
You can use [`getUserIdentities()`](/docs/reference/dart/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/dart/auth-unlinkidentity) to unlink the identity. The user needs to be signed in and have at least 2 linked identities in order to unlink an existing identity.
|
|
|
|
```dart
|
|
// retrieve all identities linked to a user
|
|
final List<UserIdentity> identities = await supabase.auth.getUserIdentities();
|
|
|
|
// find the google identity linked to the user
|
|
final UserIdentity googleIdentity =
|
|
identities.singleWhere((identity) => identity.provider == 'google');
|
|
|
|
// unlink the google identity from the user
|
|
await supabase.auth.unlinkIdentity(googleIdentity);
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:swift">
|
|
<TabPanel id="swift" label="Swift">
|
|
|
|
You can use [`getUserIdentities()`](/docs/reference/swift/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/swift/auth-unlinkidentity) to unlink the identity. The user needs to be signed in and have at least 2 linked identities in order to unlink an existing identity.
|
|
|
|
```swift
|
|
// retrieve all identities linked to a user
|
|
let identities = try await supabase.auth.userIdentities()
|
|
|
|
// find the google identity linked to the user
|
|
let googleIdentity = identities.first { $0.provider == .google }
|
|
|
|
// unlink the google identity from the user
|
|
try await supabase.auth.unlinkIdentity(googleIdentity)
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:kotlin">
|
|
<TabPanel id="kotlin" label="Kotlin">
|
|
|
|
You can use [`currentIdentitiesOrNull()`](/docs/reference/kotlin/auth-getuseridentities) to get all the identities linked to a user. Then, call [`unlinkIdentity()`](/docs/reference/kotlin/auth-unlinkidentity) to unlink the identity. The user needs to be signed in and have at least 2 linked identities in order to unlink an existing identity.
|
|
|
|
```kotlin
|
|
//get all identities linked to a user
|
|
val identities = supabase.auth.currentIdentitiesOrNull() ?: emptyList()
|
|
|
|
//find the google identity linked to the user
|
|
val googleIdentity = identities.first { it.provider == "google" }
|
|
|
|
//unlink the google identity from the user
|
|
supabase.auth.unlinkIdentity(googleIdentity.identityId!!)
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:python">
|
|
<TabPanel id="python" label="Python">
|
|
|
|
You can use [`get_user_identities()`](/docs/reference/python/auth-getuseridentities) to fetch all the identities linked to a user. Then, call [`unlink_identity()`](/docs/reference/python/auth-unlinkidentity) to unlink the identity. The user needs to be signed in and have at least 2 linked identities in order to unlink an existing identity.
|
|
|
|
```python
|
|
# retrieve all identities linked to a user
|
|
response = supabase.auth.get_user_identities()
|
|
|
|
# find the google identity linked to the user
|
|
google_identity = next((identity for identity in response.identities if identity.provider == 'google'), None)
|
|
|
|
# unlink the google identity from the user
|
|
if google_identity:
|
|
response = supabase.auth.unlink_identity(google_identity.identity_id)
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
<$Show if="sdk:csharp">
|
|
<TabPanel id="csharp" label="C#">
|
|
|
|
Use `CurrentUser.Identities` to get all the identities linked to a user. Then, call [`UnlinkIdentity()`](/docs/reference/csharp/unlink-identity) to unlink the identity. The user needs to be signed in and have at least 2 linked identities in order to unlink an existing identity.
|
|
|
|
```c#
|
|
// get all identities linked to the user
|
|
var identities = supabase.Auth.CurrentUser.Identities;
|
|
|
|
// find the google identity linked to the user
|
|
var googleIdentity = identities.First(x => x.Provider == "google");
|
|
|
|
// unlink the google identity from the user
|
|
await supabase.Auth.UnlinkIdentity(googleIdentity);
|
|
```
|
|
|
|
</TabPanel>
|
|
</$Show>
|
|
</Tabs>
|
|
|
|
## Frequently asked questions
|
|
|
|
### How to add email/password sign-in to an OAuth account?
|
|
|
|
Call the `updateUser({ password: 'validpassword'})` to add email with password authentication to an account created with an OAuth provider (Google, GitHub, etc.).
|
|
|
|
### Can you sign up with email if already using OAuth?
|
|
|
|
If you try to create an email account after previously signing up with OAuth using the same email, you'll receive an obfuscated user response with no verification email sent. This prevents user enumeration attacks.
|