Vincular varios proveedores a una cuenta
En este documento se explica cómo vincular varios proveedores a una sola cuenta de Identity Platform.
Identity Platform usa un ID único para identificar a los usuarios. De esta forma, los usuarios pueden iniciar sesión en la misma cuenta con diferentes proveedores. Por ejemplo, un usuario que se haya registrado inicialmente con un número de teléfono podría vincular posteriormente su cuenta de Google y, después, usar cualquiera de los dos métodos para iniciar sesión.
Antes de empezar
Añade compatibilidad con dos o más proveedores de identidades a tu aplicación.
Habilitar o inhabilitar la vinculación de cuentas
El ajuste de vinculación de cuentas determina cómo gestiona Identity Platform a los usuarios que intentan iniciar sesión con el mismo correo mediante distintos proveedores.
Vincular cuentas que usan el mismo correo: Identity Platform mostrará un error si un usuario intenta iniciar sesión con un correo que ya está en uso. Tu aplicación puede detectar este error y vincular el nuevo proveedor a la cuenta que ya tiene el usuario.
Crear varias cuentas para cada proveedor de identidades: se creará una nueva cuenta de usuario de Identity Platform cada vez que un usuario inicie sesión con un proveedor diferente.
Para elegir un ajuste, sigue estos pasos:
Ve a la página Configuración de Identity Platform en laGoogle Cloud consola.
Seleccione una opción en Vinculación de cuentas de usuario.
Haz clic en Guardar.
Vincular credenciales de proveedor federado
Para vincular credenciales de un proveedor federado, sigue estos pasos:
Inicia la sesión del usuario con cualquier proveedor o método de autenticación.
Obtén el objeto de proveedor que corresponda al proveedor que quieras vincular a la cuenta del usuario. Por ejemplo:
Versión web 9
import { GoogleAuthProvider, FacebookAuthProvider, TwitterAuthProvider, GithubAuthProvider } from "firebase/auth"; const googleProvider = new GoogleAuthProvider(); const facebookProvider = new FacebookAuthProvider(); const twitterProvider = new TwitterAuthProvider(); const githubProvider = new GithubAuthProvider();
Versión web 8
var googleProvider = new firebase.auth.GoogleAuthProvider(); var facebookProvider = new firebase.auth.FacebookAuthProvider(); var twitterProvider = new firebase.auth.TwitterAuthProvider(); var githubProvider = new firebase.auth.GithubAuthProvider();
Pide al usuario que inicie sesión con el proveedor que quieras vincular. Puedes abrir una ventana emergente o redirigir la página actual. La redirección es más sencilla para los usuarios de dispositivos móviles.
Para mostrar una ventana emergente, llama a
linkWithPopup()
:Versión web 9
import { getAuth, linkWithPopup, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); const auth = getAuth(); linkWithPopup(auth.currentUser, provider).then((result) => { // Accounts successfully linked. const credential = GoogleAuthProvider.credentialFromResult(result); const user = result.user; // ... }).catch((error) => { // Handle Errors here. // ... });
Versión web 8
auth.currentUser.linkWithPopup(provider).then((result) => { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... }).catch((error) => { // Handle Errors here. // ... });
Para redirigir la página, primero llama a
linkWithRedirect()
:Sigue las prácticas recomendadas cuando uses
signInWithRedirect
,linkWithRedirect
oreauthenticateWithRedirect
.Versión web 9
import { getAuth, linkWithRedirect, GoogleAuthProvider } from "firebase/auth"; const provider = new GoogleAuthProvider(); const auth = getAuth(); linkWithRedirect(auth.currentUser, provider) .then(/* ... */) .catch(/* ... */);
Versión web 8
auth.currentUser.linkWithRedirect(provider) .then(/* ... */) .catch(/* ... */);
Una vez que el usuario haya iniciado sesión, se le redirigirá a tu aplicación. A continuación, puedes obtener el resultado de inicio de sesión llamando a
getRedirectResult()
:Versión web 9
import { getRedirectResult } from "firebase/auth"; getRedirectResult(auth).then((result) => { const credential = GoogleAuthProvider.credentialFromResult(result); if (credential) { // Accounts successfully linked. const user = result.user; // ... } }).catch((error) => { // Handle Errors here. // ... });
Versión web 8
auth.getRedirectResult().then((result) => { if (result.credential) { // Accounts successfully linked. var credential = result.credential; var user = result.user; // ... } }).catch((error) => { // Handle Errors here. // ... });
La cuenta del usuario con el proveedor federado ahora está vinculada a su cuenta de Identity Platform y puede usar el proveedor para iniciar sesión.
Vincular credenciales de correo y contraseña
Para añadir una dirección de correo y una contraseña a una cuenta de usuario ya creada, sigue estos pasos:
Inicia la sesión del usuario con cualquier proveedor de identidades o método.
Pide al usuario una dirección de correo y una contraseña.
Crea un objeto
AuthCredential
con la dirección de correo y la contraseña:Versión web 9
import { EmailAuthProvider } from "firebase/auth"; const credential = EmailAuthProvider.credential(email, password);
Versión web 8
var credential = firebase.auth.EmailAuthProvider.credential(email, password);
Pasa el objeto
AuthCredential
al métodolinkWithCredential()
del usuario que ha iniciado sesión:Versión web 9
import { getAuth, linkWithCredential } from "firebase/auth"; const auth = getAuth(); linkWithCredential(auth.currentUser, credential) .then((usercred) => { const user = usercred.user; console.log("Account linking success", user); }).catch((error) => { console.log("Account linking error", error); });
Versión web 8
auth.currentUser.linkWithCredential(credential) .then((usercred) => { var user = usercred.user; console.log("Account linking success", user); }).catch((error) => { console.log("Account linking error", error); });
Las credenciales de correo y contraseña ahora están vinculadas a la cuenta de Identity Platform del usuario, que puede usarlas para iniciar sesión.
Ten en cuenta que una credencial de proveedor federado se puede vincular a una cuenta de correo o contraseña con un correo diferente. Si esto ocurre, se puede usar el correo correspondiente al proveedor federado para crear una cuenta independiente con correo y contraseña.
Gestionar el error "account-exists-with-different-credential"
Si has habilitado el ajuste Vincular cuentas que usan el mismo correo en la consolaGoogle Cloud , cuando un usuario intente iniciar sesión en un proveedor (como SAML) con un correo que ya exista en otro proveedor (como Google), se mostrará el error auth/account-exists-with-different-credential
(junto con un objeto AuthCredential
).
Para gestionar este error, pide al usuario que inicie sesión con el proveedor actual.
A continuación, llama a linkWithCredential()
, linkWithPopup()
o linkWithRedirect()
para asociar el nuevo proveedor a su cuenta mediante AuthCredential
.
En el siguiente ejemplo se muestra cómo gestionar este error cuando un usuario intenta iniciar sesión con Facebook:
Versión web 9
import { signInWithPopup, signInWithEmailAndPassword, linkWithCredential } from "firebase/auth"; // User tries to sign in with Facebook. signInWithPopup(auth, facebookProvider).catch((error) => { // User's email already exists. if (error.code === 'auth/account-exists-with-different-credential') { // The pending Facebook credential. const pendingCred = error.credential; // The provider account's email address. const email = error.customData.email; // Present the user with a list of providers they might have // used to create the original account. // Then, ask the user to sign in with the existing provider. const method = promptUserForSignInMethod(); if (method === 'password') { // TODO: Ask the user for their password. // In real scenario, you should handle this asynchronously. const password = promptUserForPassword(); signInWithEmailAndPassword(auth, email, password).then((result) => { return linkWithCredential(result.user, pendingCred); }).then(() => { // Facebook account successfully linked to the existing user. goToApp(); }); return; } // All other cases are external providers. // Construct provider object for that provider. // TODO: Implement getProviderForProviderId. const provider = getProviderForProviderId(method); // At this point, you should let the user know that they already have an // account with a different provider, and validate they want to sign in // with the new provider. // Note: Browsers usually block popups triggered asynchronously, so in // real app, you should ask the user to click on a "Continue" button // that will trigger signInWithPopup(). signInWithPopup(auth, provider).then((result) => { // Note: Identity Platform doesn't control the provider's sign-in // flow, so it's possible for the user to sign in with an account // with a different email from the first one. // Link the Facebook credential. We have access to the pending // credential, so we can directly call the link method. linkWithCredential(result.user, pendingCred).then((userCred) => { // Success. goToApp(); }); }); } });
Versión web 8
// User tries to sign in with Facebook. auth.signInWithPopup(facebookProvider).catch((error) => { // User's email already exists. if (error.code === 'auth/account-exists-with-different-credential') { // The pending Facebook credential. const pendingCred = error.credential; // The provider account's email address. const email = error.email; // Present the user with a list of providers they might have // used to create the original account. // Then, ask the user to sign in with the existing provider. const method = promptUserForSignInMethod(); if (method === 'password') { // TODO: Ask the user for their password. // In real scenario, you should handle this asynchronously. const password = promptUserForPassword(); auth.signInWithEmailAndPassword(email, password).then((result) => { return result.user.linkWithCredential(pendingCred); }).then(() => { // Facebook account successfully linked to the existing user. goToApp(); }); return; } // All other cases are external providers. // Construct provider object for that provider. // TODO: Implement getProviderForProviderId. const provider = getProviderForProviderId(method); // At this point, you should let the user know that they already have an // account with a different provider, and validate they want to sign in // with the new provider. // Note: Browsers usually block popups triggered asynchronously, so in // real app, you should ask the user to click on a "Continue" button // that will trigger signInWithPopup(). auth.signInWithPopup(provider).then((result) => { // Note: Identity Platform doesn't control the provider's sign-in // flow, so it's possible for the user to sign in with an account // with a different email from the first one. // Link the Facebook credential. We have access to the pending // credential, so we can directly call the link method. result.user.linkWithCredential(pendingCred).then((userCred) => { // Success. goToApp(); }); }); } });
Usar una redirección es similar a una ventana emergente, pero tendrás que almacenar en caché la credencial pendiente entre las redirecciones de página (por ejemplo, mediante el almacenamiento de sesión).
Ten en cuenta que algunos proveedores, como Google y Microsoft, actúan como proveedores de correo electrónico y de identidad social. Los proveedores de correo se consideran autoritativos para todas las direcciones relacionadas con su dominio de correo alojado. Esto significa que un usuario que inicie sesión con una dirección de correo alojada por el mismo proveedor nunca recibirá este error (por ejemplo, si inicia sesión con Google usando un correo de @gmail.com
o con Microsoft usando un correo de @live.com
o @outlook.com
).
Combinar cuentas manualmente
Si un usuario intenta iniciar sesión con credenciales que ya están vinculadas a otra cuenta de usuario con el mismo proveedor, los métodos integrados del SDK de cliente para vincular cuentas fallarán. En esta situación, tendrás que fusionar las cuentas manualmente y, después, eliminar la segunda cuenta. Por ejemplo:
Versión web 9
// Sign in first account.
const result1 = await signInWithCredential(auth, cred1);
const user1 = result1.user;
// Try to link a credential that belongs to an existing account
try {
await linkWithCredential(user1, cred2);
} catch (error) {
// cred2 already exists so an error is thrown.
const result2 = await signInWithCredential(auth, error.credential);
const user2 = result2.user;
// Merge the data.
mergeData(user1, user2);
// Delete one of the accounts, and try again.
await user2.delete();
// Linking now will work.
await linkWithCredential(user1, result2.credential);
}
Versión web 8
// Sign in first account.
const result1 = await auth.signInWithCredential(cred1);
const user1 = result1.user;
// Try to link a credential that belongs to an existing account
try {
await user1.linkWithCredential(cred2);
} catch (error) {
// cred2 already exists so an error is thrown.
const result2 = await auth.signInWithCredential(error.credential);
const user2 = result2.user;
// Merge the data.
mergeData(user1, user2);
// Delete one of the accounts, and try again.
await user2.delete();
// Linking now will work.
await user1.linkWithCredential(result2.credential);
}
Desvincular un proveedor
Puedes desvincular un proveedor de la cuenta de un usuario. El usuario ya no podrá autenticarse con ese proveedor.
Para desvincular un proveedor, pasa el ID del proveedor al método unlink()
.
Puede obtener los IDs de los proveedores de autenticación vinculados a un usuario desde la propiedad providerData
.
Versión web 9
import { getAuth, unlink } from "firebase/auth"; const auth = getAuth(); unlink(auth.currentUser, providerId).then(() => { // Auth provider unlinked from account // ... }).catch((error) => { // An error happened // ... });
Versión web 8
user.unlink(providerId).then(() => { // Auth provider unlinked from account // ... }).catch((error) => { // An error happened // ... });
Siguientes pasos
- Añade compatibilidad con diferentes proveedores de identidades a tu aplicación.
- Consulta cómo gestionar proveedores mediante programación.