diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000000000000000000000000000000000000..347cf2a9073124b259908bfa7bb8f851ce0af5ef
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+# Versions from Debian Buster
+ldap3==2.4.1
+flask==1.0.2
+Flask-SQLAlchemy==2.1
+qrcode==6.1
+fido2==0.5.0
+Flask-OAuthlib==0.9.5
diff --git a/uffd/mfa/views.py b/uffd/mfa/views.py
index 2237db2d6f3ab03ca504f34797cd81c8f68354f7..408e6a982e1d65edf09735b98b58ca7753e9d742 100644
--- a/uffd/mfa/views.py
+++ b/uffd/mfa/views.py
@@ -1,9 +1,8 @@
 from flask import Blueprint, render_template, session, request, redirect, url_for, flash, current_app
 import urllib.parse
 
-from fido2.webauthn import PublicKeyCredentialRpEntity, UserVerificationRequirement
 from fido2.client import ClientData
-from fido2.server import Fido2Server
+from fido2.server import Fido2Server, RelyingParty
 from fido2.ctap2 import AttestationObject, AuthenticatorData
 from fido2 import cbor
 
@@ -104,7 +103,7 @@ def delete_totp(id):
 	return redirect(url_for('mfa.setup'))
 
 def get_webauthn_server():
-	return Fido2Server(PublicKeyCredentialRpEntity(urllib.parse.urlsplit(request.url).hostname, "uffd"))
+	return Fido2Server(RelyingParty(urllib.parse.urlsplit(request.url).hostname, "uffd"))
 
 @bp.route('/setup/webauthn/begin', methods=['POST'])
 @login_required()
@@ -123,11 +122,10 @@ def setup_webauthn_begin():
 			"displayName": user.displayname,
 		},
 		creds,
-		user_verification=UserVerificationRequirement.DISCOURAGED,
-		authenticator_attachment="cross-platform",
+		user_verification='discouraged',
 	)
 	session["webauthn-state"] = state
-	return cbor.encode(registration_data)
+	return cbor.dumps(registration_data)
 
 @bp.route('/setup/webauthn/complete', methods=['POST'])
 @login_required()
@@ -135,7 +133,7 @@ def setup_webauthn_begin():
 def setup_webauthn_complete():
 	user = get_current_user()
 	server = get_webauthn_server()
-	data = cbor.decode(request.get_data())
+	data = cbor.loads(request.get_data())[0]
 	client_data = ClientData(data["clientDataJSON"])
 	att_obj = AttestationObject(data["attestationObject"])
 	auth_data = server.register_complete(session["webauthn-state"], client_data, att_obj)
@@ -143,7 +141,7 @@ def setup_webauthn_complete():
 	db.session.add(method)
 	db.session.commit()
 	print("REGISTERED CREDENTIAL:", auth_data.credential_data)
-	return cbor.encode({"status": "OK"})
+	return cbor.dumps({"status": "OK"})
 
 @bp.route('/setup/webauthn/<int:id>/delete')
 @login_required()
@@ -163,9 +161,9 @@ def auth_webauthn_begin():
 	creds = [method.cred_data.credential_data for method in methods]
 	if not creds:
 		abort(404)
-	auth_data, state = server.authenticate_begin(creds, user_verification=UserVerificationRequirement.DISCOURAGED)
+	auth_data, state = server.authenticate_begin(creds, user_verification='discouraged')
 	session["webauthn-state"] = state
-	return cbor.encode(auth_data)
+	return cbor.dumps(auth_data)
 
 @bp.route("/auth/webauthn/complete", methods=["POST"])
 def auth_webauthn_complete():
@@ -175,7 +173,7 @@ def auth_webauthn_complete():
 	creds = [method.cred_data.credential_data for method in methods]
 	if not creds:
 		abort(404)
-	data = cbor.decode(request.get_data())
+	data = cbor.loads(request.get_data())[0]
 	credential_id = data["credentialId"]
 	client_data = ClientData(data["clientDataJSON"])
 	auth_data = AuthenticatorData(data["authenticatorData"])
@@ -189,7 +187,7 @@ def auth_webauthn_complete():
 		signature,
 	)
 	session['user_mfa'] = True
-	return cbor.encode({"status": "OK"})
+	return cbor.dumps({"status": "OK"})
 
 @bp.route('/auth', methods=['GET'])
 @login_required(skip_mfa=True)