Skip to content

Commit 6643fb6

Browse files
authored
Okta 1145765 uber bug (#3995) (#4018)
OKTA-1168850 Okta 1145765 uber bug (#3995) OKTA-1145765 feat: add support for transports and hints - Adds support for transports and hints for WebAuthn - Localizes RP ID mismatch errors
1 parent 8350559 commit 6643fb6

19 files changed

Lines changed: 498 additions & 39 deletions

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@
246246
"webpack-dev-server": "^4.15.2"
247247
},
248248
"dependencies": {
249-
"@okta/okta-auth-js": "7.14.0",
249+
"@okta/okta-auth-js": "7.14.2",
250250
"@sindresorhus/to-milliseconds": "^1.0.0",
251251
"@types/backbone": "^1.4.15",
252252
"@types/eslint-scope": "^3.7.3",

playground/mocks/data/idp/idx/authenticator-enroll-webauthn-custom.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
"authenticatorSelection": {
9898
"userVerification": "discouraged"
9999
},
100+
"hints": ["security-key"],
100101
"u2fParams": {
101102
"appid": "http://idx.okta1.com:1802"
102103
}

playground/mocks/data/idp/idx/authenticator-enroll-webauthn-passkeys.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
"authenticatorSelection": {
9797
"userVerification": "discouraged"
9898
},
99+
"hints": ["client-device"],
99100
"u2fParams": {
100101
"appid": "http://idx.okta1.com:1802"
101102
}

playground/mocks/data/idp/idx/authenticator-enroll-webauthn.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,7 @@
213213
"authenticatorSelection": {
214214
"userVerification": "discouraged"
215215
},
216+
"hints": ["security-key"],
216217
"u2fParams": {
217218
"appid": "http://idx.okta1.com:1802"
218219
}

playground/mocks/data/idp/idx/authenticator-verification-webauthn-custom.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"challengeData": {
6464
"challenge": "qjUCU0xoVe5QZ3-etDCD",
6565
"userVerification": "discouraged",
66+
"hints": ["security-key"],
6667
"extensions": {
6768
"appid": "https://localhost:3000"
6869
}

playground/mocks/data/idp/idx/authenticator-verification-webauthn-passkeys.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@
6363
"challengeData": {
6464
"challenge": "qjUCU0xoVe5QZ3-etDCD",
6565
"userVerification": "discouraged",
66+
"hints": ["client-device"],
6667
"extensions": {
6768
"appid": "https://localhost:3000"
6869
}

playground/mocks/data/idp/idx/authenticator-verification-webauthn.json

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,7 @@
189189
"challengeData": {
190190
"challenge": "qjUCU0xoVe5QZ3-etDCD",
191191
"userVerification": "required",
192+
"hints": ["security-key"],
192193
"extensions": {
193194
"appid": "https://localhost:3000"
194195
}
@@ -297,15 +298,17 @@
297298
"key": "webauthn",
298299
"id": "autwa6eD9o02iBbtv0g2",
299300
"authenticatorId": "aidtheidkwh282hv8g3",
300-
"credentialId": "hpxQXbu5R5Y2JMqpvtE9Oo9FdwO6z2kMR-ZQkAb6p6GSguXQ57oVXKvpVHT2fyCR_m2EL1vIgszxi00kyFIX6w"
301+
"credentialId": "hpxQXbu5R5Y2JMqpvtE9Oo9FdwO6z2kMR-ZQkAb6p6GSguXQ57oVXKvpVHT2fyCR_m2EL1vIgszxi00kyFIX6w",
302+
"transports": ["usb", "nfc"]
301303
},
302304
{
303305
"displayName": "MacBook Touch ID",
304306
"type": "security_key",
305307
"key": "webauthn",
306308
"id": "autwa6eD9o02iBbtv0g2",
307309
"authenticatorId": "fwftheidkwh282hv8g3",
308-
"credentialId": "7Ag2iWUqfz0SanWDj-ZZ2fpDsgiEDt_08O1VSSRZHpgkUS1zhLSyWYDrxXXB5VE_w1iiqSvPaRgXcmG5rPwB-w"
310+
"credentialId": "7Ag2iWUqfz0SanWDj-ZZ2fpDsgiEDt_08O1VSSRZHpgkUS1zhLSyWYDrxXXB5VE_w1iiqSvPaRgXcmG5rPwB-w",
311+
"transports": ["internal"]
309312
},
310313
{
311314
"displayName": "Okta Email",

src/v2/view-builder/views/IdentifierView.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,12 @@ const Body = BaseForm.extend({
370370
.then((assertion) => {
371371
this.remediateWithAssertion(assertion, RemediationForms.LAUNCH_PASSKEYS_AUTHENTICATOR);
372372
}, (error) => {
373+
if (webauthn.isRelyingPartyIdMismatchError(error)) {
374+
const rpId = this.options.appState.get('webauthnAutofillUIChallenge')?.challengeData?.rpId;
375+
const errorSummary = loc('signin.passkeys.error.rpIdMismatch', 'login', [rpId]);
376+
this.model.trigger('error', this.model, this._generateErrorObject(errorSummary));
377+
return;
378+
}
373379
this._handleWebAuthnError(error);
374380
})
375381
.finally(() => {

src/v2/view-builder/views/webauthn/ChallengeWebauthnView.js

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,15 @@ const Body = BaseForm.extend({
8484
const authenticatorEnrollments = this.options.appState.get('authenticatorEnrollments')?.value || [];
8585
authenticatorEnrollments.forEach((enrollement) => {
8686
if (enrollement.key === 'webauthn') {
87-
allowCredentials.push({
87+
const credential = {
8888
type: 'public-key',
8989
id: CryptoUtil.strToBin(enrollement.credentialId),
90-
});
90+
};
91+
const transports = enrollement.transports ?? enrollement.profile?.transports;
92+
if (Array.isArray(transports)) {
93+
credential.transports = transports;
94+
}
95+
allowCredentials.push(credential);
9196
}
9297
});
9398
const challengeData = authenticatorData.contextualData.challengeData;
@@ -118,6 +123,21 @@ const Body = BaseForm.extend({
118123
});
119124
this.saveForm(this.model);
120125
}, (error) => {
126+
// Override the default browser RP ID mismatch error in order to provide
127+
// a more user friendly error and have it localized
128+
if (webauthn.isRelyingPartyIdMismatchError(error)) {
129+
this.model.trigger('error', this.model, {
130+
responseJSON: {
131+
errorSummary: loc(
132+
'signin.passkeys.error.rpIdMismatch',
133+
'login',
134+
[authenticatorData.contextualData.challengeData.rpId]
135+
)
136+
}
137+
});
138+
return;
139+
}
140+
121141
// Do not display if it is abort error triggered by code when switching.
122142
// this.webauthnAbortController would be null if abort was triggered by code.
123143
if (this.webauthnAbortController) {

src/v2/view-builder/views/webauthn/EnrollWebauthnView.js

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,15 @@ function getExcludeCredentials(authenticatorEnrollments = []) {
1212
const credentials = [];
1313
authenticatorEnrollments.forEach((enrollement) => {
1414
if (enrollement.key === 'webauthn') {
15-
credentials.push({
15+
const credential = {
1616
type: 'public-key',
1717
id: CryptoUtil.strToBin(enrollement.credentialId),
18-
});
18+
};
19+
const transports = enrollement.transports ?? enrollement.profile?.transports;
20+
if (Array.isArray(transports)) {
21+
credential.transports = transports;
22+
}
23+
credentials.push(credential);
1924
}
2025
});
2126
return credentials;
@@ -86,19 +91,31 @@ const Body = BaseForm.extend({
8691
publicKey: options,
8792
signal: this.webauthnAbortController && this.webauthnAbortController.signal
8893
}).then((newCredential) => {
94+
// example data: ["nfc", "usb"]
95+
const transports =
96+
webauthn.processWebAuthnResponse(newCredential.response.getTransports, newCredential.response);
8997
this.model.set({
9098
credentials : {
9199
clientData: CryptoUtil.binToStr(newCredential.response.clientDataJSON),
92100
attestation: CryptoUtil.binToStr(newCredential.response.attestationObject),
93-
// example data: ["nfc", "usb"]
94-
transports: webauthn.processWebAuthnResponse(newCredential.response.getTransports, newCredential.response),
101+
...(transports !== null && { transports }),
95102
// example data: {"credProps":{"rk":true}}
96103
clientExtensions: webauthn.processWebAuthnResponse(newCredential.getClientExtensionResults, newCredential)
97104
}
98105
});
99106
this.saveForm(this.model);
100107
})
101108
.catch((error) => {
109+
// Override the default browser RP ID mismatch error in order to provide
110+
// a more user friendly error and have it localized
111+
if (webauthn.isRelyingPartyIdMismatchError(error)) {
112+
this.model.trigger('error', this.model, {
113+
responseJSON: {
114+
errorSummary: loc('signin.passkeys.error.SecurityError', 'login')
115+
}
116+
});
117+
return;
118+
}
102119
this.model.trigger('error', this.model, {responseJSON: {errorSummary: getMessageFromBrowserError(error)}});
103120
}).finally(() => {
104121
this.webauthnAbortController = null;

0 commit comments

Comments
 (0)