In the route below I'm checking if the user is logged in before rendering the content, but users sometimes gets logged out by the server and get the following message in the console:
Error logging in with token: Error: You've been logged out by the server. Please log in again. [403] undefined
When this happens, the check for userId() in the route still passes and the user gets a blank page and have to manually navigate to or reload to get to the login page. Is there a more reliable way of checking that the user is logged in and has a valid session going?
FlowRouter.route('/', {
name: '_users.currentUser',
action() {
if (!Meteor.userId()) {
FlowRouter.go('/login');
}
mount(LayoutDefaultCtx, {
content: () => (<UsersSingle _id={Meteor.userId()}/>),
});
}
});
Related
I've been trying to figure this out for hours but everything I try fails. I'm trying login a user and on success get route the user to the correct url based on the user's role. In the example below, I login successfully, and the user is successfully identified however when I try to redirect or push.history it doesn't let me. There are no errors, it just stays on the login url.
I'm using:
React router 4, Meteorjs
handleSubmit(event) {
event.preventDefault();
Meteor.loginWithPassword(email, password, (error, result) => {
if (error) {
this.setState({ loginError: 'Incorrect username or password.' });
} else {
if (!!Roles.userIsInRole(Meteor.userId(), 'isAdmin')) {
<Redirect to="/admin/dashboard" push />
}
}
});
}
A react component is something that is rendered, it's not just a function that you can call from anywhere.
Use history.push('/admin/dashboard")
If the router is being passed into your component as a prop you might also find yourself doing
this.props.history.push('/admin/dashboard")
I've built impersonate method in my Meteor application in order to login as another user, based on following article: https://dweldon.silvrback.com/impersonating-a-user. I also have Intercom integration (chat widget and user tracking). I would like to be able to disable on client side that Intercom widget, in order to avoid any tracking from Intercom application, when I am logged as another user (impersonating). I was thinking about creating on user profile impersonate boolean property, and updating it to true, when I am triggering that impersonate method for any user. The problem is that, I have no idea how to set it to false when impersonate method is finished. According to article, you can stop impersonating when you refresh the browser manually. Could you please help me, and find the best approach?
We can solve this in two parts:
When we start impersonating a user, keep track of who is impersonating who. Let's do this by first extending the impersonate method in the tutorial:
Meteor.methods({
impersonate: function(userId) {
check(userId, String);
if (!Meteor.users.findOne(userId))
throw new Meteor.Error(404, 'User not found');
if (!Meteor.user().isAdmin)
throw new Meteor.Error(403, 'Permission denied');
Meteor.users.update(this.userId, { $set: { 'profile.impersonating': userId }});
this.setUserId(userId);
}
});
Next we need to listen for a new login (which should happen on a browser refresh)
Meteor.onLogin(() => {
Meteor.call('clearImpersonation', (err, result) => {
if (err) console.log('Error clearing impersonation: ',err);
});
});
Meteor.methods({
clearImpersonation(){
const user = Meteor.users.findOne(this.userId);
if (user && user.profile && user.profile.impersonating) Meteor.users.update(user._id,{ $unset: 'profile.impersonating' });
return;
}
});
Now in your UI you can disable Intercom by checking for the existence of Meteor.user().profile.impersonating
I am using accounts-google on my app and I'd like to solve rather odd authentication scenario.
A logs in so now as an app session and a google session
A switches to gmail and logs out there.
Now, mind you that, A is actually still logged in on the meteor app.
B comes along, logs in to Gmail using his account.
Switches to the meteor app to see that he's logged in, but oddly, logged in with A's account.
This scenario leads to lots of confusions and people unknowingly using other users' accounts where they share computers.
So, basically, I need to users in the meteor session and google session to be the same, and if not, ensure that the current meteor session is invalidated and loginWithGoogle() is called again.
How can I solve this?
It seems impossible with Meteor's current accounts package, although one could create a new one using Google's latest googleplus api.
But there seems to exist a workaround by:
1) Set up onBeforeAction hooks on your router to login the user automatically (which asks for credentials if user is not logged in to external service)
var loginWithGoogle = function() {
if (Meteor.isClient) {
Session.set('loginError', undefined);
Meteor.loginWithGoogle({
loginStyle : "redirect",
requestPermissions : ['profile', 'email'],
requestOfflineToken: true
}, function (err) {
if (err)
Session.set('loginError', 'reason: ' + err.reason + ' message: ' + err.message || 'Unknown error');
});
}
}
var requireLogin = function() {
if (! Meteor.user()) {
if (Meteor.loggingIn()) {
this.render(this.loadingTemplate);
} else {
console.log('The app is automatically asking for you to log in.');
loginWithGoogle();
}
} else {
this.next();
}
}
Router.onBeforeAction(requireLogin, {except: ['some-special-public-route']});
2) Log the user out when they are navigating away from every page (caveat: login/logout gets called everytime the user navigates within the app)
Meteor.startup(function(){
$(window).bind('beforeunload', function() {
closingWindow();
});
});
closingWindow = function(){
console.log('The app is automatically logging you out because you are leaving.');
Meteor.logout();
}
3) improvement area: set a session variable to track user's navigation within the app and run the unload event depending on the variable.
I sent enrollment email to the user and when he enters password and other details I'm trying to reset the password but it is throwing error
uncaught error extpected to find a document to change
As you can see in the mage
I've subscribed to the user record
my code
this.route('enroll', {
path: '/enroll-account/:token',
template: 'enroll_page',
onBeforeAction: function() {
Meteor.logout();
Session.set('_resetPasswordToken', this.params.token);
s = this.subscribe('enrolledUser', this.params.token).wait();
}
}),
After I'm displaying form and on the submit event
onSubmit: function(creds) {
var options = {
_id: Meteor.users.findOne()._id,
name: creds.name
}
var token=Session.get('_resetPasswordToken');
Meteor.call('updateUser', options, function(error, result) {
if(!error) {
Accounts.resetPassword(token, creds.password, function(error) {
if (error) {
toastr.error("Sorry we could not update your password. Please try again.");
return false;
}
else{
toastr.error("Logged In");
Router.go('/');
}
});
} else {
toastr.error("Sorry we could not update your password. Please try again.");
return false;
}
});
this.resetForm();
this.done();
return false;
}
Everything is working fine but resetpassword callback is not triggering and the above error is displaying in console.
my token is get deleted from the user record and I'm able to login using login form but
From the docs
Reset the password for a user using a token received in email. Logs the user in afterwards.
I'm not able to automatically login after resetting the password,above error is throwing
What am I missing here?
this.subscribe('enrolledUser', this.params.token).wait();
here you're subscribing using resetPassword token
when you call Accounts.resetPassword method the method will reset the password and delete the token from user record.
So your subscription is lost and there are no records available in client side to modify
(That is waht the error Expected to find a document to change)
Instead on first subscription save the user Id and subscribe to the user record using Id
so the subscription will not be lost
path: '/enroll-account/:token',
template: 'enroll_page',
onBeforeAction: function() {
Meteor.logout();
Session.set('_resetPasswordToken', this.params.token);
s = this.subscribe('enrolledUser', this.params.token).wait();
},
onAfterAction:function(){
if(this.ready()){
var userid=Meteor.users.findOne()._id;
Meteor.subscribe("userRecord",userid);
}
}
Alternatively, you could do something like as follows in your publication. This worked for me (but mine was a slightly more involved query than this).
Meteor.publish('enrolledUser', function (token) {
check(token, String);
return Meteor.users.find({
$or: [{
_id: this.userId
}, {
'services.password.reset.token': token
}]
});
});
From the docs, it says
Reset the password for a user using a token received in email. Logs the user in afterwards.
So basically, you have to subscribe to the logged in user after the fact as well. A little silly, but whatever.
I am trying to build a basic web application w/ user authentication via email/password registration using Firebase.
My setup right now includes a main.js file that consists of the following:
var dbRef = new Firebase('https://url.firebaseIO.com');
var authClient = new FirebaseAuthClient(dbRef, function(error, user) {
if (error) {
// an error occurred while attempting login
console.log(error);
} else if (user) {
// user authenticated with Firebase
console.log('User ID: ' + user.id + ', Provider: ' + user.provider);
} else {
// user is logged out
console.log('logged out!');
}
});
function next(){
window.location = 'index.html';
}
function test(){
authClient.login('password', {
email: email,
password: password,
rememberMe: true
},next());
// window.location = 'index.html';
}
I obtain email/password values from a form and login. That works. But as soon as I include a callback function to then redirect them to a new authenticated page, it no longer works. In fact, most of the time I get an "UNKOWN ERROR" response.
When I get to the next page, I am no longer logged in. If I remove the next() function and stay on the same page, it works - even if I then trigger the next function from the console. Is there a different way you are supposed to proceed to another page?
I'm pretty sure there is some sort of communication issue (possibly the login does not get a return before the page is switched?) because if I add a 1s timeout before the next function, it then works. But surely this is not best practice?
Thanks!
Per https://www.firebase.com/docs/security/simple-login-email-password.html, the authClient.login() method does not actually accept a callback, so the problem you're seeing is likely the result of navigating away from the current page before the callback is returned, as you suggested.
I would recommend doing the redirect in the callback you're passing during the instantiation of the auth client. (new FirebaseAuthClient(ref, callback)) and redirect if you detect a logged-in user. This callback will be invoked once upon instantiation with the current authentication state of the user, and then again any time the user's authentication state changes (such as on login or logout).