Skip to content

Commit 3b100bc

Browse files
Add support for proper e2e testing for the sign in functionality of passkey
1 parent 8a149f9 commit 3b100bc

File tree

7 files changed

+886
-36
lines changed

7 files changed

+886
-36
lines changed

examples/for-tests-react-16/src/App.js

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -907,11 +907,55 @@ function getWebauthnConfigs({ throwWebauthnError, webauthnErrorStatus }) {
907907
log(`GET REGISTER OPTIONS`);
908908
return implementation.getRegisterOptions(...args);
909909
},
910-
getSignInOptions(...args) {
910+
async getSignInOptions(...args) {
911911
log(`GET SIGN IN OPTIONS`);
912912
return implementation.getSignInOptions(...args);
913913
},
914-
signIn(...args) {
914+
async authenticateCredential(...args) {
915+
log("AUTHENTICATE CREDENTIAL");
916+
917+
// We will make a network call to get the registration options
918+
// for sign up.
919+
// Then we will use the registrationOptions and the passed args
920+
// to create and assert a credential.
921+
922+
const email = `${Math.random().toString().slice(2)}@supertokens.com`;
923+
const registrationOptions = await implementation.getRegisterOptions({
924+
userContext: {},
925+
email,
926+
});
927+
const signInOptions = args[0].authenticationOptions;
928+
929+
const response = await fetch(`${getApiDomain()}/test/webauthn/create-and-assert-credential`, {
930+
method: "POST",
931+
body: JSON.stringify({
932+
registerOptionsResponse: registrationOptions,
933+
signInOptionsResponse: signInOptions,
934+
rpId: "localhost",
935+
rpName: "localhost",
936+
origin: "http://localhost:3031",
937+
}),
938+
headers: {
939+
"Content-Type": "application/json",
940+
},
941+
});
942+
943+
if (!response.ok) {
944+
throw new STGeneralError("TEST ERROR: CREATING CREDENTIAL FAILED");
945+
}
946+
947+
const { attestation, assertion } = (await response.json()).credential;
948+
949+
// Sign up the user using the attestation;
950+
await implementation.signUp({
951+
webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId,
952+
credential: attestation,
953+
userContext: {},
954+
});
955+
956+
return { authenticationResponse: assertion, status: "OK" };
957+
},
958+
async signIn(...args) {
915959
log(`SIGN IN`);
916960
return implementation.signIn(...args);
917961
},
@@ -953,11 +997,7 @@ function getWebauthnConfigs({ throwWebauthnError, webauthnErrorStatus }) {
953997
};
954998
}
955999

956-
return {
957-
status: "OK",
958-
user: {},
959-
fetchResponse: {},
960-
};
1000+
return implementation.authenticateCredentialWithSignIn(...args);
9611001
},
9621002
};
9631003
},

examples/for-tests/src/App.js

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1169,11 +1169,55 @@ function getWebauthnConfigs({ throwWebauthnError, webauthnErrorStatus }) {
11691169
log(`GET REGISTER OPTIONS`);
11701170
return implementation.getRegisterOptions(...args);
11711171
},
1172-
getSignInOptions(...args) {
1172+
async getSignInOptions(...args) {
11731173
log(`GET SIGN IN OPTIONS`);
11741174
return implementation.getSignInOptions(...args);
11751175
},
1176-
signIn(...args) {
1176+
async authenticateCredential(...args) {
1177+
log("AUTHENTICATE CREDENTIAL");
1178+
1179+
// We will make a network call to get the registration options
1180+
// for sign up.
1181+
// Then we will use the registrationOptions and the passed args
1182+
// to create and assert a credential.
1183+
1184+
const email = `${Math.random().toString().slice(2)}@supertokens.com`;
1185+
const registrationOptions = await implementation.getRegisterOptions({
1186+
userContext: {},
1187+
email,
1188+
});
1189+
const signInOptions = args[0].authenticationOptions;
1190+
1191+
const response = await fetch(`${getApiDomain()}/test/webauthn/create-and-assert-credential`, {
1192+
method: "POST",
1193+
body: JSON.stringify({
1194+
registerOptionsResponse: registrationOptions,
1195+
signInOptionsResponse: signInOptions,
1196+
rpId: "localhost",
1197+
rpName: "localhost",
1198+
origin: "http://localhost:3031",
1199+
}),
1200+
headers: {
1201+
"Content-Type": "application/json",
1202+
},
1203+
});
1204+
1205+
if (!response.ok) {
1206+
throw new STGeneralError("TEST ERROR: CREATING CREDENTIAL FAILED");
1207+
}
1208+
1209+
const { attestation, assertion } = (await response.json()).credential;
1210+
1211+
// Sign up the user using the attestation;
1212+
await implementation.signUp({
1213+
webauthnGeneratedOptionsId: registrationOptions.webauthnGeneratedOptionsId,
1214+
credential: attestation,
1215+
userContext: {},
1216+
});
1217+
1218+
return { authenticationResponse: assertion, status: "OK" };
1219+
},
1220+
async signIn(...args) {
11771221
log(`SIGN IN`);
11781222
return implementation.signIn(...args);
11791223
},
@@ -1215,11 +1259,7 @@ function getWebauthnConfigs({ throwWebauthnError, webauthnErrorStatus }) {
12151259
};
12161260
}
12171261

1218-
return {
1219-
status: "OK",
1220-
user: {},
1221-
fetchResponse: {},
1222-
};
1262+
return implementation.authenticateCredentialWithSignIn(...args);
12231263
},
12241264
};
12251265
},

