2fatang
Version: 
use for 2 factor authenticate with jwt
151 lines (122 loc) • 4.18 kB
JavaScript
var express = require('express');
var bodyParser = require('body-parser');
var path = require('path');
var speakeasy = require('speakeasy');
var cookieParser = require("cookie-parser");
var nodemailer = require('nodemailer');
var jwt = require("jsonwebtoken");
var app = express();
app.use(bodyParser.json())
app.use(cookieParser())
app.use('/', express.static(__dirname + '/views'));
const jwtKey = "my_secret_key";
const jwtExpirySeconds = 300;
// manually set the user details for login verification
// change the email and password here for login
var user = {
    email: "joeleesuperweb@gmail.com",
    password: "test1"
}
// can change the smtp server details in here
var transporter = nodemailer.createTransport({
  host: 'smtp.gmail.com',
  port: 587,
  auth: {
    user: 'joeleewiserobot@gmail.com',
    pass: 'mytest!@#'
  }
});
app.use(bodyParser.urlencoded({extended : true}));
app.use(bodyParser.json());
app.get('/', function(req, res) {
	res.sendFile(path.join(__dirname + '/views/index.html'));
});
app.post('/auth', function(req, res) {
	var email = req.body.email;
	var password = req.body.password;
	if (email && password) {
		if(email == user.email && password == user.password){ // compare the email password with mock data
			// Create a new token with the email in the payload
			// and which expires 300 seconds after issue
			const JWTtoken = jwt.sign({ email }, jwtKey, {
				expiresIn: jwtExpirySeconds,
			})
			// set the cookie as the token string, with a similar max age as the token
			res.cookie("JWTtoken", JWTtoken, { maxAge: jwtExpirySeconds * 1000 })
			const secret = speakeasy.generateSecret({length: 10});
			// generate token in here
		    var generatetoken = speakeasy.totp({
		        secret: secret.base32,
		        encoding: 'base32'
		    });
		    // setup email
		    var mailOptions = {
		      from: 'joeleewiserobot@gmail.com',
		      to: email,
		      subject: 'Email OTP',
		      html: '<h1>Your OTP is '+generatetoken+'</h1>'
		    };
		    // send token via email
		    transporter.sendMail(mailOptions, function(error, info){
		      if (error) {
		        console.log(error);
		      } else {
		        console.log('Email sent: ' + info.response);
		      }
		    });
		    // store the tempSecret of the logged in user
		    user.twofactor = {
		        tempSecret: secret.base32
		    };
			res.sendFile(path.join(__dirname + '/views/otp.html'));
		} else {
			res.send('Incorrect Username or Password!');
			res.end();
		}
	} else {
		res.send('Please enter Email and Password!');
		res.end();
	}
});
app.post('/verify', function(req, res){
	// obtain the session JWTtoken from the requests cookies, which come with every request
	const JWTtoken = req.cookies.JWTtoken
	// if the JWTToken cookie is not set, return an unauthorized error
	if (!JWTtoken) {
		res.status(401).end()
	}
	var payload
	try {
		// Parse the JWT string and store the result in `payload`.
		// Note that we are passing the key in this method as well. This method will throw an error
		// if the JWTtoken is invalid (if it has expired according to the expiry time we set on sign in),
		// or if the signature does not match
		payload = jwt.verify(JWTtoken, jwtKey)
	} catch (e) {
		if (e instanceof jwt.JsonWebTokenError) {
			// if the error thrown is because the JWT is unauthorized, return a 401 error
			res.status(401).end()
		}
		// otherwise, return a bad request error
		res.status(400).end()
	}
	var verified = speakeasy.totp.verify({
        secret: user.twofactor.tempSecret, //secret of the logged in user
        encoding: 'base32',
        token: req.body.token,
        window: 2 //accept tokens generated within ± 60 seconds of the server time
    });
    if(verified){
        res.redirect('/home');
    } else {
    	res.send('Invalid otp token, verification failed');
		res.end();
    }
});
app.get('/home', function(req, res) {
	res.send('Welcome back');
	res.end();
});
app.listen('3000', () => {
    console.log('App running on 3000');
});