Firebase Authentication. General Query - firebase

I am currently creating a react-native app and testing it using exp on a physical Pixel 2. When I load my app up, I have the following in componentDidMount:
componentDidMount = () => {
firebase.auth().onAuthStateChanged((user)=>{
if (user) {
//this.setState({userid: user.uid}); //I added this to see if it was the below slowing things down (it is not)
firebase.database().ref('/Users/'+user.uid+'/Public/').once('value')
.catch(err=>{console.log(err)})
.then(snapshot=>{
let username = snapshot.child('Username').val();
this.setState({username: username, userid: user.uid});
});
} else {
this.setState({ user: null, username: null});
}
});}
My aim is to direct the user to the log-in page if they are not authenticated. Otherwise, dive straight into the inner pages. My code sort-of-works and this does actually take place (hurray!).
However, when I load my app up is takes a number of seconds (maybe 10 seconds), for the app to realise that I am already signed in. This means it shows the log-in page for 10 seconds and then starts to display the inner pages. Has anyone got any idea of why it takes so long for .onAuthStateChanged to register that I am in fact still signed in from my last session? And is there any way for me to know whether I am at the login page because I am not logged in at all or because the app doesn't yet realise that I am logged in? It is very awkward for the user having to sign in every time and then mid way through typing their details in, being logged in lol!
As always, all help is much appreciated.

Related

Amplify Reset Password Hangs

I used amplify's withAuthenticator as shown below for my /mainPage path. But when I tried to reset password, supply the confirmation code and submit it, the page hangs. It should refresh my /mainPage page.
import { withAuthenticator } from "#aws-amplify/ui-react";
import "#aws-amplify/ui-react/styles.css";
function MainPage({ signOut, user }) {
return (
<>
<h1>Hello {user.username}</h1>
<button onClick={signOut}>Sign out</button>
</>
);
}
export default withAuthenticator(MainPage);
Lots of missing information here but.. here's go nothing
page hangs == there was an error which can be viewed and inspected by your browser's developer tools - you should attach the error here in order to help others to assist (next time of course)
do you use the default reset password flow or make something custom?
in any case - why do you use the signOut method for this process? the user is not signed in (forgot password) so there is no point to sign out
The only scenerio I can think of is if the user is forced to change password (e.g. - getting kicked off with the signOut method, change password and sign in again). Even for that use-case - the signOut method alone (as present in your code) is only the first phase of this process (and not the entire process)
With that being said, I'll try to suggest a process that will simplify things for you (as the name Amplify applies) - reset one's password by using the build-in mechanism already provided with the library (please read the docs)
Long story short, the process would be:
User need to change password (forgot or forced to perform this action)
An email with temporary code is then send to user's email (this code is only valid for one hour - please generate it only when user is able to actually change current password)
User copy the code from email to your form, and then enter the new password
After confirmation - password changed. It's up to you to decide if you want to enter user into your app of force re-entry (e.g. typing the new password in the login screen in order to sign-in)
And you can use the forgotPassword and forgotPasswordSubmit methods in order to fulfill that process (more information in the link provided above) . In any other case (you have a custom flow) - please share more details
One last technical note:
In react this form of event handling
<button onClick={asyncFunc} >I am a button!</button>
Is the short way of wrtiting
<button onClick={async () => { await asyncFunc1(); await asyncFunc2() } }>
I am a button!
</button>
So either write your own custom async function and use the short way (preferred) or use the long way and use several functions in order to materialize your async process steps
Good luck 😊

Xolvio Cucumber - Getting errors in console yet all tests are passing

