Skip to content

Commit a51cf36

Browse files
committed
Testing Immediate webauthn
1 parent 264a3ac commit a51cf36

File tree

3 files changed

+99
-47
lines changed

3 files changed

+99
-47
lines changed

example/test_app/templates/login.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@
3939
</div>
4040
<div class="form-group">
4141
<div class="form-label-group">
42-
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password">
42+
<input type="password" id="inputPassword" autocomplete="current-password" name="password" class="form-control" placeholder="Password">
4343
<label for="inputPassword">Password</label>
4444
</div>
4545
</div>
4646
<input type="hidden" name="passkeys" id="passkeys"/>
47-
<button class="btn btn-primary btn-block" type="submit">Login</button><br/>
47+
<button class="btn btn-primary btn-block" type="button" onclick="tryLogin('loginForm')" >Login</button><br/>
4848
<button class="btn btn-block btn-dark" type="button" onclick="authn('loginForm')"><img src="{% static 'passkeys/imgs/FIDO-Passkey_Icon-White.png' %}" style="width: 24px"> &nbsp;Login By Passkeys</button>
4949
{%include 'passkeys.js' %}
5050
</form>

passkeys/templates/check_passkeys.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ function check_passkey(platform_authenticator = true,success_func, fail_func)
88
if (available) {
99
success_func();
1010
}
11+
else{
12+
fail_func();
13+
}
14+
1115
else{
1216
fail_func();
1317
}

passkeys/templates/passkeys.js

Lines changed: 93 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2,78 +2,126 @@
22
<script type="application/javascript" src="{% static 'passkeys/js/base64url.js' %}"></script>
33
<script type="application/javascript" src="{% static 'passkeys/js/helpers.js' %}"></script>
44
<script type="text/javascript">
5-
window.conditionalUI=false;
5+
window.allow_immediate=true;
6+
async function checkImmediateMediationAvailability() {
7+
if (!window.allow_immediate)
8+
return [false, false];
9+
try {
10+
const capabilities = await PublicKeyCredential.getClientCapabilities();
11+
if (capabilities.immediateGet && window.PasswordCredential) {
12+
console.log("Immediate Mediation with passwords supported.");
13+
return [true, true];
14+
} else if (capabilities.immediateGet) {
15+
console.log("Immediate Mediation without passwords supported.");
16+
return [true, false];
17+
} else {
18+
console.log("Immediate Mediation unsupported.");
19+
return [false, false];}
20+
} catch (error) {
21+
console.error("Error getting client capabilities:", error);
22+
return [false, false];
23+
}
24+
}
25+
26+
function tryLogin(formid)
27+
{
28+
window.loginForm = formid;
29+
if ($("#inputUsername").val() != "" && $("#inputPassword").val() != "")
30+
$("#" + formid).submit();
31+
options = {};
32+
status = checkImmediateMediationAvailability();
33+
if (status[0] && window.allow_immediate)
34+
{
35+
start_authn(formid, false);
36+
}
37+
}
38+
window.conditionalUI = false;
639
window.conditionUIAbortController = new AbortController();
740
window.conditionUIAbortSignal = conditionUIAbortController.signal;
841
function checkConditionalUI(form) {
9-
if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) {
10-
// Check if conditional mediation is available.
11-
PublicKeyCredential.isConditionalMediationAvailable().then((result) => {
12-
window.conditionalUI = result;
13-
if (window.conditionalUI) {
14-
start_authn(form,true)
15-
}
42+
if (window.PublicKeyCredential && PublicKeyCredential.isConditionalMediationAvailable) {
43+
// Check if conditional mediation is available.
44+
PublicKeyCredential.isConditionalMediationAvailable().then((result) => {
45+
window.conditionalUI = result;
46+
if (window.conditionalUI) {
47+
start_authn(form,true)
48+
}
1649
});
1750
}
1851
}
1952

20-
var GetAssertReq = (getAssert) => {
21-
getAssert.publicKey.challenge = base64url.decode(getAssert.publicKey.challenge);
53+
var GetAssertReq = (getAssert) => {
54+
getAssert.publicKey.challenge = base64url.decode(getAssert.publicKey.challenge);
2255

23-
for(let allowCred of getAssert.publicKey.allowCredentials) {
24-
allowCred.id = base64url.decode(allowCred.id);
25-
}
56+
for(let allowCred of getAssert.publicKey.allowCredentials) {
57+
allowCred.id = base64url.decode(allowCred.id);
58+
}
2659

27-
return getAssert
28-
}
60+
return getAssert
61+
}
2962

30-
function start_authn(form,conditionalUI=false)
31-
{
32-
window.loginForm=form;
33-
fetch('{% url 'passkeys:auth_begin' %}', {
34-
method: 'GET',
63+
function start_authn(form, conditionalUI = false)
64+
{
65+
window.loginForm = form;
66+
fetch('{% url 'passkeys:auth_begin' %}', {
67+
method: 'GET',
3568
}).then(function(response) {
36-
if(response.ok) {
37-
return response.json().then(function (req){
38-
return GetAssertReq(req)
39-
});
40-
}
41-
throw new Error('No credential available to authenticate!');
69+
if(response.ok) {
70+
return response.json().then(function (req){
71+
return GetAssertReq(req)
72+
});
73+
}
74+
throw new Error('No credential available to authenticate!');
4275
}).then(function(options) {
4376
if (conditionalUI) {
4477
options.mediation = 'conditional';
4578
options.signal = window.conditionUIAbortSignal;
4679
}
4780
else
48-
window.conditionUIAbortController.abort()
81+
{
82+
window.conditionUIAbortController.abort('Stopping conditional UI');
83+
options.mediation = 'immediate';
84+
options.password = true;
85+
}
4986
console.log(options)
50-
return navigator.credentials.get(options);
87+
return navigator.credentials.get(options);
5188
}).then(function(assertion) {
5289
pk = $("#passkeys")
5390
if (pk.length == 0)
54-
{
55-
console.error("Did you add the 'passkeys' hidden input field")
56-
return
57-
}
91+
{
92+
console.error("Did you add the 'passkeys' hidden input field")
93+
return
94+
}
5895
pk.val(JSON.stringify(publicKeyCredentialToJSON(assertion)));
5996
x= document.getElementById(window.loginForm)
6097
if (x === null || x === undefined)
61-
{
62-
console.error("Did you pass the correct form id to auth function")
63-
return;
64-
}
65-
x.submit()
98+
{
99+
console.error("Did you pass the correct form id to auth function")
100+
return;
101+
}
102+
x.submit()
103+
104+
}).catch(function (err)
105+
{
66106

67-
});
68-
$(document).ready(function () {
107+
if (err.toString() === 'NotAllowedError: No immediate discoverable credentials are found.') {
108+
window.allow_immediate = false;
109+
tryLogin(window.loginForm);
110+
}
111+
else {
112+
console.error("Authentication failed: " + err);
113+
}
114+
115+
});
116+
$(document).ready(function () {
69117
if (location.protocol != 'https:') {
70-
console.error("Passkeys must work under secure context")
71-
}
118+
console.error("Passkeys must work under secure context")
119+
}
72120
});
73-
}
74-
function authn(form)
121+
}
122+
function authn(form)
75123
{
76-
start_authn(form,false)
124+
start_authn(form, false)
77125
}
78126

79-
</script>
127+
</script>

0 commit comments

Comments
 (0)