@aws-amplify/auth
Version:
Auth category of aws-amplify
177 lines (174 loc) • 7.69 kB
JavaScript
import { createAssertionFunction, AmplifyError, AmplifyErrorCode } from '@aws-amplify/core/internals/utils';
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
class PasskeyError extends AmplifyError {
constructor(params) {
super(params);
// Hack for making the custom error class work when transpiled to es5
// TODO: Delete the following 2 lines after we change the build target to >= es2015
this.constructor = PasskeyError;
Object.setPrototypeOf(this, PasskeyError.prototype);
}
}
var PasskeyErrorCode;
(function (PasskeyErrorCode) {
// not supported
PasskeyErrorCode["PasskeyNotSupported"] = "PasskeyNotSupported";
// duplicate passkey
PasskeyErrorCode["PasskeyAlreadyExists"] = "PasskeyAlreadyExists";
// misconfigurations
PasskeyErrorCode["InvalidPasskeyRegistrationOptions"] = "InvalidPasskeyRegistrationOptions";
PasskeyErrorCode["InvalidPasskeyAuthenticationOptions"] = "InvalidPasskeyAuthenticationOptions";
PasskeyErrorCode["RelyingPartyMismatch"] = "RelyingPartyMismatch";
// failed credential creation / retrieval
PasskeyErrorCode["PasskeyRegistrationFailed"] = "PasskeyRegistrationFailed";
PasskeyErrorCode["PasskeyRetrievalFailed"] = "PasskeyRetrievalFailed";
// cancel / aborts
PasskeyErrorCode["PasskeyRegistrationCanceled"] = "PasskeyRegistrationCanceled";
PasskeyErrorCode["PasskeyAuthenticationCanceled"] = "PasskeyAuthenticationCanceled";
PasskeyErrorCode["PasskeyOperationAborted"] = "PasskeyOperationAborted";
})(PasskeyErrorCode || (PasskeyErrorCode = {}));
const notSupportedRecoverySuggestion = 'Passkeys may not be supported on this device. Ensure your application is running in a secure context (HTTPS) and Web Authentication API is supported.';
const abortOrCancelRecoverySuggestion = 'User may have canceled the ceremony or another interruption has occurred. Check underlying error for details.';
const misconfigurationRecoverySuggestion = 'Ensure your user pool is configured to support the WEB_AUTHN as an authentication factor.';
const passkeyErrorMap = {
[PasskeyErrorCode.PasskeyNotSupported]: {
message: 'Passkeys may not be supported on this device.',
recoverySuggestion: notSupportedRecoverySuggestion,
},
[PasskeyErrorCode.InvalidPasskeyRegistrationOptions]: {
message: 'Invalid passkey registration options.',
recoverySuggestion: misconfigurationRecoverySuggestion,
},
[PasskeyErrorCode.InvalidPasskeyAuthenticationOptions]: {
message: 'Invalid passkey authentication options.',
recoverySuggestion: misconfigurationRecoverySuggestion,
},
[PasskeyErrorCode.PasskeyRegistrationFailed]: {
message: 'Device failed to create passkey.',
recoverySuggestion: notSupportedRecoverySuggestion,
},
[PasskeyErrorCode.PasskeyRetrievalFailed]: {
message: 'Device failed to retrieve passkey.',
recoverySuggestion: 'Passkeys may not be available on this device. Try an alternative authentication factor like PASSWORD, EMAIL_OTP, or SMS_OTP.',
},
[PasskeyErrorCode.PasskeyAlreadyExists]: {
message: 'Passkey already exists in authenticator.',
recoverySuggestion: 'Proceed with existing passkey or try again after deleting the credential.',
},
[PasskeyErrorCode.PasskeyRegistrationCanceled]: {
message: 'Passkey registration ceremony has been canceled.',
recoverySuggestion: abortOrCancelRecoverySuggestion,
},
[PasskeyErrorCode.PasskeyAuthenticationCanceled]: {
message: 'Passkey authentication ceremony has been canceled.',
recoverySuggestion: abortOrCancelRecoverySuggestion,
},
[PasskeyErrorCode.PasskeyOperationAborted]: {
message: 'Passkey operation has been aborted.',
recoverySuggestion: abortOrCancelRecoverySuggestion,
},
[PasskeyErrorCode.RelyingPartyMismatch]: {
message: 'Relying party does not match current domain.',
recoverySuggestion: 'Ensure relying party identifier matches current domain.',
},
};
const assertPasskeyError = createAssertionFunction(passkeyErrorMap, PasskeyError);
/**
* Handle Passkey Authentication Errors
* https://w3c.github.io/webauthn/#sctn-get-request-exceptions
*
* @param err unknown
* @returns PasskeyError
*/
const handlePasskeyAuthenticationError = (err) => {
if (err instanceof PasskeyError) {
return err;
}
if (err instanceof Error) {
if (err.name === 'NotAllowedError') {
const { message, recoverySuggestion } = passkeyErrorMap[PasskeyErrorCode.PasskeyAuthenticationCanceled];
return new PasskeyError({
name: PasskeyErrorCode.PasskeyAuthenticationCanceled,
message,
recoverySuggestion,
underlyingError: err,
});
}
}
return handlePasskeyError(err);
};
/**
* Handle Passkey Registration Errors
* https://w3c.github.io/webauthn/#sctn-create-request-exceptions
*
* @param err unknown
* @returns PasskeyError
*/
const handlePasskeyRegistrationError = (err) => {
if (err instanceof PasskeyError) {
return err;
}
if (err instanceof Error) {
// Duplicate Passkey
if (err.name === 'InvalidStateError') {
const { message, recoverySuggestion } = passkeyErrorMap[PasskeyErrorCode.PasskeyAlreadyExists];
return new PasskeyError({
name: PasskeyErrorCode.PasskeyAlreadyExists,
message,
recoverySuggestion,
underlyingError: err,
});
}
// User Cancels Ceremony / Generic Catch All
if (err.name === 'NotAllowedError') {
const { message, recoverySuggestion } = passkeyErrorMap[PasskeyErrorCode.PasskeyRegistrationCanceled];
return new PasskeyError({
name: PasskeyErrorCode.PasskeyRegistrationCanceled,
message,
recoverySuggestion,
underlyingError: err,
});
}
}
return handlePasskeyError(err);
};
/**
* Handles Overlapping Passkey Errors Between Registration & Authentication
* https://w3c.github.io/webauthn/#sctn-create-request-exceptions
* https://w3c.github.io/webauthn/#sctn-get-request-exceptions
*
* @param err unknown
* @returns PasskeyError
*/
const handlePasskeyError = (err) => {
if (err instanceof Error) {
// Passkey Operation Aborted
if (err.name === 'AbortError') {
const { message, recoverySuggestion } = passkeyErrorMap[PasskeyErrorCode.PasskeyOperationAborted];
return new PasskeyError({
name: PasskeyErrorCode.PasskeyOperationAborted,
message,
recoverySuggestion,
underlyingError: err,
});
}
// Relying Party / Domain Mismatch
if (err.name === 'SecurityError') {
const { message, recoverySuggestion } = passkeyErrorMap[PasskeyErrorCode.RelyingPartyMismatch];
return new PasskeyError({
name: PasskeyErrorCode.RelyingPartyMismatch,
message,
recoverySuggestion,
underlyingError: err,
});
}
}
return new PasskeyError({
name: AmplifyErrorCode.Unknown,
message: 'An unknown error has occurred.',
underlyingError: err,
});
};
export { PasskeyError, PasskeyErrorCode, assertPasskeyError, handlePasskeyAuthenticationError, handlePasskeyRegistrationError };
//# sourceMappingURL=errors.mjs.map