Looking to enable two factor authentication for your application? We've got you covered with this quick, 20 minute Node tutorial.

Data privacy and security are a major concern in every industry today. With the average cost of a data breach reaching 8 million dollars, companies are implementing measures to avoid these instances and protect their consumers. One popular method for increasing security is two factor authentication (2FA), which requires users to verify their identity by providing two things. The first is some information that you know -- usually a username/password combination -- and the other is something you have -- usually a cellular device or some other physical token.
The latter is where SMS becomes relevant; enabling SMS-based 2FA will send a one-time code to the user’s mobile phone number so that they can verify their identity by confirming their device, and securely log into their account.
With Telnyx’s developer docs, you can enable 2FA on your application using Node, in about 20 minutes.
To get started, this is a basic overview of the steps we’ll cover:
Before you start building your 2FA service, you’ll need to provision an SMS number and messaging profile on the Mission Control Portal. A guide on how to set up your portal can be found here. Once your messaging profile is complete, you will add see the account’s API key in your portal. Next, you’ll create a config.json file in your project directory, and add the API key to the config file:
{
"API_KEY": "YOUR_API_KEY",
"FROM_NUMBER": "YOUR_TELNYX_NUMBER"
}
Place Node in debug mode, and specify the number of characters you’d like your OTP token to be. The country code will be +1 if all numbers are in the U.S.
{
"NODE_ENV": "development",
"COUNTRY_CODE": "+1",
"TOKEN_LENGTH": 4
}
In a production environment, a traditional database would be appropriate, but for the purpose of this example, we’ll be storing the tokens in a class. This class will store uppercase tokens as keys with details about those tokens as values.
Create a class, name it
TokenStorage
, and specify three static methods:class TokenStorage{
static add_token(token, phone_number){
this.tokens[token] = {
'phone_number': phone_number,
'last_updated': Date.now(),
'token': token.toUpperCase()
}
}
static token_is_valid(token){
return token in TokenStorage.tokens
}
static clear_token(token){
delete TokenStorage.tokens[token]
}
}
TokenStorage.tokens = {}
To initialize the server, we’ll set up a simple Express app that watches the templates directory with
Nunjucks
, load the config file, and configure the telnyx library.const config = require('./config.json';)
const express = require("express")
const app = express()
app.use(express.urlencoded());
app.set('views', `${__dirname}/templates`);
expressNunjucks(app, {
watch: true,
noCache: true,
});
We’ll need to create a simple HTML form, index.html, to collect phone numbers for validation; the full HTML source can be found at our Github repo.
app.get('/', (_req, res) => {
res.render('index');
});
To generate the OTP tokens, we’ll start with
get random token hex
, which generates a random string of hex characters.function get_random_token_hex(num_chars) {
return crypto.randomBytes(num_chars).toString('hex');
}
The
randomBytes
method accepts a number of bytes, so we need to divide by two and and round up in order to ensure we get enough characters (two characters per byte),and then trim by the desired length. This allows us to support odd numbered token lengths.Next, handle the form on the
/request
route, which will normalize the phone number.app.post('/request', (req, res) => {
let phone_number = req.body.phone.replace('/[\-\.\(\)]/g','')
Then, generate a token and add the token/phone number pair to the data store:
let generated_token = get_random_token_h(config.TOKEN_LENGTH)
TokenStorage.add_token(generated_token, phone_number)
Finally, we send an SMS including the token to the user’s device and serve the verification page.
telnyx.messages.create({
"to": `${phone_number}`,
"from": `${config.COUNTRY_CODE}${config.FROM_NUMBER}`,
"text": `Your Token is ${generated_token}`
})
res.render('verify.html');
})
The
verify.html
file includes a form that collects the token and sends it back to the server. If the token is valid, we'll clear it from the datastore and serve the success page.app.post("/verify", (req, res) => {
let token = req.body.token
if (TokenStorage.token_is_valid(token)) {
TokenStorage.clear_token(token)
res.render('verify_success.html')
}
If the token is not valid, an error message will be displayed and the user will be sent back to the verify form.
else {
res.render('verify.html')
}
})
At the end of the file, run the server:
const port = 3000
app.listen(port, () => console.log(`App listening on ${port}!`))
To start the application, run
node index.js
Congrats! You’ve just configured 2FA on the Telnyx platform that you can use to scale across your application. Make sure you check out our developer community on Slack to see what others are building with Telnyx.
What is 2FA in Node.js and how does TOTP work? Two-factor authentication adds a second check beyond the password to confirm a user’s identity. Time-based One-Time Passwords use a shared secret and the current time to generate a six-digit code that typically refreshes every 30 seconds.
How do I implement 2FA in Node.js? Generate a per-user secret with a library like otplib or speakeasy, enroll via QR code, encrypt the secret at rest, and verify a TOTP during sign-in. If you deliver OTPs over messaging, follow the provider’s developer documentation to handle retries, delivery status webhooks, and regional rules.
Why do some say 2FA is no longer safe? Weak 2FA flows can be phished, SIM-swapped, or abused through prompt fatigue if protections like rate limits and origin binding are missing. Use authenticator apps or hardware keys for sensitive actions, and add anti-phishing checks such as origin-bound prompts or verified domains.
Should I use SMS or an authenticator app for 2FA? SMS is convenient and reaches nearly everyone, but it is more vulnerable than app-based TOTP or WebAuthn hardware keys. If you pick SMS delivery, understand the differences between SMS and MMS so you design for text-only constraints and carrier policies.
How do I send one-time passcodes via SMS from Node.js? Generate a short numeric code, set a brief expiration, and send it through a messaging API with throttling and replay protections. Choose the correct messaging types, avoid links when possible, and never log the full OTP.
How do I get my 2FA authenticator code? Open your enrolled authenticator app and use the current six-digit code shown for the account. If the code fails, resync your device’s time and confirm you are selecting the correct account entry.
How do I add 2FA to a JWT or session-based auth flow in Node.js? After verifying username and password, mark the session as 2FA pending and block access until the user passes the second factor, then issue the final JWT or elevate the session. Use step-up prompts for high-risk actions and add lockouts, IP checks, and rate limits to curb abuse.
Related articles