Adam Freymiller Adam Freymiller - 2 months ago 6
Node.js Question

Does input field containing email for signup in passport-local have to have attribute 'name = username'?

I have local passport strategies set up to login and signup users, and I the way the current userflow works is that the user visits the signup page, enters their email address and password, and can login with those exact same credentials in the login view. Nothing fancy.

What I've noticed is that when I attempt to change the single line name attribute of the input field from 'username' to something like, 'email' to make it more readable, the code breaks with the message "Invalid user credentials" propagating via connect-flash. Every proof of concepts I've seen has had that input information be 'username', but when I change that single line and enter a distinct new email, signup no longer works.

Here is the view in question:


<h1><span class="fa fa-sign-in"></span> Signup</h1>

<!-- show any messages that come back with authentication -->
<% if (message.length > 0) { %>
<div class="alert alert-danger"><%= message %></div>
<% } %>

<!-- LOGIN FORM -->
<form action="/users/signup" method="post">
<div class="form-group">
<!-- the line directly below works -->
<input type="text" class="form-control" name="username">
<!-- but this line immediately below does not work! -->
<!-- <input type="text" class="form-control" name="email"> -->
<div class="form-group">
<input type="password" class="form-control" name="password">

<button type="submit" class="btn btn-warning btn-lg">Signup</button>

Here is my local-signup strategy:

passport.serializeUser(function(user, done) {

passport.deserializeUser(function(id, done) {
db.User.findById(id).then(function(user) {
done(null, user);
done(err, null);

passport.use('local-signup', new LocalStrategy({
emailField : 'email',
passwordField : 'password',
passReqToCallback : true },
function(req, email, password, done){
if(req.session.user && req.session){
done(null, false, {message: 'User is already logged in, signup illegal'});
db.User.findOne({ where: {email : email }})
.then(function(user) {
if(user !== null) {
done(null, false, {message: 'User already exists'});
//create user yada yada
return done(null, false, {message: err});

Is it absolutely required by passport.js that the attribute in the signup view for the signup strategy MUST be username? That strikes me as incredibly strange. Again, I'd like to emphasize the fact that literally the only change I made to the existing functional signup process was to change the attribute to 'email' instead of 'username'.


Though similar question have been asked a couple of times, they are without a really good answer in the context that PassportJS is to make authentication simple and so we can't expect those who are implementing it to delve deep into its code.

Passport-local is the Strategy that most people will utilize when using PassportJS. It typically expects a value of username and email as mentioned above.

If you go into node_modules/<path to passport-local>/strategy.js you will find more documentation on how to implement this.

`Strategy` constructor.

The local authentication strategy authenticates requests based on the
credentials submitted through an HTML-based login form.

Applications must supply a `verify` callback which accepts `username` and
`password` credentials, and then calls the `done` callback supplying a
`user`, which should be set to `false` if the credentials are not valid.
If an exception occured, `err` should be set.

Optionally, `options` can be used to change the fields in which the
credentials are found.

  - `usernameField`  field name where the username is found, defaults to _username_
  - `passwordField`  field name where the password is found, defaults to _password_
  - `passReqToCallback`  when `true`, `req` is the first argument to the verify callback (default: `false`)

The example that Jared Hanson, provided here that follows, is frankly inadequate as it doesn't even implement any of these features, thus, I've ommitted it, but if you look at the actual Strategy constructor's code, it's much clearer.

    function Strategy(options, verify) {
      if (typeof options == 'function') {
        verify = options;
        options = {};
      if (!verify) { throw new TypeError('LocalStrategy requires a verify callback'); }

      this._usernameField = options.usernameField || 'username';
      this._passwordField = options.passwordField || 'password';; = 'local';
      this._verify = verify;
      this._passReqToCallback = options.passReqToCallback;

So, basically, it checks to see if you passed in the callback appropriately, and checks to see if you passed in an options object. This options object is then checked to see for configurations and it does so via short-circuiting with the || symbol. So if you don't pass in any configs it'll just default to the username and password params.

Thus, pass inside your local config as follows -- in this example I swap out username for email.

passport.use('local-signup', new LocalStrategy({
  usernameField: 'email',
  passwordField : 'password',
  passReqToCallback : true
function(req, email, password, done){
  if(req.session.user && req.session){
      done(null, false, {message: 'User is already logged in, signup illegal'});

Finally, go into your model or database schema and make sure to change columns appropriately to match.

Extra info: "Why do we need to configure PassportJS?" (answering because that same question occurred to me)

The answer is you need to configure it to your database needs; you might be using MySQL, or MongoDB or some other database and each PassportJS implementation has to suit that database somehow. The following are questions that PassportJS cannot figure out on its own without customization from the user.

  • Do I need to use an ORM?
  • What kind of error messages do I need to display?
  • What other fields do I need to accept?

TL;DR pass in an options object to ur new local strategy config by changing expected params around as intended by the passport-local creator.