User is created however cannot login after logging out MeteorJS - meteor

So I'm creating a new user as my template is created. The user is being created successfully, and automatically is logged in however if I sign out and then try to sign in , I get the 'user not found'. Here is my code
Template.hello.onCreated(function helloOnCreated() {
// counter starts at 0
this.counter = new ReactiveVar(0);
var userObject = {
username: "anotherTest",
mail: "anotherTest#me.com",
password: "testingME"
};
Accounts.createUser(userObject, function(error){
console.log('User created');
console.log(error);
});
});
And here is the full project in case it is needed.
https://github.com/hayk94/UbMvp/tree/accountsTEST
Do you know what is the problem?

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 run on the client and/or on the server with different behaviors, Accounts.createUser docs specify 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.

Related

New user email verification [duplicate]

Question says it all. In Firebase, how do I confirm email when a user creates an account, or, for that matter, do password reset via email.
I could ask more broadly: is there any way to send emails out from Firebase? E.g. notifications, etc. This isn't the kind of thing you would usually do client-side.
Update
Note that this was never a very secure way of handling email verification, and since Firebase now supports email verification, it should probably be used instead.
Original answer
I solved the email verification using the password reset feature.
On account creation I give the user a temporary (randomly generated) password. I then trigger a password reset which will send an email to the user with a link. The link will allow the user to set a new password.
To generate a random password you can use code similar to this:
function () {
var possibleChars = ['abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?_-'];
var password = '';
for(var i = 0; i < 16; i += 1) {
password += possibleChars[Math.floor(Math.random() * possibleChars.length)];
}
return password;
}
Note that this is happening on the client, so a malicious user could tamper with your logic.
This would need to be done outside of firebase. I store users at /users/ and keep a status on them (PENDING, ACTIVE, DELETED). I have a small service that monitors users of a PENDING status and sends out a confirmation email. Which has a link to a webservice I've created to update the user status to ACTIVE.
[Engineer at Firebase - Update 2014-01-27]
Firebase Simple Login now supports password resets for email / password authentication.
Each of the Simple Login client libraries has been given a new method for generating password reset emails for the specified email address - sendPasswordResetEmail() on the Web and Android, and sendPasswordResetForEmail() on iOS.
This e-mail will contain a temporary token that the user may use to log into their account and update their credentials. This token will expire after 24 hours or when the user changes their password, whichever occurs first.
Also note that Firebase Simple Login enables full configuration of the email template as well as the sending address (including whitelabel email from your domain for paid accounts).
To get access to this feature, you'll need to update your client library to a version of v1.2.0 or greater. To grab the latest version, check out https://www.firebase.com/docs/downloads.html.
Also, check out https://www.firebase.com/docs/security/simple-login-email-password.html for the latest Firebase Simple Login - Web Client docs.
As at 2016 July, you might not have to use the reset link etc. Just use the sendEmailVerification() and applyActionCode functions:
In short, below is basically how you'll approach this, in AngularJS:
// thecontroller.js
$scope.sendVerifyEmail = function() {
console.log('Email sent, whaaaaam!');
currentAuth.sendEmailVerification();
}
// where currentAuth came from something like this:
// routerconfig
....
templateUrl: 'bla.html',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn() // this throws an AUTH_REQUIRED broadcast
}]
}
...
// intercept the broadcast like so if you want:
....
$rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) {
if (error === "AUTH_REQUIRED") {
$state.go('login', { toWhere: toState });
}
});
....
// So user receives the email. How do you process the `oobCode` that returns?
// You may do something like this:
// catch the url with its mode and oobCode
.state('emailVerify', {
url: '/verify-email?mode&oobCode',
templateUrl: 'auth/verify-email.html',
controller: 'emailVerifyController',
resolve: {
currentAuth:['Auth', function(Auth) {
return Auth.$requireSignIn()
}]
}
})
// Then digest like so where each term is what they sound like:
.controller('emailVerifyController', ['$scope', '$stateParams', 'currentAuth', 'DatabaseRef',
function($scope, $stateParams, currentAuth, DatabaseRef) {
console.log(currentAuth);
$scope.doVerify = function() {
firebase.auth()
.applyActionCode($stateParams.oobCode)
.then(function(data) {
// change emailVerified for logged in User
console.log('Verification happened');
})
.catch(function(error) {
$scope.error = error.message;
console.log(error.message, error.reason)
})
};
}
])
And ooh, with the above approach, I do not think there's any need keeping the verification of your user's email in your user data area. The applyActionCode changes the emailVerified to true from false.
Email verification is important when users sign in with the local account. However, for many social authentications, the incoming emailVerified will be true already.
Explained more in the article Email Verification with Firebase 3.0 SDK
What I did to work around this was use Zapier which has a built in API for firebase. It checks a location for added child elements. Then it takes the mail address and a verification url from the data of new nodes and sends them forwards. The url points back to my angular app, which sets the user email as verified.
As I host my app files in firebase, I don't need have to take care of any servers or processes doing polling in the background.
There is a delay, but as I don't block users before verifying mails it's ok. Zapier has a free tier and since I don't have much traffic it's a decent workaround for time being.
The new Firebase SDK v3 appears to support email address verification, see here (put your own project id in the link) but it doesn't appear to be documented yet.
I have asked the question on SO here
See #SamQuayle's answer there with this link to the official docs.
As noted by various others Firebase does now support account related emails but even better, as of 10 days ago or so it also supports sending any kind of email via Firebase Functions. Lots of details in the docs and example code here.
I used following code to check the email verification after creating new account.
let firAuth = FIRAuth.auth()
firAuth?.addAuthStateDidChangeListener { auth, user in
if let loggedUser = user {
if loggedUser.emailVerified == false {
loggedUser.sendEmailVerificationWithCompletion({ (error) in
print("error:\(error)")
})
}
else {
print(loggedUser.email)
}
} else {
// No user is signed in.
print("No user is signed in.")
}
}
I used MandrillApp. You can create an API key that only allows sending of a template. This way even thought your key is exposed it can't really be abused unless someone wants to fire off tonnes of welcome emails for you.
That was a hack to get myself off the ground. I'm now enabling CORS from a EC2 that uses the token to verify that the user exists before extending them a welcome via SES.

