How to prevent auto login after create user - javascript

I add accounts-password and accounts-base packages in Meteor
When I create user like this:
Accounts.createUser({username: username, password : password}, function(err){
if (err) {
// Inform the user that account creation failed
console.log("Register Fail!")
console.log(err)
} else {
console.log("Register Success!")
// Account has been created and the user has logged
}
});
Account has been created and the user has logged.
for instance, I log in as an administrator and I want to create a account for somebody,but I don't want to log out after create account.
How to prevent auto login after create user ?
I find source code of accouts-password packages:
48 - 63 lines:
// Attempt to log in as a new user.
Accounts.createUser = function (options, callback) {
options = _.clone(options); // we'll be modifying options
if (!options.password)
throw new Error("Must set options.password");
var verifier = Meteor._srp.generateVerifier(options.password);
// strip old password, replacing with the verifier object
delete options.password;
options.srp = verifier;
Accounts.callLoginMethod({
methodName: 'createUser',
methodArguments: [options],
userCallback: callback
});
};
Should I modify the source code to solve this problem?
Any help is appreciated.

You're trying to use client side accounts management to perform a task it hasn't been designed for.
Client side accounts package purpose is to specifically allow new users to create their account and expect to be logged in immediately.
You have to remember that certain functions can be ran on the client and/or on the server with different behaviors, Accounts.createUser docs specifies that : "On the client, this function logs in as the newly created user on successful completion."
On the contrary, "On the server, it returns the newly created user id." (it doesn't mess with the currently logged in user on the client).
In order to solve your problem, you should write a server side method creating a new user and be able to call it from your client side admin panel, after filling correctly a user creation form of your own design.

If you really want this behavior you would need to modify password_server.js
and remove lines 474-475 containing:
// client gets logged in as the new user afterwards.
this.setUserId(result.id);
So the User would not be logged in after the user is created.

I had the same problem. I wanted to create an admin interface where an administrator can set a user's password but not pass it to a server method in plaintext. The client side of Accounts.createUser already deals with this, so I just alter the normal sequence of events in accounts-password/password-server.js in the presence of a flag. Its not perfect or pretty but seems to work and you don't have to modify the accounts-password package directly.
Meteor.startup(function ()
{
// store the default createUser method handler
var default_create_user = Meteor.server.method_handlers.createUser;
// remove it so we can register our own
delete Meteor.server.method_handlers.createUser;
Meteor.methods({createUser: function (options) {
var default_login_method = Accounts._loginMethod;
// check if noAutoLogin flag is present
if (options.noAutoLogin)
{
// temporarily disable the login method while creating our user
// NB: it might be possible that simultaneous calls to createUser that do want the default behavior
// would use the altered Accounts._loginMethod instead
Accounts._loginMethod = function(s, m, a, p, fn)
{
// this is the callback that is constructed with a closure of the options array and calls internal create functions
fn();
// restore default _loginMethod so other calls are not affected
Accounts._loginMethod = default_login_method;
}
}
// invoke the default create user now that the login behavior has been short-circuited
default_create_user(options);
}});
});

If you want to continue using Accounts.createUser on the client without logging the user in. You can call Meteor.logout() from createUser's optional callback.
Accounts.createUser(user, err => {
if (err) {
// handle error
return;
}
// Prevent unwanted login
Meteor.logout();
});

Related

Generate recover email link in firebase

Is there any way to create custom recoverEmail link in firebase/firebase-admin?
I've checked the docs and tutorials there's none.
Any help would be great!
From my understanding there is currently no solution for this within the SDK. Instead, we took the approach of using admin.auth().generateSignInWithEmailLink(email, actionCodeSettings) and then replacing the mode within the returned link from signIn to recoverEmail.
const updatedLink = link.replace('signIn', 'recoverEmail');
This allowed us to customise the auth handler action as suggested here Create the email action handler page in the Firbase documentation.
Now we are able to call on admin.auth().updateUser again to reset the email to it's previous, along with update across our databases, merchant and other services. You'll also need to add the original email to a query in the updatedLink too.
const linkWithOriginalEmail = updatedLink.concat(`&email=${email}`)
Hope that helps and if anyone has a better solution we'd love to discuss.
I´m not sure if I understand your problem correctly, but If your goal is to have a custom link in the automatic email sent by Firebase when someone changes his authentication email address with updateEmail then you can define a custom action url in the Firebase console e.g. https://example.com/__/auth/action in the Authentication section and add the following code to the defined url (ref. https://firebase.google.com/docs/auth/custom-email-handler).
function handleRecoverEmail(auth, actionCode, lang) {
// Localize the UI to the selected language as determined by the lang
// parameter.
var restoredEmail = null;
// Confirm the action code is valid.
auth.checkActionCode(actionCode).then(function(info) {
// Get the restored email address.
restoredEmail = info['data']['email'];
// Revert to the old email.
return auth.applyActionCode(actionCode);
}).then(function() {
// Account email reverted to restoredEmail
// TODO: Display a confirmation message to the user.
// You might also want to give the user the option to reset their password
// in case the account was compromised:
auth.sendPasswordResetEmail(restoredEmail).then(function() {
// Password reset confirmation sent. Ask user to check their email.
}).catch(function(error) {
// Error encountered while sending password reset code.
});
}).catch(function(error) {
// Invalid code.
});
}

Meteor: trying to add another field to the user profile Accounts.onCreateUser();

Basically trying to modify the user that was just created by giving it an extra field called sid in it's profile object. I'm running this on server.js (the server code)
Accounts.onCreateUser(function (options, user) {
Meteor.users.update({_id: user._id}, {$set: {"user.profile.sid": [post.content]}});
});
console.log(JSON.stringify(user));
However, the user object does not show the sid field in it's output. Am I doing this in the wrong location or is my code wrong?
From the docs
The function you pass will be called with two arguments: options and user. The options argument comes from Accounts.createUser for password-based users or from an external service login flow. options may come from an untrusted client so make sure to validate any values you read from it. The user argument is created on the server and contains a proposed user object with all the automatically generated fields required for the user to log in, including the _id.
The function should return the user document (either the one passed in or a newly-created object) with whatever modifications are desired. The returned document is inserted directly into the Meteor.users collection.
So your code should be:
Accounts.onCreateUser(function (options, user) {
user.profile.sid = [post.content];
return user;
});
However be aware that anything in the user.profile object can be changed by your users.
profile: an Object which the user can create and update with any data. Do not store anything on profile that you wouldn't want the user to edit unless you have a deny rule on the Meteor.users collection.
Try this instead
Accounts.onCreateUser(function (options, user) {
user.profile.sid = [post.content];
return user;
});
From the documentation it reads (http://docs.meteor.com/#/full/accounts_oncreateuser):
The user argument is created on the server and contains a proposed user object...
So at this point it looks like the user does not actually exist in the database yet.

Firebase Anonymous User Authentication flow

I have the following js code where I try to login on the blog_root object and then use my user_root to listen for any changes with user_root.on("child_added",...)
var root = new Firebase( /*my firebase url*/);
var blog_root = root.child("blog");
var user_root;
console.log("====");
blog_root.authAnonymously(function(err, authData) {
if(err){
console.log("user not authenticated?"+err);
}else{
console.log("user authenticated?"+authData.uid);
if(authData){
user_root = blog_root.child(authData.uid);
user_root.set(authData);
}
}
},{
remember: "sessionOnly"
});
user_root.on(
"child_added", //event_name
function(snapshot) {
//called for each existing element and each new element
}
Using this code specifically my user_root object is shown to be undefined. I check my data and the anonymous user has been successfully added to the blog_root, but I cannot seem to be able to listen to changes on user_root.
What I gather is that the user_root.on("child_added") event is fired on my authentication statement, but this makes no sense to me because user_root is initialized inside the authentication statement.
Any clues?
The authAnonymously method is asynchronous, and the callback is invoked after you first get to user_root.on('child_added', ...). Try moving this listener into the callback from authAnonymously.
Also, note that each time you call authAnonymously(), you're creating a new session. Sessions are automatically persisted by default. To check whether or not the user is already authenticated, try ref.getAuth(), and only invoke authAnonymously() if the user is unauthenticated (ref.getAuth() === null).

Meteor.user() alternatives

I am writing an application which needs to display some user information.
Because Meteor.user() is not immediately available I wrapped every user information with an handlerbar helper
Handlebars.registerHelper('isLoggingIn', function() {
return Meteor.loggingIn();
})
This worked for me until I needed to create an admin page and custom content for every user/user role.
Waiting for Meteor.user() to be available or showing general information first while waiting for the roles to load are options I would like to avoid.
I then tried an alternative way and published the currentUser with a new Collection.
Meteor.publish('currentUser', function() {
var sub = this;
var handle = Meteor.users.find({_id: this.userId}).observe({
added: function (user) {
sub.added('currentUser', user._id, user);
}
});
sub.ready();
sub.onStop(function() { handle.stop(); });
});
and
CurrentUser = new Meteor.Collection('currentUser');
In this way I can access the logged in user with CurrentUser.findOne(), and it's available at the same time as the other collections.
What I fear is that this alternative is not as secure and problem free as the common Meteor.user(), and I was wondering if my method is correct and if there are better ways to obtain the same result (user detail information immediately available) without reinventing the wheel.
Just a note you can use {{loggingIn}}, {{#if loggingIn}}.. without writing your own helper.
The option to publish the user who is logged in with a custom publish function adds an unnecessary complexity.
When it comes to security you have to assume if its from the client side, in any scenario it is untrustworthy. This means you publish relevant data for the role, etc only when they are logged in to that user.
On the server the data is immediately available as soon as the user logs in, all you have to do is publish only the data for that users role. On the client it may take some time to adjust to this, which is why you can use placeholder until the subscriptions are complete.
What might be a better option would be to use either a helper that checks for when subscriptions are completed and displays a 'loading message'. Or use a router such as iron-router (github.com/EventedMind/iron-router) that can let you wait for a subcription to complete for a particular page.
This way you can use Meteor.user(), {{#currentUser}} and roles in way you intend.
One thing to keep in mind, is if you want to check if the user is logged in, not to use:
if(Meteor.user())
but instead
if(Meteor.user() && Meteor.user().profile && Meteor.user().profile.name)
(You will have to insert a name property in your profile, though). While logging in the user gets more and more data. I've noticed if you wait for the profile field, then the user is 'ready'. It seems initially the profile field is empty (still loggin in), but it would return true if you used if(Meteor.user())

Picking up meteor.js user logout

Is there any way to pick up when a user logs out of the website? I need to do some clean up when they do so. Using the built-in meteor.js user accounts.
I'll be doing some validation using it, so I need a solution that cannot be trigger on behalf of other users on the client side - preferably something completely server side.
You may use Deps.autorun to setup a custom handler observing Meteor.userId() reactive variable changes.
Meteor.userId() (and Meteor.user()) are reactive variables returning respectively the currently logged in userId (null if none) and the corresponding user document (record) in the Meteor.users collection.
As a consequence one can track signing in/out of a Meteor application by reacting to the modification of those reactive data sources.
client/main.js :
var lastUser=null;
Meteor.startup(function(){
Deps.autorun(function(){
var userId=Meteor.userId();
if(userId){
console.log(userId+" connected");
// do something with Meteor.user()
}
else if(lastUser){
console.log(lastUser._id+" disconnected");
// can't use Meteor.user() anymore
// do something with lastUser (read-only !)
Meteor.call("userDisconnected",lastUser._id);
}
lastUser=Meteor.user();
});
});
In this code sample, I'm setting up a source file local variable (lastUser) to keep track of the last user that was logged in the application.
Then in Meteor.startup, I use Deps.autorun to setup a reactive context (code that will get re-executed whenever one of the reactive data sources accessed is modified).
This reactive context tracks Meteor.userId() variation and reacts accordingly.
In the deconnection code, you can't use Meteor.user() but if you want to access the last user document you can use the lastUser variable.
You can call a server method with the lastUser._id as argument if you want to modify the document after logging out.
server/server.js
Meteor.methods({
userDisconnected:function(userId){
check(userId,String);
var user=Meteor.users.findOne(userId);
// do something with user (read-write)
}
});
Be aware though that malicious clients can call this server method with anyone userId, so you shouldn't do anything critical unless you setup some verification code.
Use the user-status package that I've created: https://github.com/mizzao/meteor-user-status. This is completely server-side.
See the docs for usage, but you can attach an event handler to a session logout:
UserStatus.events.on "connectionLogout", (fields) ->
console.log(fields.userId + " with connection " + fields.connectionId + " logged out")
Note that a user can be logged in from different places at once with multiple sessions. This smart package detects all of them as well as whether the user is online at all. For more information or to implement your own method, check out the code.
Currently the package doesn't distinguish between browser window closes and logouts, and treats them as the same.
We had a similar, though not exact requirement. We wanted to do a bit of clean up on the client when they signed out. We did it by hijacking Meteor.logout:
if (Meteor.isClient) {
var _logout = Meteor.logout;
Meteor.logout = function customLogout() {
// Do your thing here
_logout.apply(Meteor, arguments);
}
}
The answer provided by #saimeunt looks about right, but it is a bit fluffy for what I needed. Instead I went with a very simple approach like this:
if (Meteor.isClient) {
Deps.autorun(function () {
if(!Meteor.userId())
{
Session.set('store', null);
}
});
}
This is however triggered during a page load if the user has not yet logged in, which might be undesirable. So you could go with something like this instead:
if (Meteor.isClient) {
var userWasLoggedIn = false;
Deps.autorun(function (c) {
if(!Meteor.userId())
{
if(userWasLoggedIn)
{
console.log('Clean up');
Session.set('store', null);
}
}
else
{
userWasLoggedIn = true;
}
});
}
None of the solutions worked for me, since they all suffered from the problem of not being able to distinguish between manual logout by the user vs. browser page reload/close.
I'm now going with a hack, but at least it works (as long as you don't provide any other means of logging out than the default accounts-ui buttons):
Template._loginButtons.events({
'click #login-buttons-logout': function(ev) {
console.log("manual log out");
// do stuff
}
});
You can use the following Meteor.logout - http://docs.meteor.com/#meteor_logout

Categories

Resources