10

What's the quickest way to generate a secure password in javascript?

I want it to contain at least 1 special character, and 2 mixed case. Must be at least 6 characters long.

chovy
  • 72,281
  • 52
  • 227
  • 295
  • 3
    Dont use secure and javascript in same context ;) Let PHP generate passwords instead of doing it client side. – Ron van der Heijden Sep 28 '12 at 07:39
  • Maybe helpful: http://stackoverflow.com/questions/5840577/jquery-or-javascript-password-generator-with-at-least-a-capital-and-a-number?lq=1 and http://stackoverflow.com/questions/2477862/jquery-password-generator?rq=1 – Thilo Sep 28 '12 at 07:41
  • Check this - http://stackoverflow.com/questions/9719570/generate-random-password-string-with-requirements-in-javascript – niksvp Sep 28 '12 at 07:44
  • 3
    javascript has dominated the past 5 years. lol – chovy Jun 05 '18 at 23:16

7 Answers7

39

Here are some useful String functions:

String.prototype.pick = function(min, max) {
    var n, chars = '';

    if (typeof max === 'undefined') {
        n = min;
    } else {
        n = min + Math.floor(Math.random() * (max - min + 1));
    }

    for (var i = 0; i < n; i++) {
        chars += this.charAt(Math.floor(Math.random() * this.length));
    }

    return chars;
};


// Credit to @Christoph: http://stackoverflow.com/a/962890/464744
String.prototype.shuffle = function() {
    var array = this.split('');
    var tmp, current, top = array.length;

    if (top) while (--top) {
        current = Math.floor(Math.random() * (top + 1));
        tmp = array[current];
        array[current] = array[top];
        array[top] = tmp;
    }

    return array.join('');
};

Your password would look like this:

var specials = '!@#$%^&*()_+{}:"<>?\|[];\',./`~';
var lowercase = 'abcdefghijklmnopqrstuvwxyz';
var uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
var numbers = '0123456789';

var all = specials + lowercase + uppercase + numbers;

var password = '';
password += specials.pick(1);
password += lowercase.pick(1);
password += uppercase.pick(1);
password += all.pick(3, 10);
password = password.shuffle();

Demo: http://jsfiddle.net/Blender/ERCsD/6/

Blender
  • 289,723
  • 53
  • 439
  • 496
  • I'm new to php. How would I be able to call this from a button with onclick? – CBC_NS Dec 18 '13 at 20:57
  • 1
    Great answer - just what I needed. I added `password += numbers.pick(1)` to also make sure a number is included. – phansen Dec 19 '14 at 03:32
  • Pretty solution, thx, but in the line `n = min + Math.floor(Math.random() * (max - min));` I would replace `Math.floor` with `Math.round`. The `max` couldn't actually be reached. – algorhythm Jun 01 '16 at 06:22
  • @algorhythm: But max is `this.length`, which shouldn't be reached if you're using it for indexing a string. – Blender Jun 01 '16 at 14:47
  • I'm not sure if I understand... `pick` picks a bounded count of random characters out of a string. And when I call the method with `min` and `max` I expect that the minimum length is `min` and the maximum length is `max`. What exactly does this have to do with indexing a string? Do you have an example? – algorhythm Jun 01 '16 at 15:15
  • @algorhythm: I was looking at the line below the one you were referencing, sorry. Fixed. – Blender Jun 01 '16 at 18:17
  • 3
    Math.random() is not a secure source of randomness. This answer is bogus. – TheGreatContini Jun 04 '18 at 22:05
7

I just get the post now. It is a bad idea to use Math.random() if you can spend few minutes to look at this article.

Actually there are crypto API into newer browsers and you must use it as soon as you start something touching cryptography.

That why i recommand to use My library which use the famous crypto API. It works both on server and client side (nodejs and browsers).

mk-

3

I modified @Blender's answer to make it more secure, and also without altering String.prototype.

// Copy-pasted from:
// https://stackoverflow.com/questions/12635652/generate-a-secure-password-in-javascript
// and modified for Auth0.
//
// Auth0 requirements:
// https://auth0.com/docs/connections/database/password-strength
//
// "at least 10 characters including at least 3 of the following 4 types of characters:
// a lower-case letter, an upper-case letter, a number, a special character (such as !@#$%^&*).
// Not more than 2 identical characters in a row (such as 111 is not allowed)".

