diff --git a/lenticular_cloud/template/frontend/app_token.html.j2 b/lenticular_cloud/template/frontend/app_token.html.j2
new file mode 100644
index 0000000..3bd09ef
--- /dev/null
+++ b/lenticular_cloud/template/frontend/app_token.html.j2
@@ -0,0 +1,60 @@
+{% extends 'frontend/base.html.j2' %}
+
+{% block title %}{{ gettext('client certs') }}{% endblock %}
+
+{% block content %}
+
+
+
+ {% for service in services.values() if service.client_cert %}
+
+
+
+
+
+ not valid before |
+ not valid after |
+ serial_number |
+ | |
+ |
+
+
+ {% for cert in client_certs[service.name] %}
+
+ {{ cert.not_valid_before }} |
+ {{ cert.not_valid_after }} |
+ {{ cert.serial_number_hex }} |
+
+
+
+ {% if cert.is_valid %}
+
+ {% endif %}
+ |
+
+ {% endfor %}
+
+
+ New Certificate
+
+
+ {% endfor %}
+
+
+
+{% endblock %}
+
+
+{% block script_js %}
+
+client_cert.init_list();
+
+
+{% endblock %}
diff --git a/lenticular_cloud/template/frontend/app_token_new.html.j2 b/lenticular_cloud/template/frontend/app_token_new.html.j2
new file mode 100644
index 0000000..c03f3d6
--- /dev/null
+++ b/lenticular_cloud/template/frontend/app_token_new.html.j2
@@ -0,0 +1,45 @@
+{% extends 'frontend/base.html.j2' %}
+
+{% block title %}{{ gettext('new client cert - {service_name}').format(service_name=service.name) }}{% endblock %}
+
+{% block content %}
+
+
+
Generate new key in the browser
+
+ {{ render_form(form) }}
+
+
+
+
Save Keypair
+{% endblock %}
+
+
+
diff --git a/lenticular_cloud/template/frontend/base.html.j2 b/lenticular_cloud/template/frontend/base.html.j2
index 03cc4b4..670613e 100644
--- a/lenticular_cloud/template/frontend/base.html.j2
+++ b/lenticular_cloud/template/frontend/base.html.j2
@@ -18,6 +18,7 @@
{#
#}
{{ gettext('Account') }}
{{ gettext('Client Cert') }}
+
{{ gettext('App Tokens') }}
{{ gettext('2FA - TOTP') }}
{{ gettext('Oauth2 Tokens') }}
{{ gettext('Password Change') }}
diff --git a/lenticular_cloud/views/frontend.py b/lenticular_cloud/views/frontend.py
index c05d4f4..bc79508 100644
--- a/lenticular_cloud/views/frontend.py
+++ b/lenticular_cloud/views/frontend.py
@@ -133,6 +133,17 @@ def client_cert_new(service_name) -> ResponseReturnValue:
service=service,
form=form)
+@frontend_views.route('/app_token')
+def app_token() -> ResponseReturnValue:
+ return
+
+@frontend_views.route('/app_token/
/new')
+def app_token_new(service_name: str) -> ResponseReturnValue:
+ return
+
+@frontend_views.route('/app_token//')
+def app_token_delete(service_name: str, token_name: str) -> ResponseReturnValue:
+ return
@frontend_views.route('/totp')
def totp() -> ResponseReturnValue: