Change Password Script Templates

Change Password Script Templates

The Change Password script implements the function executed to change the password associated with the user identity in the your legacy identity store. We recommend naming this function changePassword. The script is only used in a legacy authentication scenario.

This script executes whenever a user tries to change their password; the user will receive the password reset email, which includes the link they need to follow to change their password. This script is optional; however, a call to changePassword is typically preceded by a call to getUser, so if you implement the change password script you will also need to implement the get user script.

Best practice

While it’s not mandatory to implement the changePassword function, we recommend it as a best practice. The changePassword function is required to for the password reset workflow recommended for a great customer experience.

The script is executed whenever password reset workflow is performed and also during password change workflow via the Auth0 Dashboard or the Auth0 Management API.

The changePassword function implemented in the Change Password script should be defined as follows:

function changePassword(email, newPassword, callback) {
  // TODO: implement your script
  return callback(null, result);
}

Was this helpful?

/

Parameter Description
email The email address for the user as the user identifying credential.
password The new password credential for the user. The password credential for the user is passed to the script in plain text so care must be taken regarding its use.
callback Executed with up to two parameters. The first parameter is an indication of status: a null first parameter with a corresponding second parameter of true indicates that the operation executed successfully; a null first parameter with no corresponding second parameter (or one with a value of false) indicates that no password change was performed (possibly due to the user not being found). A non null first parameter value indicates that some error condition occurred.

Best practice

When indicating an error, we recommend using the Error object to provide Auth0 with a clear indication of the error condition. For example, use callback(new Error(“an error message”)) when a problems occurs with communication to your database. To learn more, read the "Type of Errors" section in Troubleshoot Custom Databases.

bcrypt hash encryption

The password credential for the user is passed to the login script in plain text so care must be taken regarding its use. You should refrain from logging, storing, or transporting the password credential anywhere in its vanilla form. Instead, use something similar to the following example, which uses the bcrypt algorithm to perform cryptographic hash encryption:

```js bcrypt.hash(password, 10, function (err, hash) { if (err) { return callback(err); } else { . . } }); ```

Language-specific script examples

Auth0 provides sample scripts for use with the following languages/technologies:

JavaScript

function changePassword(email, newPassword, callback) {
  // This script should change the password stored for the current user in your
  // database. It is executed when the user clicks on the confirmation link
  // after a reset password request.
  // The content and behavior of password confirmation emails can be customized
  // here: https://manage.auth0.com/#/emails
  // The `newPassword` parameter of this function is in plain text. It must be
  // hashed/salted to match whatever is stored in your database.
  //
  // There are three ways that this script can finish:
  // 1. The user's password was updated successfully:
  //     callback(null, true);
  // 2. The user's password was not updated:
  //     callback(null, false);
  // 3. Something went wrong while trying to reach your database:
  //     callback(new Error("my error message"));
  //
  // If an error is returned, it will be passed to the query string of the page
  // to which the user is being redirected after clicking the confirmation link.
  // For example, returning `callback(new Error("error"))` and redirecting to
  // https://example.com would redirect to the following URL:
  //     https://example.com?email=alice%40example.com&message=error&success=false
  const msg = 'Please implement the Change Password script for this database ' +
    'connection at https://manage.auth0.com/#/connections/database';
  return callback(new Error(msg));
}

Was this helpful?

/

ASP.NET Membership Provider (MVC3 - Universal Providers)

function changePassword(email, newPassword, callback) {
  var crypto = require('crypto');
  var Connection = require('tedious').Connection;
  var Request = require('tedious').Request;
  var TYPES = require('tedious').TYPES
  var connection = new Connection({
    userName:  'the username',
    password:  'the password',
    server:    'the server',
    options: {
      database:  'the db name',
      // encrypt: true   for Windows Azure enable this
    }
  });
  /**
   * hashPassword
   *
   * This function creates a hashed version of the password to store in the database.
   *
   * @password  {[string]}      the password entered by the user
   * @return    {[string]}      the hashed password
   */
  function hashPassword(password, salt) {
    // the default implementation uses HMACSHA256 and since Key length is 64
    // and default salt is 16 bytes, Membership will fill the buffer repeating the salt
    var key = Buffer.concat([salt, salt, salt, salt]);
    var hmac = crypto.createHmac('sha256', key);
    hmac.update(Buffer.from(password, 'ucs2'));
    var hashed = hmac.digest('base64');
    return hashed;
  }
  connection.on('debug', function(text) {
      // if you have connection issues, uncomment this to get more detailed info
      //console.log(text);
  }).on('errorMessage', function(text) {
      // this will show any errors when connecting to the SQL database or with the SQL statements
    console.log(JSON.stringify(text));
  });
  connection.on('connect', function (err) {
    if (err) {
      return callback(err);
    }
    updateMembershipUser(email, newPassword, function(err, wasUpdated) {
      if (err) {
        return callback(err); // this will return a 500
      }
      callback(null, wasUpdated);
    });
  });
  function updateMembershipUser(email, newPassword, callback) {
    var salt            = crypto.randomBytes(16);
    var hashedPassword  = hashPassword(newPassword, salt);
    var updateMembership =
      'UPDATE Memberships '+
      'SET Password=@NewPassword, PasswordSalt=@NewSalt, LastPasswordChangedDate=GETDATE() '+
      'WHERE Email=@Email';
    var updateMembershipQuery = new Request(updateMembership, function (membershipErr, membershipCount) {
      if (membershipErr) {
        return callback(membershipErr);
      }
      callback(null, membershipCount > 0);
    });
    updateMembershipQuery.addParameter('NewPassword', TYPES.VarChar, hashedPassword);
    updateMembershipQuery.addParameter('NewSalt',     TYPES.VarChar, salt.toString('base64'));
    updateMembershipQuery.addParameter('Email',       TYPES.VarChar, email);
    connection.execSql(updateMembershipQuery);
  }
}