How can I create a method for retrieving user email address that is available on the client and server?

I've got facebook, google and regular registration/login turned on on my website. The problem I have is that the email address is stored in different fields depending on how the user first joined.
For regular users, it is in field emails[0].address. For facebook and google authenticated users it is in field services[0].email.
At various places in the client (templates, events) and on the server (method), I just want to call one method that works out which field to use and returns the email address. I also want to do something similar for the verification field.
I'm fairly new to meteor and the only ways I've found to do the above so far is to repeat the same logic in the client and on the server which doesn't sit well with me.
The best thing to do would be to transfer the email address to 'emails' if they log in with facebook, google or another services for the first time. This would also make it more future proof incase you add other services, since meteor will always use emails.address (including in other packages)
Server side code:
Accounts.onCreateUser(function(user) {
user.emails = user.emails || []; //If its null set it to an empty array
if(user.services.facebook) {
user.emails.push({address: user.services.facebook.email, verified: false});
}else if(user.services.google) {
user.emails.push({address: user.services.google.email, verified: false});
}
return user;
});
Then you can just check Meteor.user().emails[0].address every time.
Note: If not published due to the autopublish package you may have to publish the emails field for it to work on the client.
You may also have to run this the first time for users who have already logged in before:
Meteor.startup(function() {
Meteor.users({'emails':{$exists: false}}).fetch().forEach(function(user) {
var email = (user.services.facebook || user.services.google).email;
if(email) Meteor.users.update({_id: user._id},{$push:{emails:{address: email, verified: false}}});
});
});
I'm not sure if facebook and google both use email in the services key, if they do the above should work fine. If they don't you can edit out the key that is used for google or facebook, in case one is emailAddress instead of email for example.

Accounts.onLogin how to get user Id?

