diff --git a/app/auth/__init__.py b/app/auth/__init__.py
index 52c4f0dc..1932940a 100644
--- a/app/auth/__init__.py
+++ b/app/auth/__init__.py
@@ -10,4 +10,5 @@ from .views import (
google,
facebook,
change_email,
+ mfa,
)
diff --git a/app/auth/templates/auth/mfa.html b/app/auth/templates/auth/mfa.html
new file mode 100644
index 00000000..0dee84d4
--- /dev/null
+++ b/app/auth/templates/auth/mfa.html
@@ -0,0 +1,28 @@
+{% extends "single.html" %}
+
+
+{% block title %}
+ MFA
+{% endblock %}
+
+
+{% block single_content %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/app/auth/views/mfa.py b/app/auth/views/mfa.py
new file mode 100644
index 00000000..2e8e715f
--- /dev/null
+++ b/app/auth/views/mfa.py
@@ -0,0 +1,52 @@
+import pyotp
+from flask import request, render_template, redirect, url_for, flash, session
+from flask_login import login_user
+from flask_wtf import FlaskForm
+from wtforms import StringField, validators
+
+from app.auth.base import auth_bp
+from app.config import MFA_USER_ID
+from app.log import LOG
+from app.models import User
+
+
+class OtpTokenForm(FlaskForm):
+ token = StringField("Token", validators=[validators.DataRequired()])
+
+
+@auth_bp.route("/mfa", methods=["GET", "POST"])
+def mfa():
+ # passed from login page
+ user_id = session[MFA_USER_ID]
+ user = User.get(user_id)
+
+ if not user.enable_otp:
+ raise Exception("Only user with MFA enabled should go to this page. %s", user)
+
+ otp_token_form = OtpTokenForm()
+ next_url = request.args.get("next")
+
+ if otp_token_form.validate_on_submit():
+ totp = pyotp.TOTP(user.otp_secret)
+
+ if otp_token_form.validate_on_submit():
+ token = otp_token_form.token.data
+
+ if totp.verify(token):
+ del session[MFA_USER_ID]
+
+ login_user(user)
+ flash(f"Welcome back {user.name}!")
+
+ # User comes to login page from another page
+ if next_url:
+ LOG.debug("redirect user to %s", next_url)
+ return redirect(next_url)
+ else:
+ LOG.debug("redirect user to dashboard")
+ return redirect(url_for("dashboard.index"))
+
+ else:
+ flash("Incorrect token", "warning")
+
+ return render_template("auth/mfa.html", otp_token_form=otp_token_form)