Was this helpful?

/

ASP.NET Membership Provider (MVC4 - Simple Membership)

function changePassword(email, newPassword, callback) {
  var crypto = require('crypto');
  var Connection = require('tedious').Connection;
  var Request = require('tedious').Request;
  var TYPES = require('tedious').TYPES
  var connection = new Connection({
    userName:  'the username',
    password:  'the password',
    server:    'the server',
    options: {
      database:  'the db name',
      // encrypt: true for Windows Azure enable this
    }
  });
  /**
   * hashPassword
   *
   * This function hashes a password using HMAC SHA256 algorithm.
   *
   * @password    {[string]}    password to be hased
   * @salt        {[string]}    salt to be used in the hashing process
   * @callback    {[function]}  callback to be called after hashing the password
   */
  function hashPassword(password, salt, callback) {
    var iterations         = 1000;
    var passwordHashLength = 32;
    crypto.pbkdf2(password, salt, iterations, passwordHashLength, function (err, hashed) {
      if (err) {
        return callback(err);
      }
      var result = Buffer.concat([Buffer.from([0], 1), salt, Buffer.from(hashed, 'binary')]);
      var resultBase64 = result.toString('base64');
      callback(null, resultBase64);
    });
  }
  connection.on('debug', function(text) {
      // if you have connection issues, uncomment this to get more detailed info
      //console.log(text);
  }).on('errorMessage', function(text) {
      // this will show any errors when connecting to the SQL database or with the SQL statements
    console.log(JSON.stringify(text));
  });
  connection.on('connect', function (err) {
    if (err) {
      return callback(err);
    }
    updateMembershipUser(email, newPassword, function(err, wasUpdated) {
      if (err) {
        return callback(err); // this will return a 500
      }
      callback(null, wasUpdated);
    });
  });
  function findUserId(email, callback) {
    var findUserIdFromEmail =
      'SELECT UserProfile.UserId FROM ' +
      'UserProfile INNER JOIN webpages_Membership ' +
      'ON UserProfile.UserId = webpages_Membership.UserId ' +
      'WHERE UserName = @Email';
    var findUserIdFromEmailQuery = new Request(findUserIdFromEmail, function (err, rowCount, rows) {
      if (err) {
        return callback(err);
      }
      // No record found with that email
      if (rowCount < 1) {
        return callback(null, null);
      }
      var userId = rows[0][0].value;
      callback(null, userId);
    });
    findUserIdFromEmailQuery.addParameter('Email', TYPES.VarChar, email);
    connection.execSql(findUserIdFromEmailQuery);
  }
  function updateMembershipUser(email, newPassword, callback) {
    findUserId(email, function (err, userId) {
      if (err) {
        return callback(err);
      }
      if (userId === null) {
        return callback();
      }
      var salt = crypto.randomBytes(16);
      var updateMembership =
        'UPDATE webpages_Membership '+
        'SET Password=@NewPassword, PasswordChangedDate=GETDATE() '+
        'WHERE UserId=@UserId';
      var updateMembershipQuery = new Request(updateMembership, function (err, rowCount) {
        if (err) {
          return callback(err);
        }
        if (rowCount < 1) {
          return callback();
        }
        callback(null, rowCount > 0);
      });
      hashPassword(newPassword, salt, function (err, hashedPassword) {
        if (err) {
          return callback(err);
        }
        updateMembershipQuery.addParameter('NewPassword',   TYPES.VarChar, hashedPassword);
        updateMembershipQuery.addParameter('UserId',        TYPES.VarChar, userId);
        connection.execSql(updateMembershipQuery);
      });
    });
  }
}

Was this helpful?

/

MongoDB

