I've set-up a Firebase project which I am using for it's user authentication module. I am also using the firebaseui-web project from Github.
My redirect on sign-on is working fine per this code:
// FirebaseUI config.
var uiConfig = {
'signInSuccessUrl': 'MY_REDIRECT.html',
'signInOptions': [
firebase.auth.EmailAuthProvider.PROVIDER_ID
],
// Terms of service url.
'tosUrl': '<your-tos-url>',
};
When the page loads (i.e. MY_REDIRECT.html) I'm checking the status of the user to see if they have verified their e-mail, and if not then invoke the sendEmailVerification method:
checkLoggedInUser = function() {
auth.onAuthStateChanged(function(user) {
if (user) {
// is email verified
if(user.emailVerified) {
// show logged in user in UI
$('#loggedinUserLink').html('Logged in:' + user.email + '<span class="caret"></span>');
} else {
// user e-mail is not verified - send verification mail and redirect
alert('Please check your inbox for a verification e-mail and follow the instructions');
// handle firebase promise and don't redirect until complete i.e. .then
user.sendEmailVerification().then(function() {
window.location.replace('index.html');
});
}
} else {
// no user object - go back to index
window.location.replace("index.html");
}
}, function(error) {
console.log(error);
});
};
window.onload = function() {
checkLoggedInUser()
};
All good so far - Firebase is doing what I want! Thanks guys :)
However, in the Firebase Console UI there doesn't appear to be a way of seeing if a user actually went to their inbox and clicked on the link to perform the verification. The UI looks like this:
I've run basic tests and the User UID doesn't change before and after verification has taken place.
So, here's my question - did I go about the e-mail verification correctly? If so (and therefore the UI doesn't show me verified vs unverified) is there an accepted method of accessing these two sets of users in the Auth module? I can't see the way to access the underlying table of UIDs and their properties (including the emailVerified property). I don't mind having to write more code if the functionality isn't in the Console - just looking to get nudged in the correct direction for my next step.
There is currently no way in the Firebase Console to see whether a specific user's email address has been verified. There is an API to get a list of users, but you can't filter on whether they're verified or not.
You can check whether the currently authenticated user's email address is verified with:
firebase.auth().currentUser.emailVerified
You cannot prevent who signs up. But you can easily ensure that only users with a verified email address can access (certain) data. For example:
{
"rules": {
".read": "auth != null && auth.token.email_verified",
"gmailUsers": {
"$uid": {
".write": "auth.token.email_verified == true &&
auth.token.email.matches(/.*#gmail.com$/)"
}
}
}
}
The above rules ensure that only users with a verified email address can read any data and only users with a verified gmail address can write under gmailUsers.
Related
Action:
- signInWithPhoneNumber(NUMBER NOT IN DB, recaptchaVerifier)
Expected Behavior:
- Since number not in DB, it should not log me in.
Current Behavior:
- If the number does not exist in DB, it CREATES a new user after going through recaptcha + sms verification. WHY?
Code:
function loginWithSMS(phoneNumber) {
firebase.auth().useDeviceLanguage();
//#ts-ignore
window.recaptchaVerifier = new firebase.auth.RecaptchaVerifier("recaptcha-container");
//#ts-ignore
window.recaptchaVerifier.render().then(function (widgetId) {
//#ts-ignore
window.recaptchaWidgetId = widgetId;
});
// #ts-ignore
firebase
.signInWithPhoneNumber(phoneNumber, window.recaptchaVerifier)
.then((confirmationResult) => {
console.log("Login success", confirmationResult);
window.recaptchaVerifier.clear();
// SMS sent. Prompt user to type the code from the message, then sign the
// user in with confirmationResult.confirm(code).
const verificationCode = window.prompt(
"Please enter the verification " + "code that was sent to your mobile device."
);
return confirmationResult.confirm(verificationCode);
})
.catch((error) => {
console.error(error);
// Error; SMS not sent
// Handle Errors Here
window.recaptchaVerifier.clear();
return Promise.reject(error);
});
}
This is just how the API is defined: by sending a text to the number, Firebase allows the user to verify that they have access to that phone number. If they do, they're allowed to sign in.
This is the same for the email+password provider in Firebase Authentication. Calling firebase.auth().createUserWithEmailAndPassword(email, password) creates the user, even if they didn't exist yet. And while your code may not call this API, any developer can take the Firebase configuration data from your app and call the API themselves.
Most often when developers are asking about this they're confusing authentication with authorization.
When you authenticate, you are proving that you are you. So in the examples above, that you have access to a certain phone number, or that you know the email+password combination of the account.
Based on knowing who the user is, the application then authorizes that user to perform certain actions or to access certain data.
For example, if you're using Realtime Database, Cloud Storage, or Cloud Firestore, you can control access with Firebase's server-side security rules.
If you have a different back-end, you'd control it there by checking the information in the ID token of the user (which you get from Firebase Authentication) against some set of authorization rules for your application.
Also see:
Prevent user account creation with sign in by email in firestore (similar question, but then for passwordless email signin)
How to disable Signup in Firebase 3.x
How does the firebase authentication and realtime application database secure itself?
I'm trying to disable the verification process for some users that I register myself(admin).
I've added the pre-signup lambda like the documentation says:
```exports.handler = (event, context, callback) => {
// Confirm the user
event.response.autoConfirmUser = true;
// Set the email as verified if it is in the request
if (event.request.userAttributes.hasOwnProperty("email")) {
event.response.autoVerifyEmail = true;
}
// Set the phone number as verified if it is in the request
if (event.request.userAttributes.hasOwnProperty("phone_number")) {
event.response.autoVerifyPhone = true;
}
// Return to Amazon Cognito
callback(null, event);
};
And the email verification is still coming to the user.
I've also tried using the adminConfirmSignUp api to confirm the user right after I create it with adminCreateUser. But this is the error i'm getting when using the adminConfirmSignUp
{ NotAuthorizedException: User cannot be confirmed. Current status is FORCE_CHANGE_PASSWORD
Is there any other way that I can make it to not send the verification email to some users?
I got this to working by just including these 2 properties inside the request when creating the user.
DesiredDeliveryMediums: [],
MessageAction: "SUPPRESS"
No need for pre-signup lambda.
I have a web app built on Firebase's web library. I want to restrict some pages to only users who are logged in.
This code triggers when firebase detects the user is logged in, which is good.
firebase.auth().onAuthStateChanged(function (user) {
console.log('User is logged in');
});
But I can't get anything to reliably check whether the user is not logged in without leaving the page before the above code has a chance to check...
var check_firebaseReady == false;
function local_initApp() {
if (check_firebaseReady == false) {
if (typeof firebase !== 'undefined') {
check_firebaseReady = true;
console.log(firebase.auth().currentUser); //not reliable becuase it may return an empty user before it has a chance to get an existing user
}
setTimeout(function () {
local_initApp();
}, 300);
}
}
local_initApp();
I think for single page apps, you have to use the onAuthStateChanged listener and enforce access via security rules on specific data. If you want to block access to a complete page, you are better off using a cookie system. Firebase Auth provides that option: https://firebase.google.com/docs/auth/admin/manage-cookies
With cookies, you would check and verify the cookie server side, otherwise, not serve the page and show some error or redirect to login page instead.
I came across this openFB plugin to make facebook requests without the sdk, that can be used in cordova,
I got it to log in the user in facebook, the thing is as oauthRedirectURL I end up in a white page, that says Success and I'm not sure how to get the user back to the app,
if (runningInCordova) {
oauthRedirectURL = "https://www.facebook.com/connect/login_success.html";
}
Question is,
What url can i use to point my app ?
User ends up in this screen after the login
-edit-
I found solutions like http://localhost.com/oauthcallback.html but I don't have a apache2 in the cordova environament..
-2nd edit-
This is my current code,
openFB.init({appId: 'xxxxxxxxyyyyyyyy'});
openFB.login( function(response) {
if(response.status === 'connected') {
alert('Facebook login succeeded, got access token: ' + response.authResponse.token);
} else {
alert('Facebook login failed: ' + response.error);
}
}, {scope: 'email'});
This the line of the lib that fills this value
if (runningInCordova) {
oauthRedirectURL = "https://www.facebook.com/connect/login_success.html";
}
I haven't used openFB before but I'm pretty sure it's based on the following docs:
https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.3
If you go to the section "logging people in" you'll see the following message:
redirect_uri. The URL that you want to redirect the person logging in
back to. This URL will capture the response from the Login Dialog. If
you are using this in a webview within a desktop app, this must be set
to https://www.facebook.com/connect/login_success.html.
When a FB user grants permissions to your App, it will be redirected to the url https://www.facebook.com/connect/login_success.html?access_token=new_token&...
What you have to do now is monitor this url and get the access token provided, which you should store with the fb user id in order to perform any API call.
Googling how to do this with openFB I found a thread at the openFB github repo that should help: https://github.com/ccoenraets/OpenFB/issues/20#issuecomment-49249483 (is not totally related but it provides some code you can use)
This should be the code that will allow you to monitor the URL (extracted from the code provided on the thread):
if (runningInCordova) {
loginWindow.addEventListener('loadstart', function (event) {
var url = event.url;
if (url.indexOf("access_token=") > 0) {
// Get the token
}
});
}
Once you have obtained the access token and stored in your database, you should redirect to any other place of your App.
I hope it helps.
Javier.
Yesterday, I discovered Firebase and started to use it. I deployed an edited version (I just changed the CSS) of the chat app provided by Firebase, Everything went OK until I added Twitter Logging option. I couldn't authenticate my app with Twitter even though I followed these instructions and I activated "Sign in with Twitter" from Twitter Application Management Panel.
This is the code I'm using in my chat app to log in (anything else is related to Twitter logging in my code):
// instatiate the FirebaseSimpleLogin and monitor the user's auth state
var chatRef = new Firebase('https://ranchat.firebaseIO.com');
var auth = new FirebaseSimpleLogin(chatRef, function(error, user) {
if (error) {
// an error occurred while attempting login
alert(error);
} else if (user) {
// user authenticated with Firebase
alert('Welcome' + user.username);
} else {
// user is logged out
}
});
// attempt to log the user in with your preferred authentication provider
$('#twlog').click(function(){
auth.login('twitter', {
RememberMe: true
});
});
These are the Firebase Rules I'm using
{
"rules": {
".read": true,
"$comment": {
".write": "!data.exists() && newData.child('twitter_id').val() == auth.id"
}
}
}
And this is what happens after press Twitter Log button in my app
Error: FirebaseSimpleLogin: An unknown error occurred
Honesly, I don't know why it happening. Would you give a hand?
I found the solution thanks to #RobDiMarco.
The error was occuring due to an incorrect copy of Twitter API ID and API Secret into my Firebase Forge. I just needed to copy these and then paste it here.
The terminology is very confusing in Firebase Simple Login documentation. Firebase requires three things:
Twitter App ID (used in the client call), which is the "API key" from API keys tab in your Twitter application settings page
Twitter Consumer Key (entered into Firebase Forge), which is also the "API key"
Twitter Consumer Secret (entered into Firebase Forge), which is the "API secret" from the same tab