This week, I needed to create an OTP (one-time password) code, a 4-digit random number code, to email users so they could verify their email addresses.
Before we get into the details, here's the code:
function getCode() {
return `${Math.floor(Math.random() * 10000)}`.padStart(4,0);
};
A couple of things to note:
- It returns a string (not a number) - and there are a couple of reasons for this which I will explain shortly!
- From '0000' to '9999'
This function returns a string of numbers for a 4-digit code. If you want letters in your code, here's how I built a random unique ID JavaScript function.
Why do I return a string?
A few other solutions I found did something like Math.floor(1000 + (Math.random() * 9000));
and return a number. That works too, but you're missing the first 999 codes from 0000 to 0999.
The problem with numbers is you don't keep the leading zeros. So if my random number code generator returns 71, it's not 4 digits. It's two. This is an issue because my code always needed to be 4 digits.
Starting at 1000 removes that issue. But it creates another annoyance that may or may not bother you. The first digit in your code will never be 0. I wanted each of my 4 digits to have the full range of options from 0-9, and if I start at 1000, then the first digit can never be 0, which bothered me.
I figured out that if I generate my code as a string then leading zeros wouldn't be a problem.
And since my solution is for an OTP (one-time password) code, it will get sent back to my server as a string inputted by the user anyway.
It's easier to compare string-to-string, rather than converting the user-supplied string to a number and then comparing.
Let's get into the code, and I'll also expand the function so you can use it for 4 digits, 6 digits and even 10-digit codes!
Generating the 4-digit OTP
Ok, so I'm starting with the classic Math.random()
because its literal purpose is to create a random number, which is what I want to do here.
But instead of the default which is a number between 0 and 1, I want a number between 0 and 10000:
Math.random() * 10000
And I don't want decimal numbers, only whole numbers, so I can use Math.floor()
to round the numbers down to the nearest whole number which will give me numbers from 0 - 9999 (because we are rounding down the random number won't go up to 10000).
Math.floor(Math.random() * 10000)
Now for those pesky leading zeros!
If we get any number less than 1000, our code won't be four digits. If we get 748 it's three digits, and if we get 5 it's only one digit!
I thought the easiest way to fix this would be to use .padStart()
which takes a parameter for the target length, and a parameter for the string to pad it with.
I want a target length of 4 and for the string to be padded with zeros:
.padStart(4,0)
.padStart()
will only work on strings, so I'm using a template literal (${}
) to turn the number into a string first (I did try chaining .toString().padStart(4,0)
but it didn't work).
`${Math.floor(Math.random() * 10000)}`.padStart(4,0);
Now the getCode()
function returns a 4-digit random number code.
function getCode() {
return `${Math.floor(Math.random() * 10000)}`.padStart(4,0);
};
getCode(); // '4736'
getCode(); // '0689'
getCode(); // '4031'
getCode(); // '2416'
getCode(); // '3717'
getCode(); // '0110'
getCode(); // '6723'
Generating longer random numerical codes
I only need 4-digit codes, but maybe in the future, I'll need 6 or 8-digit codes - who knows what the future holds!
So I thought I'd expand the function to take a length parameter, that defaults to 4.
function getCode(length = 4) {
let max = Number("1".padEnd(length+1, 0));
return `${Math.floor(Math.random() * max)}`.padStart(length,0);
};
Now instead of the max being 10000, I need it to be 100000 for five digits, or 1000 for three digits. I'm using padEnd()
to add however many zeros I need to 1 (as a string so that padEnd()
works!) and then converting it to a number max
for the Math.random()
calculation.
I also use the length
variable to determine how many leading zeros I need in padStart(length,0)
.
Here's the new function working:
getCode(); // '2332' - defaults to 4 digits
getCode(4); // '4549'
getCode(2); // '07'
getCode(2); // '29'
getCode(5); // '20809'
getCode(5); // '71133'
getCode(8); // '99740831'
getCode(8); // '09646710'
Want letters in your code too? Here's how I built a random unique ID JavaScript function.