Firebase Authentication - Linking other auth providers - javascript

I am working with firebase authentication in web and ran into a problem. I signed in a user using google and now i also want the user to create a password so that he can login with email and password.
So basically i want to link both of them.
I tried firebase.auth.createUserWithEmailAndPassword(userEmail, newpassword) but it throws an error "email-already-in-use" which is correct because i signed in with google first.
Is there any way i can link these?

Here is an example how to link an email/password credential to an existing user (note you can also just user updatePassword)
// Email/Password credential. Similar logic can be used for linking
// other credentials.
var cred = firebase.auth.EmailAuthProvider.credential(
firebase.auth().currentUser.email, 'password');
firebase.auth().currentUser.linkWithCredential(cred)
.then(function() {
// Credential successfully linked.
})
.catch(function(error) {
// Some error occurred.
});

Check the docs: Link Multiple Auth Providers to an Account Using JavaScript

Related

Firebase authentication error: auth/invalid-credential

I've been experimenting with the authentication service provided by firebase for more than 2 weeks. Everything was perfectly working until yesterday it became impossible for me to use the facebook auth provider neither twitter to make users connect to my web app.
I've tried to sign out and sign in, I deleted my facebook and twitter apps and created others even with other accounts and the problem persists.
The same problem occurred when I tried to use the code they provide on their github which was working before.
The strange thing is that it's working fine when I use the google provider or the sign in with email and password method.
PS: I made sure the providers are enabled in the console.
const signInWithFacebookButton = document.getElementById('signInWithFacebook');
const auth = firebase.auth();
const signInWithFacebook = () => {
const facebookProvider = new firebase.auth.FacebookAuthProvider();
auth.signInWithPopup(facebookProvider)
.then(() => {
console.log('Successfully signed in');
})
.catch(error => {
console.error(error);
})
}
signInWithFacebookButton.addEventListener('click', signInWithFacebook);
Error message when I try to authenticate using facebook :
{code: "auth/invalid-credential", message: "The supplied auth credential is malformed or has expired."}
Error message when I try to authenticate using twitter:
{code: "auth/invalid-credential", message: "Error getting request token: 403 <?xml version="1.…ode-project-fd88e.firebaseapp.com/__/auth/handler"}
For Twitter login, the error code 403 indicates that access to the URL by the client is Forbidden. It gives such an error because you have to whitelist callback URLs(your site).
From documentation,
As part of our continued effort to ensure safety and security on the Twitter developer platform, any developer using Sign in with Twitter must explicitly declare their callback URLs in a whitelist in the Twitter apps settings which can be accessed in the apps dashboard when logged into your Twitter account on developer.twitter.com. This means that if the callback_url parameter used with the oauth/request_token endpoint isn't whitelisted, you will receive an error.
So in Twitter app settings, you have to add your URL say for example,
https://sitename.example.com/auth/twitter and https://sitename.example.com/auth/twitter/callback
You want to use https://yourdomain.com?source=twitter as your callback URL
Add this to the Twitter app dashboard: https://yourdomain.com
Use this in your call to oauth/request_token: https://yourdomain.com?source=twitter.
Refer this community article for more detail:-
Twitter callback URLs
This is worth as an answer: Always click to show your Facebook app secret before copying and pasting it into Firebase setting console. It is counter-intuitive, but Facebook did not implement the clipboard correctly so the hidden asterisk characters will just be copied and pasted verbatim.

Sending ID token to signInSuccessUrl in firebaseui

I'm using firebaseUI to sign in users to my web app. I am using the redirect option. Upon successful sign in, the users are redirected to signInSuccessUrl, which is the admin page of my web app. However, I want to be able to pass the ID token associated with the user to the admin endpoint, where it can be authenticated and checked whether the user trying to log in has admin permissions or not (this I do by checking the user permissions in my database).
I've considered a few other options, namely:
Using firebase.auth().onAuthStateChanged on the admin page itself, checking if the user is signed in, and making a request to the backend to check if the user is an admin. If these conditions are met, render the page, otherwise, show permission denied.
The problem with this approach is that:
It moves a significant part of the auth to the client side
I can't restrict access at the endpoint level itself. In contrast, if I send an ID token, I can check if the user is an admin or not and accordingly decide what to render, instead of always rendering the admin page and then checking on the client side if the user is logged in and is an admin.
Making a dummy page in between the firebase sign-in page and the admin home page. This dummy page would check if the user is signed in using onAuthStateChanged as mentioned above, make a request to the backend to check if the user has admin permissions, and based on the results, redirect to either the admin home page or show permission denied and go back to the login page.
This is how the config would look like if I do this:
var uiConfig = {
signInSuccessUrl: '/admintestpage/',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID
]
}
The /admintestpage/ endpoint would render test.html, which would have code something like:
<script type="text/javascript">
initApp = function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
idToken = user.getIdToken();
/*Send idToken to a backend api to check if the corresponding user is an admin*/
/*redirect to https://my-app.com/adminpage/ if user is an admin, otherwise, redirect to https://my-app.com/login/ */
} else {
/*user is signed-off, redirect to https://my-app.com/login */
}
}
</script>
I'm keeping this as the last option as it doesn't look like a very good flow.
Here's how my uiConfig looks right now:
var uiConfig = {
signInSuccessUrl: '/adminpage/',
signInOptions: [
firebase.auth.GoogleAuthProvider.PROVIDER_ID
]
}
The Crux is that I want to render my admin home page only if I know beforehand that the user is logged in and is an admin.
I want to know if there is a way to pass the ID token as a basic auth header when redirecting to the signInSuccessUrl from the firebaseUI page, or if the idea of sending an ID token itself is not necessary and there is an alternate better flow.
I think you're on the right track. I've been struggling to find something elegant to do this as well, but I ended up doing what you did. Ideally I wish signInSuccessUrl passed the jwt payload, therefore, my backend server could verify its authenticity, and I can then look up the user and then set the session or reject the session.
A lot of the API's and docs are written in the context of a "Firebase first" or "Firebase only" so you have to start getting creative integrating with a traditional REST API.
My context is somewhat similar. I'm a mobile-only app that used Firebase auth to offload auth, in exchange, it then linked to my own custom token. Recently I needed to make a few web properties and wanted to implement this same exchange for my own session management in a traditional client/server synchronous REST page.
window.initApp = function() {
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
// User is signed in.
user.getIdToken().then(function(accessToken) {
redirectPost("/login", {"access_token": accessToken, "authenticity_token": $("meta[name='csrf-token']").attr('content')})
});
} else {
// User is signed out.
}
}, function(error) {
console.log(error);
});
};

