diff --git a/web/packages/teleport/src/Account/ChangePasswordWizard/ChangePasswordWizard.tsx b/web/packages/teleport/src/Account/ChangePasswordWizard/ChangePasswordWizard.tsx index a5eb1e8fc7204..4d4f40a4f49c4 100644 --- a/web/packages/teleport/src/Account/ChangePasswordWizard/ChangePasswordWizard.tsx +++ b/web/packages/teleport/src/Account/ChangePasswordWizard/ChangePasswordWizard.tsx @@ -65,7 +65,7 @@ export function ChangePasswordWizard({ const reauthState = useReAuthenticate({ challengeScope: MfaChallengeScope.CHANGE_PASSWORD, onMfaResponse: async mfaResponse => - setWebauthnResponse(mfaResponse.webauthn_response), + setWebauthnResponse(mfaResponse?.webauthn_response), }); const [reauthMethod, setReauthMethod] = useState(); diff --git a/web/packages/teleport/src/lib/term/tty.ts b/web/packages/teleport/src/lib/term/tty.ts index 3e924ff466f3f..7c50a38ee9a38 100644 --- a/web/packages/teleport/src/lib/term/tty.ts +++ b/web/packages/teleport/src/lib/term/tty.ts @@ -82,7 +82,7 @@ class Tty extends EventEmitterMfaSender { this.socket.send(bytearray.buffer); } - sendChallengeResponse(data: MfaChallengeResponse) { + sendChallengeResponse(resp: MfaChallengeResponse) { // we want to have the backend listen on a single message type // for any responses. so our data will look like data.webauthn, data.sso, etc // but to be backward compatible, we need to still spread the existing webauthn only fields @@ -90,8 +90,8 @@ class Tty extends EventEmitterMfaSender { // in 19, we can just pass "data" without this extra step // TODO (avatus): DELETE IN 18 const backwardCompatibleData = { - ...data.webauthn_response, - ...data, + ...resp?.webauthn_response, + ...resp, }; const encoded = this._proto.encodeChallengeResponse( JSON.stringify(backwardCompatibleData) diff --git a/web/packages/teleport/src/services/auth/auth.ts b/web/packages/teleport/src/services/auth/auth.ts index 3724f1dc8b056..e1533ee4d3297 100644 --- a/web/packages/teleport/src/services/auth/auth.ts +++ b/web/packages/teleport/src/services/auth/auth.ts @@ -239,7 +239,7 @@ const auth = { .then(res => { const request = { action: 'accept', - webauthnAssertionResponse: res.webauthn_response, + webauthnAssertionResponse: res?.webauthn_response, }; return api.put(cfg.getHeadlessSsoPath(transactionId), request); @@ -280,7 +280,9 @@ const auth = { challenge: MfaAuthenticateChallenge, mfaType?: DeviceType, totpCode?: string - ): Promise { + ): Promise { + if (!challenge) return; + // TODO(Joerger): If mfaType is not provided by a parent component, use some global context // to display a component, similar to the one used in useMfa. For now we just default to // whichever method we can succeed with first. @@ -303,7 +305,7 @@ const auth = { } // No viable challenge, return empty response. - return null; + return; }, async getWebAuthnChallengeResponse( @@ -387,7 +389,7 @@ const auth = { return auth .getMfaChallenge({ scope, allowReuse, isMfaRequiredRequest }, abortSignal) .then(challenge => auth.getMfaChallengeResponse(challenge, 'webauthn')) - .then(res => res.webauthn_response); + .then(res => res?.webauthn_response); }, getMfaChallengeResponseForAdminAction(allowReuse?: boolean) { diff --git a/web/packages/teleport/src/services/mfa/makeMfa.ts b/web/packages/teleport/src/services/mfa/makeMfa.ts index 505a972fe33e5..4d98503dafa87 100644 --- a/web/packages/teleport/src/services/mfa/makeMfa.ts +++ b/web/packages/teleport/src/services/mfa/makeMfa.ts @@ -63,13 +63,13 @@ export function parseMfaRegistrationChallengeJson( // parseMfaChallengeJson formats fetched authenticate challenge JSON. export function parseMfaChallengeJson( challenge: MfaAuthenticateChallengeJson -): MfaAuthenticateChallenge { +): MfaAuthenticateChallenge | undefined { if ( !challenge.sso_challenge && !challenge.webauthn_challenge && !challenge.totp_challenge ) { - return null; + return; } // WebAuthn challenge contains Base64URL(byte) fields that needs to