diff --git a/backend/MESSAGE_CODES b/backend/MESSAGE_CODES
new file mode 100644
index 0000000000000000000000000000000000000000..bc46a5b8d21ecd96827b3e9a2c5f41f0d3c8bf30
--- /dev/null
+++ b/backend/MESSAGE_CODES
@@ -0,0 +1,21 @@
+
+
+List of message codes used in the frontend
+
+
+
+Kratos codes:
+=============
+
+4000006 The provided credentials are invalid, check for spelling mistakes 
+        in your password or username, email address, or phone number.
+
+
+1010003 Please confirm this action by verifying that it is you.
+
+
+Stackspin codes:
+================
+
+S_CONFIRM_CREDENTIALS   Please confirm your credentials to complete this action.
+
diff --git a/backend/web/login/login.py b/backend/web/login/login.py
index 99851d29d462201163971db83884eba015fb27b7..424767b3e98455004181b7d9d1ee4c02e28c518a 100644
--- a/backend/web/login/login.py
+++ b/backend/web/login/login.py
@@ -131,12 +131,52 @@ def login():
     # Check if we are logged in:
     identity = get_auth()
 
+    # List to contain messages pushed to the frontend
+    messages = list()
+
+
     refresh = False
     flow = request.args.get("flow")
     if flow:
         cookies = request.headers['cookie']
         flow = kratos_public_frontend_api.get_login_flow(flow, cookie=cookies)
         refresh = flow['refresh']
+        if refresh:
+            message = {
+                "id": "S_CONFIRM_CREDENTIALS",
+                "message": "Please confirm your credentials to complete this action.",
+                "type": "info"
+            }
+            messages.append(message)
+        try:
+            for msg in flow.ui.messages.value:
+                current_app.logger.info("Kratos message:" + msg.text)
+                if msg.id == 4000006:
+                    message = {
+                        "id": msg.id,
+                        "message": "The provided login e-mail address or password is incorrect. Please try again.",
+                        "type": "error"
+                    }
+                else:
+                    message = {
+                        "id": msg.id,
+                        "message": msg.text,
+                    }
+
+                    if msg.type == 'error':
+                        message['type'] = 'error'
+                    else:
+                        message['type'] = 'info'
+
+                messages.append(message)
+
+        except ory_kratos_client.exceptions.ApiAttributeError as ex:
+            # This exception is expected when there are no messages
+            pass
+        except Exception as ex:
+            # An unkown exception happens, we log the error but continue as it
+            # only affects the messages part
+            current_app.logger.error("Unknown exception: " + str(ex))
 
     if identity and not refresh:
         # We are already logged in, and don't need to refresh.
@@ -164,7 +204,9 @@ def login():
     # or `not identity`
     #     User is not logged in yet.
     # In either case, we present the login screen now.
-    return render_template("login.html", api_url=KRATOS_PUBLIC_URL, dashboard_url=DASHBOARD_URL, refresh=refresh, demo=DEMO_INSTANCE)
+    return render_template("login.html", api_url=KRATOS_PUBLIC_URL,
+            dashboard_url=DASHBOARD_URL, messages=messages,
+            demo=DEMO_INSTANCE)
 
 
 @web.route("/auth", methods=["GET", "POST"])
diff --git a/backend/web/static/base.js b/backend/web/static/base.js
index a2cf2f18a5dbde19742883e1de748804a8a997f1..3499d5fe83ee651be147a294349aa5584a0773a1 100644
--- a/backend/web/static/base.js
+++ b/backend/web/static/base.js
@@ -20,6 +20,24 @@
 // before calling the scripts (and configured by the flask app
 var dashboard_url = '';
 
+// Render a message by appending the data to the messages box. The message id is
+// availble, potentially for future translations/locale handling
+// @param string id        Message ID\
+// @param string message   Message in the default language (English)
+// @param string type      Type of message, currently only "error" renders in
+//                         'danger'. Others render in 'info'
+function renderMessage(id, message, type) {
+    // Default class for messages
+    var class_name = 'info';
+    if (type == 'error') {
+        class_name = 'danger';
+    }
+    let html = '<div class="alert alert-'+class_name+'">';
+    html = html + message
+    html = html + "</div>";
+    $("#messages").append( html );
+}
+
 // Check if an auth flow is configured and redirect to auth page in that
 // case.
 function check_flow_auth() {
diff --git a/backend/web/templates/base.html b/backend/web/templates/base.html
index 081453028d4f0b389f77dbac03dbd0056cc2cb1b..e2db15b126e52964fe23d905c4d08a65f37ca77b 100644
--- a/backend/web/templates/base.html
+++ b/backend/web/templates/base.html
@@ -13,6 +13,7 @@
 
 <body>
 
+
 <script>
     var api_url = '{{ api_url }}';
 
@@ -34,6 +35,8 @@
 
 <a href="{{ dashboard_url }}"><img src='static/logo.svg'/></a><br/><br/>
 
+    <div id='messages'></div>
+
 {% block content %}{% endblock %}
 
 
diff --git a/backend/web/templates/login.html b/backend/web/templates/login.html
index 6b1f04731b972f72b969407dd05e02fdf5f9cee8..79db1512e62920d9c24866caf1c3f6be0c85ceb3 100644
--- a/backend/web/templates/login.html
+++ b/backend/web/templates/login.html
@@ -12,12 +12,12 @@
         flow_login();
     });
 
+    // Render messages
+    {% for message in messages %}
+        renderMessage('{{ message['id'] }}', '{{ message['message'] }}', '{{ message['type'] }}');
+    {% endfor %}
 </script>
 
-
-{% if refresh %}
-    <div class="alert alert-warning">Please confirm your credentials to complete this action.</div>
-{% endif %}
     <div id="contentMessages"></div>
     <div id="contentLogin_password"></div>
     <div id="contentLogin_totp"></div>