function changePassword(email, newPassword, callback) {
  const bcrypt = require('bcrypt');
  const MongoClient = require('mongodb@3.1.4').MongoClient;
  const client = new MongoClient('mongodb://user:pass@mymongoserver.com');
  client.connect(function (err) {
    if (err) return callback(err);
    const db = client.db('db-name');
    const users = db.collection('users');
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) {
        client.close();
        return callback(err);
      }
      users.update({ email: email }, { $set: { password: hash } }, function (err, count) {
        client.close();
        if (err) return callback(err);
        callback(null, count > 0);
      });
    });
  });
}

Was this helpful?

/

MySQL

function changePassword(email, newPassword, callback) {
  const mysql = require('mysql');
  const bcrypt = require('bcrypt');
  const connection = mysql({
    host: 'localhost',
    user: 'me',
    password: 'secret',
    database: 'mydb'
  });
  connection.connect();
  const query = 'UPDATE users SET password = ? WHERE email = ?';
  bcrypt.hash(newPassword, 10, function(err, hash) {
    if (err) return callback(err);
    connection.query(query, [ hash, email ], function(err, results) {
      if (err) return callback(err);
      callback(null, results.length > 0);
    });
  });
}

Was this helpful?

/

PostgreSQL

function changePassword (email, newPassword, callback) {
  //this example uses the "pg" library
  //more info here: https://github.com/brianc/node-postgres
  const bcrypt = require('bcrypt');
  const postgres = require('pg');
  const conString = 'postgres://user:pass@localhost/mydb';
  postgres.connect(conString, function (err, client, done) {
    if (err) return callback(err);
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) return callback(err);
      const query = 'UPDATE users SET password = $1 WHERE email = $2';
      client.query(query, [hash, email], function (err, result) {
        // NOTE: always call `done()` here to close
        // the connection to the database
        done();
        return callback(err, result && result.rowCount > 0);
      });
    });
  });
}

Was this helpful?

/

SQL Server

function changePassword (email, newPassword, callback) {
  //this example uses the "tedious" library
  //more info here: http://tediousjs.github.io/tedious/
  const bcrypt = require('bcrypt');
  const sqlserver = require('tedious@1.11.0');
  const Connection = sqlserver.Connection;
  const Request = sqlserver.Request;
  const TYPES = sqlserver.TYPES;
  const connection = new Connection({
    userName:  'test',
    password:  'test',
    server:    'localhost',
    options:  {
      database: 'mydb'
    }
  });
  const query = 'UPDATE dbo.Users SET Password = @NewPassword WHERE Email = @Email';
  connection.on('debug', function(text) {
    console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  });
  connection.on('connect', function (err) {
    if (err) return callback(err);
    const request = new Request(query, function (err, rows) {
      if (err) return callback(err);
      callback(null, rows > 0);
    });
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) return callback(err);
      request.addParameter('NewPassword', TYPES.VarChar, hash);
      request.addParameter('Email', TYPES.VarChar, email);
      connection.execSql(request);
    });
  });
}

Was this helpful?

/

Windows Azure SQL Database

function changePassword (email, newPassword, callback) {
  //this example uses the "tedious" library
  //more info here: http://pekim.github.io/tedious/index.html
  var Connection = require('tedious@1.11.0').Connection;
  var Request = require('tedious@1.11.0').Request;
  var TYPES = require('tedious@1.11.0').TYPES;
  var bcrypt = require('bcrypt');
  var connection = new Connection({
    userName:  'your-user@your-server-id.database.windows.net',
    password:  'the-password',
    server:    'your-server-id.database.windows.net',
    options:  {
      database: 'mydb',
      encrypt:  true
    }
  });
  var query = 'UPDATE dbo.Users SET Password = @NewPassword ' +
    'WHERE Email = @Email';
  connection.on('debug', function(text) {
    // Uncomment next line in order to enable debugging messages
    // console.log(text);
  }).on('errorMessage', function(text) {
    console.log(JSON.stringify(text, null, 2));
  }).on('infoMessage', function(text) {
    // Uncomment next line in order to enable information messages
    // console.log(JSON.stringify(text, null, 2));
  });
  connection.on('connect', function (err) {
    if (err) { return callback(err); }
    var request = new Request(query, function (err, rows) {
      if (err) { return callback(err); }
      console.log('rows: ' + rows);
      callback(null, rows > 0);
    });
    bcrypt.hash(newPassword, 10, function (err, hash) {
      if (err) { return callback(err); }
      request.addParameter('NewPassword', TYPES.VarChar, hash);
      request.addParameter('Email', TYPES.VarChar, email);
      connection.execSql(request);
    });
  });
}

Was this helpful?

/

Request with Basic Auth

function changePassword (email, newPassword, callback) {
  var request = require('request');
  request.put({
    url:  'https://myserviceurl.com/users',
    json: { email: email, password: newPassword }
    //for more options check:
    //https://github.com/mikeal/request#requestoptions-callback
  }, function (err, response, body) {
    if (err) return callback(err);
    if (response.statusCode === 401) return callback();
    callback(null, body);
  });
}

Was this helpful?

/

Learn more