I have the following code. It seems like my tests pass, but I get tons of errors in my console. What's going on? Are my tests non-deterministic and being re-run? If so how do I prevent the errors?
login.feature:
Feature: User authentication
As a user
I want to be able to login
So that I can have all the good stuff that comes with user accounts
Background:
Given I am signed out
Scenario: A user can sign up with valid information
Given I am on the home page
When I open the sign up modal
And I enter my desired authentication information
Then I should be logged in
step_definitions.js
this.When(/^I open the sign up modal$/, function (callback) {
// Write code here that turns the phrase above into concrete actions
helper.world.browser.
click('[data-ion-modal="signup"]').
waitForVisible('.#signup-form', 2000).
call(callback);
});
this.When(/^I enter my desired authentication information$/, function (callback) {
// Write code here that turns the phrase above into concrete actions
helper.world.browser.
waitForExist('#signup-form', 2000).
waitForVisible('#signup-form').
setValue('#signup-email', 'newuser#test.com').
setValue('#signup-password', 'password').
submitForm('#signup-form').
call(callback);
});
this.Then(/^I should be logged in$/, function (callback) {
// Write code here that turns the phrase above into concrete actions
helper.world.browser.
waitForExist('.tabs', 2000).
waitForVisible('.tabs').
call(callback);
});
This looks like a meteor-cucumber regression. I'm in the process of rewriting cucumber, expect this problem to go away in the next release.

Secure way to store pending user's password in Meteor