Firebase 'requires-recent-login'

I would like to know about firebase requires-recent-login.
If I reauthenticate user like this
firebase.auth().currentUser.reauthenticateAndRetrieveDataWithCredential(
firebase.auth.EmailAuthProvider.credential(firebase.auth().currentUser.email,
typedpassword))
to let user change password or email, is there any possibility that requires-recent-login error comes out?
Some actions require recent authentication and it fails with a auth/requires-recent-login error code.
One action that requires recent authentication is the updating of email.
The solution is to reauthenticate the user, before retrying the action.

How to get user_likes after firebaseauth-ui call is successful with user_likes permission approved on facebook

I am working on a login flow with FirebaseUI for web.
Facebook provider is invoked with scope(permission) user_likes.
After user approves the app and permissions, login is successful.
However, I am now wondering how to retrieve the user_likes via a graph API call to facebook directly.
Essentially, where to retrieve the required parameters from successful firebase auth so as to make a successful graph api retrieving user_likes list.
You need to get the facebook auth credential from the signInSuccess callback. You can then use the OAuth credential to query the facebook api:
'callbacks': {
'signInSuccess': function(currentUser, credential, redirectUrl) {
// Do something.
// Return type determines whether we continue the redirect automatically
// or whether we leave that to developer to handle.
// Credential is in credential.accessToken
return false;
}
}

Error when authenticating with Firebase OauthToken method

I am trying to authenticate a user in my ionic app using the authWithOAuthToken() method in Firebase. I am getting this error -> {"code":"INVALID_CREDENTIALS","details":"{\"providerErrorInfo\":{}}"} with my firebase ref, when I try with another firebase ref, it works.
In Firebase Error Listing, INVALID CREDENTIALS means
The specified authentication credentials are invalid. This may occur when credentials are malformed or expired.
But I am not passing any credential to the method
var Ref = new Firebase('https://<firebase-ref>.firebaseio.com');
Ref.authWithOAuthToken('facebook', '<facebook token>', function(error, authData) {
if (error) {
console.log('Login Failed!', JSON.stringify(error));
} else {
console.log('Authenticated successfully with payload:', authData);
}
});
Anybody encountered this before?
Go to Facebook Tab inside Login & Auth in firebase project, Copy and paste Credentials from your facebook developer app and try running your app, if you have already entered your details, make sure they are correct , if it still doesn't work check by creating a new facebook developer app and again enter the details in firebase

Categories