Link two federated auth providers to single email account? - javascript

In firebase, I'm using their authentication and I have a need to allow users to link multiple federated auth providers to their same firebase account. This seems to work well when the user has a email/password provider, and then I want to add either Google or Microsoft provider to their account.
However, I have use case where user is using Google for Authentication and now they want to add the Microsoft Provider. Instructions are here: https://firebase.google.com/docs/auth/web/account-linking#web-version-8_1 and it seems to indicate any other providers can be added to same account.
My snippet of code to link them to Microsoft as an example is:
const LinkNewProvider = async () => {
const provider = new firebase.auth.OAuthProvider('microsoft.com');
try{
const result = firebase.auth().currentUser.linkWithPopup(provider);
var credential = result.credential;
var user = result.user;
console.log(credential);
} catch(error) {
console.log(error)
}
}
When I try this, however, I get the error back "FirebaseError: Firebase: The email address is already in use by another account. (auth/email-already-in-use)."
What am I missing? Is it possible to link multiple federated providers to single account?

Related

Error: [auth/operation-not-allowed] in authetication using firebase in react native

Error: [auth/operation-not-allowed] The given sign-in provider is disabled for this Firebase project. Enable it in the Firebase console, under the sign-in method tab of the Auth section. [ The identity provider configuration is not found. ]
Having this error even if I have enabled the google sign-in provider in my firebase app. I have rechecked my SHA1 keys, but I still, have this error. I am trying to achieve authentication using firebase in react native android application.
Library used: #react-native-firebase/auth
Apparently, the same app(code) was working until I restarted the server. Please help! I have gone through relevant posts on all media but still haven't got the solution.
async function onGoogleButtonPress() {
// Get the users ID token
const {idToken} = await GoogleSignin.signIn();
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
console.log(`CREDS ${googleCredential}`);
console.log(googleCredential);
try {
auth().signInWithCredential(googleCredential);
} catch (err) {
console.log(`Error 123 ${err}`);
}
// Sign-in the user with the credential
return;
}
onGoogleButtonPress() is the function I am using to sign in using google.

Firebase - check if user created with Google Account is signing up or logging in?

I'm trying to create a web application, where you can log-in and register an account with a google account. I have managed to make it so they can log-in with the signInWithPopup(provider), but not sure how to Implement the sign-up. Any suggestions? or know of any functions in firebase i can use?
There aren't any separate methods to login and sign up when using Google Sign-In or any other provider. If a user with that credential exists then user will be logged in else a new user account will be created. You can then use additionalUserInfo.isNewUser property from the result received from signInWithPopUp method to check if the user is new.
firebase.auth().signInWithPopup(provider).then(function (result) {
const {additionalUserInfo: {isNewUser}} = result;
console.log(isNewUser ? "This user just registered" : "Existing User")
})
For the new Modular SDK (V9.0.0+), the same can be written as:
import { signInWithPopup, getAdditionalUserInfo } from "firebase/auth"
const result = await signInWithPopup(auth, googleProvider);
// Pass the UserCredential
const { isNewUser } = getAdditionalUserInfo(result)
So far, as I understood, you have two options to log in to your website: one is to make a local username/password account on your website, and the other option is to use your google account. I suppose the best way would be to check if the Google account is linked to any existing user using additionalUserInfo.isNewUser, and then linking up your google account with the account that is created via your website locally by following this article: https://firebase.google.com/docs/auth/web/account-linking?hl=lt
Once you have Firebase dependency inside your application. You can use createUserWithEmailAndPassword method to do that.
firebase
.auth()
.createUserWithEmailAndPassword("email#domain.com", "123123")
.then(data => {
data.user.updateProfile({
displayName: this.form.name
}).then(() => {});
})
.catch(err => {
this.error = err.message;
});

Using AWS Cognito can I resolve the authenticated IdentityId given a disabled unauthenticated IdentityId?