lib/build/webauthnprebuiltui.js

Lines changed: 3 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/end-to-end/webauthn.signin.test.js

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
screenshotOnFailure,
77
clearBrowserCookiesWithoutAffectingConsole,
88
toggleSignInSignUp,
9-
getTestEmail,
9+
setEnabledRecipes,
1010
waitForSTElement,
1111
submitForm,
1212
} from "../helpers";
@@ -25,6 +25,8 @@ describe("SuperTokens Webauthn SignIn", () => {
2525
method: "POST",
2626
}).catch(console.error);
2727

28+
await setEnabledRecipes(["webauthn", "emailpassword", "session", "dashboard", "userroles"]);
29+
2830
browser = await setupBrowser();
2931
page = await browser.newPage();
3032
page.on("console", (consoleObj) => {
@@ -57,13 +59,28 @@ describe("SuperTokens Webauthn SignIn", () => {
5759
});
5860

5961
describe("SignIn test", () => {
60-
it("should be able to sign in with webauthn", async () => {
62+
it("signup with passkey", async () => {
6163
await tryWebauthnSignIn(page);
64+
65+
// Most of the sign-in mock is defined in the override for the web
66+
// test server.
67+
//
68+
// In here, we are just asserting the logs to ensure that all the necessary
69+
// functions are being called in the correct order and all of them are present.
70+
6271
assert.deepStrictEqual(consoleLogs, [
6372
"ST_LOGS SESSION OVERRIDE ADD_FETCH_INTERCEPTORS_AND_RETURN_MODIFIED_FETCH",
6473
"ST_LOGS SESSION OVERRIDE ADD_AXIOS_INTERCEPTORS",
6574
"ST_LOGS WEBAUTHN OVERRIDE AUTHENTICATE CREDENTIAL WITH SIGN IN",
66-
"ST_LOGS SUPERTOKENS GET_REDIRECTION_URL TO_AUTH",
75+
"ST_LOGS WEBAUTHN OVERRIDE GET SIGN IN OPTIONS",
76+
"ST_LOGS WEBAUTHN PRE_API_HOOKS SIGN_IN_OPTIONS",
77+
"ST_LOGS WEBAUTHN OVERRIDE AUTHENTICATE CREDENTIAL",
78+
"ST_LOGS WEBAUTHN PRE_API_HOOKS REGISTER_OPTIONS",
79+
"ST_LOGS WEBAUTHN PRE_API_HOOKS SIGN_UP",
80+
"ST_LOGS SESSION ON_HANDLE_EVENT SESSION_CREATED",
81+
"ST_LOGS SESSION OVERRIDE GET_USER_ID",
82+
"ST_LOGS WEBAUTHN OVERRIDE SIGN IN",
83+
"ST_LOGS WEBAUTHN PRE_API_HOOKS SIGN_IN",
6784
]);
6885
});
6986
it("should recover successfully from a recoverable error", async () => {

0 commit comments

Comments
 (0)