For my Meteor application, I would like to have the following signup process:
User registers username, email and password. (He's not able to log in yet.)
Confirmation email sent [Accounts.sendEnrollmentEmail]
User confirms email [Accounts.onEnrollmentLink]
User is created. [Accounts.createUser] (He's able to log in.)
In order to achieve this, I feel like I would have to store the plain text password in a table of temporary users (step 1) in order to create the actual user later (step 3). Obviously this is a horrible idea.
I could of course only ask for the password as of step 3 and create the user at once - but it's not the behavior I would like to achieve.
So: Is there a proper way to store the password securely to later pass it to the user creation? Or is there a way to create a not-loginable users?
There is not much you have to do yourself as Meteor brings everything you need for save password storage when you create a user with the built in methods. So you should use these methods from the beginning (Your step 1: Accounts.createUser, step 2: Accounts.sendVerificationEmail, step 3: Accounts.verifyEmail, step 4 isn't necessary anymore).
Now to get where you want to be you can use an approach like David Weldon suggested but use Accounts.validateLoginAttempt on the sever side. That is a little easier and the login isn't allowed in the first place.
For example you could have this code server side:
Accounts.validateLoginAttempt(function(loginAttempt){
if (!loginAttempt.allowed) {
// Only tell the user that something went wrong but not what to enhance security
throw new Meteor.Error(901, 'Your login credentials are wrong. Try again.');
} else {
// In some cases this method isn't invoked with a correct user object...
if (!loginAttempt.user) {
throw new Meteor.Error(902, 'No valid user object. Make sure to validate your email address first.');
}
// If email verification is required check if the user has a valid email address and don't allow the login if he has none
if (!loginAttempt.user.emails[0].verified) {
throw new Meteor.Error(902, 'Your email address has to be verified first.');
}
// We have a correct login!
return true;
}
});
And now on the client side you can use a logic like this for the login
Meteor.loginWithPassword(email, password, function(callback) {
if (callback === undefined) {
// Your login logic
} else if (callback.error == 902) {
// Your "not verfied" logic
} else {
// Your other login errors logic
}
}
Note that you may have to adjust the registration process a little bit, too, as Meteor per default tries to login users directly after registration but this will not be possible anymore.
Also note that you may use Accounts.validateLoginAttempt for more than just that. For example you also could implement a logic here to only allow a certain amount of bad login attempts from the same IP.
We've used a slightly different pattern in our app based on the accounts package
User registers
User is logged in normally
Out main site template conditions content with
<template name="main">
{{#if currentUser}}
{{#if verified }}
...
{{else}}
Notice to user to look for their verification email
{{/if}}
{{/if}}
</template>
Based on a helper function
Template.main.helpers({
verified: function() { return Meteor.user().emails[0].verified; }
});
This meets the requirement that the user can't do much if anything until they have been verified yet uses the accounts package in a simple and secure way.
I could see taking a related approach using iron:router as well.

The earliest point I can get a Meteor.user()

I want to update my user status to be online, meaning, run this code (coffee script...)
Meteor.users.update _id: Meteor.user()._id, $set: 'profile.idle': true, 'profile.online': true if Meteor.user()?
I don't know where to put it, (is it ok to put it in client? ) where will this code run for sure with the logged in user even if user already logged in before ?
from little googling I found that meteor start events is not the place, what is the place?
client side in a Deps.autorun block would do it
in js it would be something like
Deps.autorun(function(){
if(Meteor.user()){
Meteor.users.update(Meteor.userId(),{$set:{<your fields here>}});
}
});
--
if you are trying to detect that users are online and can use meteorite, you might want to check out https://atmosphere.meteor.com/package/profile-online
you could also roll your own, by setting up a Meteor.setInterval call every 10 seconds or so to update a lastSeen time for the user, then detect if the user is online if lastSeen > timeNow - userTimeout[60 seconds?]

As3 Graph API Logout

i'm developing an application that'll be played by different's users, but i'm using the as3 graph api for authenticating users and posting on their wall, and i need to logout each user, before next user start his session on as3 graph api:
http://code.google.com/p/facebook-actionscript-api/
I search to force FB to ask for login's info but after a logout when login again, API skip the step and log, on the last user session.
None of the solutions I have seen on the web did work for me. The problem is indeed with StageWebView facebook cookie not being cleared on logout with FacebookMobile.logout() call. Loading logout.php with access token did not help me probably because there is no "next" parameter value for air applications that makes sense. I have seen people suggest to use localhost or facebook.com there but none of these options worked.
I have come up with a really questionable solution, but it works for now.
The point is to logout user in facebook normally like he would logout on his own. To do this we need to load facebook.com in StageWebView and click logout. Logout button is a submit form item for "logout_form" html form. So we need to make a javaScript call
document.getElementById('logout_form').submit();
in our StageWebView. And we can do just that by calling
webView.loadURL("javascript:document.getElementById('logout_form').submit();");
in ActionScript.
The full code that I use for now
protected var _logoutAttemptInProgress:Boolean = false;
public function fbLogout():void{
if(!_isLoggedIn) return;
if(_logoutAttemptInProgress) return;
_logoutAttemptInProgress = true;
var webView:StageWebView = new StageWebView();
webView.viewPort = new Rectangle(-1, 0, 1, 1);
webView.stage = this.stage;
webView.loadURL("http://www.facebook.com/lksmlrsgnlskn");
webView.addEventListener(Event.COMPLETE, runLogoutJs);
function runLogoutJs(event:Event):void{
webView.removeEventListener(Event.COMPLETE, runLogoutJs);
var jsString:String = "document.getElementById('logout_form').submit();";
webView.loadURL("javascript:"+jsString);
webView.addEventListener(Event.COMPLETE, closeWebView);
}
function closeWebView(event:Event):void{
webView.removeEventListener(Event.COMPLETE, closeWebView);
webView.stage = null;
webView.dispose();
_isLoggedIn = false;
_logoutAttemptInProgress = false;
}
FacebookDesktop.logout(null, APP_ORIGIN);
}
"lksmlrsgnlskn" is just some random garbage to get to error page that is much smaller than main page and loads faster.
FacebookDesktop.logout is to clear any local SharedObject data that Facebook lib might still have.
This is an issue that's been continuously revised by FacebookMobile, Facebook, and FacebookDesktop. Basically, you'll need to make sure you set FacebookDesktop.manageSession = false; and pass in the 2nd argument of "logout" your site's api url. If that doesn't work, the other method is to use "reallyLogout", as detailed here in this thread.
The notes in comment #24 detail the way to expos the Access Token from FacebooMobile (or whichever singleton you're using), and then manually calling the logout.php method on Facebook, with the access token.
http://code.google.com/p/facebook-actionscript-api/issues/detail?id=297#c24
This is a problem with the cookies, i mean, the firts user session remains and when you press to login the API logs in the first user.
I dont know why but the Facebook Api log out method dont log the user out of facebook, only log the user out from your application.
If you came to a solution or think something else, let me know so we could get the solution.

Resources