I have a JavaScript web application that supports Cognito unauthenticated identities. I'm trying to figure out how to identify the linked authenticated IdentityId for a DISABLED unauthenticated IdentityId.
First unauthenticated users are issued an IdentityId via AWS.config.credentials.get. Internally CognitoIdentityCredentials is using getId to generate a new unauthenticated IdentityId.
let unathenticatedIdentityId;
const AWS = require('aws-sdk');
AWS.config.region = region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId
});
AWS.config.credentials.get(err => {
unathenticatedIdentityId = AWS.config.credentials.identityId;
});
Then our user authenticates to a Cognito User Pool via amazon-cognito-identity-js and the unauthenticated IdentityId changes to the authenticated IdentityId associated with their Cognito Login. The unauthenticated IdentityId is automatically marked DISABLED and is linked internally to the authenticated IdentityId.
let authenticatedIdentityId;
const { CognitoUserPool, CognitoUser, AuthenticationDetails } = require('amazon-cognito-identity-js');
const Pool = new CognitoUserPool({
UserPoolId,
ClientId,
});
const authDetails = new AuthenticationDetails({
Username,
Password,
});
const user = new CognitoUser({
Pool,
Username,
});
user.authenticateUser(authDetails, {
onSuccess: (session) => {
AWS.config.credentials.params.Logins = {
[PoolProviderName]: session.idToken.jwtToken,
};
AWS.config.credentials.expired = true;
AWS.config.credentials.refresh(err => {
authenticatedIdentityId = AWS.config.credentials.identityId;
});
},
});
I have the value for unathenticatedIdentityId and authenticatedIdentityId but I do not see a way in the AWS Cognito API's to resolve that the DISABLED unauthenticatedIdentityId has been linked to the authenticatedIdentityId. Conversely I do not see a way to identify what IdentityIds have been linked to the authenticatedIdentityId. The describeIdentity API will tell me that unauthenticatedIdentityId is DISABLED and that it has no Logins, but it does not point to the linked authenticatedIdentityId.
How can I, with only the value of the linked/DISABLED unauthenticatedIdentityId, resolve the value authenticatedIdentityId?
I have an app that uses AWS Cognito to obtain an identity id and then possibly authenticate it. The situation is a client uses the app first as unauthenticated (guest) and then logs in using Facebook, making him/herself as authenticated, and AWS preserves the given identity ID for the authenticated user, because he is a new user. Now, the problem comes, when you log out of the app and someone else wants to use this app as unauthenticated or even authenticated. Cognito will error out saying that the access to the identity ID is forbidden, because it has already been linked to the previous user's Facebook account.
The Cognito mobile SDKs have a way built in to handle this. They cache the identity id when using it, which is causing the issue you are seeing. When you log out, you'll want to clear that cache. I'm not sure which SDK you're using, but in iOS it's AWSCognitoIdentityProvider.clear() and CognitoCachingCredentialsProvider.clear() in Android. Similarly, if you're using Cognito Sync, there's a method in that client that will wipe the cached id and sync data.
Also have a look at https://aws.amazon.com/blogs/mobile/understanding-amazon-cognito-authentication/
Hope you are also following https://aws.amazon.com/blogs/mobile/using-the-amazon-cognito-credentials-provider/

Firebase: recent login requested

