apps/docs/content/guides/auth/auth-identity-linking.mdx
Currently, Supabase Auth supports 2 strategies to link an identity to a user:
Supabase Auth automatically links identities with the same email address to a single user. This helps to improve the user experience when multiple OAuth login 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.
Users that signed up with SAML SSO will not be considered as targets for automatic linking.
<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 logged in. To link an OAuth identity to the user, call linkIdentity():
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-supabase-url>', '<your-supabase-anon-key>')
// ---cut---
const { data, error } = await supabase.auth.linkIdentity({ provider: 'google' })
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call linkIdentity():
await supabase.auth.linkIdentity(OAuthProvider.google);
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call linkIdentity():
try await supabase.auth.linkIdentity(provider: .google)
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call linkIdentity():
supabase.auth.linkIdentity(Google)
Supabase Auth allows a user to initiate identity linking with a different email address when they are logged in. To link an OAuth identity to the user, call link_identity():
response = supabase.auth.link_identity({'provider': 'google'})
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 or by setting the environment variable GOTRUE_SECURITY_MANUAL_LINKING_ENABLED: true when self-hosting.
<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.
// 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,
})
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():
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.
<Tabs scrollable size="small" type="underlined" defaultActiveId="js" queryGroup="language"
<TabPanel id="js" label="JavaScript">
You can use getUserIdentities() to fetch all the identities linked to a user. Then, call unlinkIdentity() to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
import { createClient } from '@supabase/supabase-js'
const supabase = createClient('<your-supabase-url>', '<your-supabase-anon-key>')
// ---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)
}
}
You can use getUserIdentities() to fetch all the identities linked to a user. Then, call unlinkIdentity() to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
// 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);
You can use getUserIdentities() to fetch all the identities linked to a user. Then, call unlinkIdentity() to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
// 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)
You can use currentIdentitiesOrNull() to get all the identities linked to a user. Then, call unlinkIdentity() to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
//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!!)
You can use get_user_identities() to fetch all the identities linked to a user. Then, call unlink_identity() to unlink the identity. The user needs to be logged in and have at least 2 linked identities in order to unlink an existing identity.
# 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)
Call the updateUser({ password: 'validpassword'}) to add email with password authentication to an account created with an OAuth provider (Google, GitHub, etc.).
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.