diff --git a/src/oauth2views/login.ejs b/src/oauth2views/login.ejs
index 6965bcb8d..0068051cf 100644
--- a/src/oauth2views/login.ejs
+++ b/src/oauth2views/login.ejs
@@ -31,6 +31,10 @@
+
+
+
+
Reset password
diff --git a/src/routes/oauth2.js b/src/routes/oauth2.js
index 0b09be1c7..5c3670c5f 100644
--- a/src/routes/oauth2.js
+++ b/src/routes/oauth2.js
@@ -19,6 +19,7 @@ var apps = require('../apps'),
querystring = require('querystring'),
session = require('connect-ensure-login'),
settings = require('../settings'),
+ speakeasy = require('speakeasy'),
tokendb = require('../tokendb'),
url = require('url'),
user = require('../user.js'),
@@ -254,6 +255,19 @@ function login(req, res) {
passport.authenticate('local', {
failureRedirect: '/api/v1/session/login?' + failureQuery
})(req, res, function () {
+ if (req.user.twoFactorAuthenticationEnabled) {
+ if (!req.body.totpToken) {
+ let failureQuery = querystring.stringify({ error: 'A 2fa token is required', returnTo: returnTo });
+ return res.redirect('/api/v1/session/login?' + failureQuery);
+ }
+
+ let verified = speakeasy.totp.verify({ secret: req.user.twoFactorAuthenticationSecret, encoding: 'base32', token: req.body.totpToken });
+ if (!verified) {
+ let failureQuery = querystring.stringify({ error: 'The 2fa token is invalid', returnTo: returnTo });
+ return res.redirect('/api/v1/session/login?' + failureQuery);
+ }
+ }
+
res.redirect(returnTo);
});
}