I'm dealing with Firebase authentication for web.
The documentation states that
Some security-sensitive actions—such as deleting an account, setting a primary email address, and changing a password—require that the user has recently signed in.
If not, the request would fail with error code auth/requires-recent-login and I should manage the case by prompting the user to re-insert her credentials. Once I have done that, I could easily re-authenticate the user with the following code:
firebase.auth().currentUser.reauthenticate(credential)
In the API reference there's some details more. It turns out credential is actually an object of type firebase.auth.AuthCredential. That being said, I still have a bunch of questions to which I couldn't find answer on the docs:
How do I create the AuthCredential object?
More importantly, how do I deal with providers (Google, Facebook, ...). I agree that changing email/password doesn't make sense for providers, because this is not the right place to change them, so re-authentication does not apply in this case. However, deleting a user is still an action requiring re-authentication, and this could be performed regardless of the authentication method. How do I re-authenticate a user that logged in with a provider?
The documentation states that the user must have logged in recently. I couldn't find any definition of recent in the docs.
You can initialize a credential by calling credential static method on any provider (include email/password provider):
firebase.auth.FacebookAuthProvider.credential(fbAccessToken);
To reauthenticate an OAuth provider, you can call in a browser signInWithPopup or redirect. This will return an object with 2 fields: user and credential. You can use that credential directly. Here is a simplified example:
var tempApp = firebase.initializeApp(originalConfig, 'temp');
var provider = new firebase.auth.FacebookAuthProvider();
tempApp.signInWithPopup(provider).then(function(result)) {
tempApp.auth().signOut();
originalApp.auth().currentUser.reauthenticate(credential);
});
That doesn't matter, as the firebase auth backend could change that. You shouldn't hard code this value. Instead try to catch that error and act appropriately when it happens.
You should reauthenticate with the provider;
import { getAuth, signInWithPopup, reauthenticateWithPopup, GoogleAuthProvider } from "firebase/auth";
const loginAuth = getAuth();
const googleProvider = new GoogleAuthProvider();
function reauthWithGoogle() {
return reauthenticateWithPopup(loginAuth, googleProvider)
}
and when you get the auth/requires-recent-login error call that function;
updatePassword(currentUser, "new password")
.catch(e => reauthWithGoogle()) //better check if the error is auth/requires-recent-login

Link Facebook to Firebase Anonymous Auth without calling Facebook API

I am creating anonymous sessions in my Firebase application to save user data before they create their accounts. I saw that Firebase allows linking a Facebook login to an anonymous account which sounds really neat, but a caveat of this process seems to be that I have to grab the Facebook token myself, outside the warmth and comfort of the awesome Firebase API, which seems strangely un-developed given how much of the login flow Firebase seems to do on behalf of apps.
A code sample of how to connect an anonymous account from their account linking docs:
var credential = firebase.auth.FacebookAuthProvider.credential(
response.authResponse.accessToken);
Naturally, I want to use Firebase's way of getting a token
var provider = new firebase.auth.FacebookAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
// result.token or whatever would appear here
});
But if I were to run that, I would lose my anonymous session (and my anonymous user ID, which we want the new Facebook login to use).
Is there anyway to get a Facebook Token out of Firebase's auth mechanism without logging the user in and losing the anonymous session that I'm trying to convert into a Facebook Login-able account? (The goal is to not have to call the Facebook API myself, especially as I'll be adding Google here as well)
I think you're looking to #linkWithPopup or #linkWithRedirect:
var provider = new firebase.auth.FacebookAuthProvider();
user.linkWithPopup(provider).then(function(result) {
console.log('Party 🎉');
});
If for some reason that doesn't cut it, you could always opt to do yourself:
Sign in the user anonymously, and store the user somewhere
Sign in the user with the provider and store the token somewhere
Delete the provider user and then link the account with the token
Quick and dirty example:
var googleToken;
var anonUser;
firebase.auth().signInAnonymously().then(function(user) {
anonUser = user;
}).catch(function(error) {
console.error("Anon sign in failed", error);
});
function signInWithGoogle() {
var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider).then(function(result) {
googleToken = result.credential.idToken;
}).catch(function(error) {
console.error("Google sign in failed", error);
})
}
function deleteAndLink() {
firebase.auth().currentUser.delete().then(function() {
var credential =
firebase.auth.GoogleAuthProvider.credential(googleToken);
anonUser.link(googleCredential);
}).then(function() {
console.log("Link succeeded");
}).catch(function(error) {
console.error("Something went wrong", error);
});
}

Categories

Resources