How do you get the _id of the user that logged in. I have tried the following combinations and I get errors, or undefined
Upon user creation, the user is automatically signed into the application. Is the user that is returned by the Accounts.onCreateUser function occurring after the user is logged in?
Accounts.onLogin(function(){
var user = this.userId / Meteor.user() / Meteor.user()._id
console.log(user)
})
http://docs.meteor.com/#/full/accounts_onlogin
The Accounts.onLogin(function(){}), come with 1 parameter user.
When it is known which user was attempting to login, the Meteor user
object. This will always be present for successful logins.
from the docs.
So this should work.
Accounts.onLogin(function(user){
console.log(user.user._id)
});
And you should see, all the user document into the server console,check this meteorpad for an example.
NOTE: this feature is only available on server side check this Hooks Accounts.onLogin/onLoginFailure should be available on client
You can always get the _id of the logged-in user via Meteor.userId(). This also works inside the Accounts.onLogin callback
Accounts.onLogin(function() {
console.log(Meteor.userId());
})

Meteor.user() on iron-router server side

How can check, on server side route, if user is logged?
I would add check on 'before', but Metor.user() don't work here.
thanks in advance.
p.s. I have found How to get Meteor.user() to return on the server side?, but not work on iron-router
I'm afraid that this is not possible. I guess that the problem comes from the fact that you're trying to connect to the server with two different protocols - both literally and in logically - so there is no obvious way to relate this two actions.
There is, however, a pretty simple solution that may suit your needs. You'll need to develop a simple system of privileges tokens, or secret keys, or whatever you call them. First, create a server method
var Secrets = new Meteor.Collection("secrets"); // only on server!!!
Meteor.methods({
getSecretKey: function () {
if (!this.userId)
// check if the user has privileges
throw Meteor.Error(403);
return Secrets.insert({_id: Random.id(), user: this.userId});
},
});
Then, you can now use it on the client to get the secretKey which attach to your AJAX request (or something), either within the HTTP header or in the URL itself. Fear not!
They will all be encrypted if you're using HTTPS.
On the server side you can now retrieve the secretKey from the incoming request and check if it is present in the Secrets collection. You'll know then if the user is granted certain privileges or not.
Also you may want to remove your secret keys from the collection after some time for safety reasons.
If what you're looking to do is to authenticate the Meteor.user making the request, I'm currently doing this within the context of IronRouter.route(). The request must be made with a valid user ID and auth token in the header. I call this function from within Router.route(), which then gives me access to this.user:
###
Verify the request is being made by an actively logged in user
#context: IronRouter.Router.route()
###
authenticate = ->
# Get the auth info from header
userId = this.request.headers['x-user-id']
loginToken = this.request.headers['x-auth-token']
# Get the user from the database
if userId and loginToken
user = Meteor.users.findOne {'_id': userId, 'services.resume.loginTokens.token': loginToken}
# Return an error if the login token does not match any belonging to the user
if not user
respond.call this, {success: false, message: "You must be logged in to do this."}, 401
# Attach the user to the context so they can be accessed at this.user within route
this.user = user
###
Respond to an HTTP request
#context: IronRouter.Router.route()
###
respond = (body, statusCode=200, headers={'Content-Type':'text/json'}) ->
this.response.writeHead statusCode, headers
this.response.write(JSON.stringify(body))
this.response.end()
This code was heavily inspired by RestStop and RestStop2. It's part of a meteor package for writing REST APIs in Meteor 0.9.0+ (built on top of Iron Router). You can check out the complete source code here:
https://github.com/krose72205/meteor-restivus

How can I store login username as a variable using Meteor?

How can I make a variable for the current user's username as they log in to create a database document for them to store their info?
You need to setup a custom function to configure user creation in server side, see Accounts.onCreateUser on docs.meteor.com
In this function you can initialize your user database document, either in user.field or user.profile.field.
The username is automatically stored in user.username, you do not need to create it.
Then to modify the user record client side, simply call a server method that will update the Meteor.users collection, ie
server/users.js
Meteor.methods({
updateUser:function(fields){
if(!this.userId){
// error : no user logged in
}
check(fields,{/* fields verification */});
Meteor.users.update(this.userId,{
$set:fields
});
}
});
client/main.js
Meteor.call("updateUser",{
"username":"foo",
"profile.bar":"bar"
});
Note that Meteor built-in user accounts greatly simplify all this process : it is well documented so I encourage you re-read that particular section in the docs.

Resources