const specials = '!@#$%^&*()_+{}:"<>?\|[];\',./`~';
const lowercase = 'abcdefghijklmnopqrstuvwxyz';
const uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
const numbers = '0123456789';

const all = specials + lowercase + uppercase + numbers;

export default function generatePassword() {
  let password = '';

  password += pick(password, specials, 1, 3);
  password += pick(password, lowercase, 1, 3);
  password += pick(password, uppercase, 1, 3);
  password += pick(password, all, 10);

  return shuffle(password);
}

function pick(exclusions, string, min, max) {
  var n, chars = '';

  if (max === undefined) {
    n = min;
  } else {
    n = min + Math.floor(Math.random() * (max - min + 1));
  }

  var i = 0;
  while (i < n) {
    const character = string.charAt(Math.floor(Math.random() * string.length));
    if (exclusions.indexOf(character) < 0 && chars.indexOf(character) < 0) {
      chars += character;
      i++;
    }
  }

  return chars;
}

// Credit to @Christoph: http://stackoverflow.com/a/962890/464744
function shuffle(string) {
  var array = string.split('');
  var tmp, current, top = array.length;

  if (top) while (--top) {
    current = Math.floor(Math.random() * (top + 1));
    tmp = array[current];
    array[current] = array[top];
    array[top] = tmp;
  }

  return array.join('');
}
catamphetamine
  • 4,489
  • 30
  • 25
0

It isn't secure way. It would be possible to simulate password generation if it depends only on Math function (seed). It would be more secure if you try to relate the generation to user event like tracking mouse location (so by using different seeds based on user actions).

Vazgen Manukyan
  • 1,410
  • 1
  • 12
  • 17
0

use this code for strong password :D

const generatePassword = (
  passwordLength = 8,
) => {
  const lowerCase = 'abcdefghijklmnopqrstuvwxyz'
  const upperCase = lowerCase.toUpperCase()
  const numberChars = '0123456789'
  const specialChars = '!"@$%+-_?^&*()'

  let generatedPassword = ''
  let restPassword = ''

  const restLength = passwordLength % 4 
  const usableLength = passwordLength - restLength
  const generateLength = usableLength / 4

  const randomString = (char) => {
    return char[Math.floor(Math.random() * (char.length))]
  }
  for (let i = 0; i <= generateLength - 1; i++) {
    generatedPassword += `${randomString(lowerCase)}${randomString(upperCase)}${randomString(numberChars)}${randomString(specialChars)}`
  }

  for (let i = 0; i <= restLength - 1; i++) {
    restPassword += randomString([...lowerCase, ...upperCase, ...numberChars, ...specialChars])
  }

  return generatedPassword + restPassword
}
M ilham
  • 352
  • 2
  • 11
0
 You could do some thing like below to generate password with following Requirements
    * At least One Special Character
    * At Least on Digit
    * At least on Upper Case
    * At least One Lower Case



function generatePassword(passwordLength) {
      var numberChars = "0123456789";
      var upperChars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
      var lowerChars = "abcdefghijklmnopqrstuvwxyz";
      var specialChars = "#?!@$%^&*-";
      var allChars = numberChars + upperChars + lowerChars + specialChars;
      var randPasswordArray = Array(passwordLength);
      randPasswordArray[0] = numberChars;
      randPasswordArray[1] = upperChars;
      randPasswordArray[2] = lowerChars;
      randPasswordArray[3] = specialChars;
      randPasswordArray = randPasswordArray.fill(allChars, 4);
      return shuffleArray(randPasswordArray.map(function(x) { return x[Math.floor(Math.random() * x.length)] })).join('');
    }
    
    function shuffleArray(array) {
      for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
      }
      return array;
    }
    
    //Change length accordingly
    alert(generatePassword(12));
Ninja
  • 338
  • 4
  • 12
0

The following allows you to have sets of characters separated by spaces. An equal number of characters will be selected from each character set to match the set length (password length).

In this case, lowercase, uppercase, numbers and special characters which satisfy a character length of 12.

function generatePassword () {
    let length = 12,
    charset = "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789 @/\_-&*#$!()",
    charsetArr = charset.split(' ');
    let retVal = "";
    charsetArr.forEach( chars => {
      for (let i = 0, n = chars.length; i < length/charsetArr.length; ++i) {
          retVal += chars.charAt(Math.floor(Math.random() * n));
      }
    })
    return retVal;
}
Cacious
  • 137
  • 1
  • 14