@vardario/cognito-client 5.1.0 → 5.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/browser.js CHANGED
@@ -603,8 +603,47 @@ function uint8ArrayToHexString(bytes) {
603
603
  return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, "0"), "");
604
604
  }
605
605
  function uint8ArrayToBase64String(bytes) {
606
+ if (bytes instanceof ArrayBuffer) {
607
+ const byteArray = new Uint8Array(bytes);
608
+ return btoa(String.fromCharCode(...byteArray));
609
+ }
606
610
  return btoa(String.fromCharCode(...bytes));
607
611
  }
612
+ function uint8ArrayToBase64UrlString(bytes) {
613
+ if (bytes === void 0) {
614
+ return void 0;
615
+ }
616
+ const base64String = uint8ArrayToBase64String(bytes);
617
+ return base64String.replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
618
+ }
619
+ function base64UrlToUint8Array(base64) {
620
+ const binary = atob(base64.replace(/-/g, "+").replace(/_/g, "/"));
621
+ const len = binary.length;
622
+ const bytes = new Uint8Array(len);
623
+ for (let i = 0; i < len; i++) {
624
+ bytes[i] = binary.charCodeAt(i);
625
+ }
626
+ return bytes;
627
+ }
628
+ function publicKeyCredentialToJSON(cred) {
629
+ return removeUndefined({
630
+ authenticatorAttachment: cred.authenticatorAttachment,
631
+ clientExtensionResults: cred.getClientExtensionResults(),
632
+ id: cred.id,
633
+ rawId: uint8ArrayToBase64UrlString(cred.rawId),
634
+ response: {
635
+ attestationObject: uint8ArrayToBase64UrlString(cred.response.attestationObject),
636
+ authenticatorData: cred.response.authenticatorData ? uint8ArrayToBase64UrlString(cred.response.authenticatorData) : void 0,
637
+ clientDataJSON: uint8ArrayToBase64UrlString(cred.response.clientDataJSON),
638
+ publicKey: cred.response.getPublicKey ? uint8ArrayToBase64UrlString(cred.response.getPublicKey()) : void 0,
639
+ publicKeyAlgorithm: cred.response.getPublicKeyAlgorithm ? cred.response.getPublicKeyAlgorithm() : void 0,
640
+ transports: cred.response.getTransports ? cred.response.getTransports() : void 0,
641
+ signature: cred.response.signature ? uint8ArrayToBase64UrlString(cred.response.signature) : void 0,
642
+ userHandle: cred.response.userHandle ? uint8ArrayToBase64UrlString(cred.response.userHandle) : void 0
643
+ },
644
+ type: cred.type
645
+ });
646
+ }
608
647
  var N = BigInt(
609
648
  "0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF0598DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3BE39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF6955817183995497CEA956AE515D2261898FA051015728E5A8AAAC42DAD33170D04507A33A85521ABDF1CBA64ECFB850458DBEF0A8AEA71575D060C7DB3970F85A6E1E4C7ABF5AE8CDB0933D71E8C94E04A25619DCEE3D2261AD2EE6BF12FFA06D98A0864D87602733EC86A64521F2B18177B200CBBE117577A615D6C770988C0BAD946E208E24FA074E5AB3143DB5BFCE0FD108E4B82D120A93AD2CAFFFFFFFFFFFFFFFF"
610
649
  );
@@ -720,6 +759,24 @@ async function hmac(algorithm, key, data) {
720
759
  const signature = await crypto.subtle.sign("HMAC", cryptoKey, data);
721
760
  return new Uint8Array(signature);
722
761
  }
762
+ function removeUndefined(obj) {
763
+ if (Array.isArray(obj)) {
764
+ return obj.map((item) => removeUndefined(item)).filter((item) => item !== void 0);
765
+ }
766
+ if (obj !== null && typeof obj === "object") {
767
+ return Object.entries(obj).reduce(
768
+ (acc, [key, value]) => {
769
+ const cleaned = removeUndefined(value);
770
+ if (cleaned !== void 0) {
771
+ acc[key] = cleaned;
772
+ }
773
+ return acc;
774
+ },
775
+ {}
776
+ );
777
+ }
778
+ return obj !== void 0 ? obj : void 0;
779
+ }
723
780
 
724
781
  // src/cognito-client.ts
725
782
  var ServiceTarget = /* @__PURE__ */ ((ServiceTarget2) => {
@@ -740,6 +797,10 @@ var ServiceTarget = /* @__PURE__ */ ((ServiceTarget2) => {
740
797
  ServiceTarget2["VerifySoftwareToken"] = "VerifySoftwareToken";
741
798
  ServiceTarget2["ListDevices"] = "ListDevices";
742
799
  ServiceTarget2["SetUserMFAPreference"] = "SetUserMFAPreference";
800
+ ServiceTarget2["StartWebAuthnRegistration"] = "StartWebAuthnRegistration";
801
+ ServiceTarget2["CompleteWebAuthnRegistration"] = "CompleteWebAuthnRegistration";
802
+ ServiceTarget2["DeleteWebAuthnCredential"] = "DeleteWebAuthnCredential";
803
+ ServiceTarget2["ListWebAuthnCredentials"] = "ListWebAuthnCredentials";
743
804
  return ServiceTarget2;
744
805
  })(ServiceTarget || {});
745
806
  var IdentityProvider = /* @__PURE__ */ ((IdentityProvider2) => {
@@ -821,6 +882,11 @@ async function cognitoRequest(body, serviceTarget, cognitoEndpoint) {
821
882
  }
822
883
  }
823
884
  var CognitoClient = class {
885
+ cognitoEndpoint;
886
+ cognitoPoolName;
887
+ userPoolClientId;
888
+ oAuth;
889
+ clientSecret;
824
890
  constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth, clientSecret }) {
825
891
  const [cognitoPoolRegion, cognitoPoolName] = userPoolId.split("_");
826
892
  this.cognitoEndpoint = (endpoint || `https://cognito-idp.${cognitoPoolRegion}.amazonaws.com`).replace(/\/$/, "");
@@ -837,6 +903,20 @@ var CognitoClient = class {
837
903
  accessToken
838
904
  };
839
905
  }
906
+ async initiateAuth(request) {
907
+ const cognitoResponse = await cognitoRequest(
908
+ {
909
+ ...request,
910
+ ClientId: this.userPoolClientId
911
+ },
912
+ "InitiateAuth" /* InitiateAuth */,
913
+ this.cognitoEndpoint
914
+ );
915
+ if (cognitoResponse.AuthenticationResult) {
916
+ cognitoResponse.AuthenticationResult = adaptExpiresIn(cognitoResponse.AuthenticationResult);
917
+ }
918
+ return cognitoResponse;
919
+ }
840
920
  /**
841
921
  *
842
922
  * Performs user authentication with username and password through ALLOW_USER_SRP_AUTH .
@@ -850,20 +930,15 @@ var CognitoClient = class {
850
930
  async authenticateUserSrp(username, password) {
851
931
  const smallA = await generateSmallA();
852
932
  const A = generateA(smallA);
853
- const initUserSrpAuthResponse = await cognitoRequest(
854
- {
855
- AuthFlow: "USER_SRP_AUTH",
856
- ClientId: this.userPoolClientId,
857
- AuthParameters: {
858
- USERNAME: username,
859
- SRP_A: A.toString(16),
860
- SECRET_HASH: this.clientSecret && await calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
861
- },
862
- ClientMetadata: {}
933
+ const initUserSrpAuthResponse = await this.initiateAuth({
934
+ AuthFlow: "USER_SRP_AUTH",
935
+ AuthParameters: {
936
+ USERNAME: username,
937
+ SRP_A: A.toString(16),
938
+ SECRET_HASH: this.clientSecret && await calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
863
939
  },
864
- "InitiateAuth" /* InitiateAuth */,
865
- this.cognitoEndpoint
866
- );
940
+ ClientMetadata: {}
941
+ });
867
942
  if (initUserSrpAuthResponse.ChallengeName !== "PASSWORD_VERIFIER") {
868
943
  return initUserSrpAuthResponse;
869
944
  }
@@ -919,7 +994,6 @@ var CognitoClient = class {
919
994
  async authenticateUser(username, password) {
920
995
  const initiateAuthPayload = {
921
996
  AuthFlow: "USER_PASSWORD_AUTH",
922
- ClientId: this.userPoolClientId,
923
997
  AuthParameters: {
924
998
  USERNAME: username,
925
999
  PASSWORD: password,
@@ -927,19 +1001,78 @@ var CognitoClient = class {
927
1001
  },
928
1002
  ClientMetadata: {}
929
1003
  };
930
- const initUserPasswordAuthResponse = await cognitoRequest(
931
- initiateAuthPayload,
932
- "InitiateAuth" /* InitiateAuth */,
933
- this.cognitoEndpoint
934
- );
1004
+ const initUserPasswordAuthResponse = await this.initiateAuth(initiateAuthPayload);
935
1005
  if (!initUserPasswordAuthResponse.AuthenticationResult) {
936
1006
  return initUserPasswordAuthResponse;
937
1007
  }
938
- initUserPasswordAuthResponse.AuthenticationResult = adaptExpiresIn(
939
- initUserPasswordAuthResponse.AuthenticationResult
940
- );
941
1008
  return initUserPasswordAuthResponse;
942
1009
  }
1010
+ /**
1011
+ * Initiates the authentication process for a user using a preferred challenge, such as WEB_AUTHN.
1012
+ */
1013
+ async authenticateWebAuthn(username) {
1014
+ const webAuthnPayload = {
1015
+ AuthFlow: "USER_AUTH",
1016
+ AuthParameters: {
1017
+ USERNAME: username,
1018
+ PREFERRED_CHALLENGE: "WEB_AUTHN"
1019
+ }
1020
+ };
1021
+ const authResponse = await this.initiateAuth(webAuthnPayload);
1022
+ if (authResponse.ChallengeName !== "WEB_AUTHN") {
1023
+ throw new InitAuthError(
1024
+ "Authentication failed, expected WEB_AUTHN challenge but received: " + authResponse.ChallengeName,
1025
+ "InternalErrorException" /* InternalErrorException */
1026
+ );
1027
+ }
1028
+ const credentialRequestOptions = JSON.parse(authResponse.ChallengeParameters.CREDENTIAL_REQUEST_OPTIONS);
1029
+ credentialRequestOptions.challenge = base64UrlToUint8Array(credentialRequestOptions.challenge);
1030
+ credentialRequestOptions.allowCredentials = (credentialRequestOptions.allowCredentials || []).map(
1031
+ (allowCred) => ({
1032
+ ...allowCred,
1033
+ id: base64UrlToUint8Array(allowCred.id)
1034
+ })
1035
+ );
1036
+ const credentials = await navigator.credentials.get({
1037
+ publicKey: credentialRequestOptions
1038
+ });
1039
+ const challengeResponse = await this.respondToAuthChallenge({
1040
+ ChallengeName: "WEB_AUTHN",
1041
+ ChallengeResponses: {
1042
+ USERNAME: username,
1043
+ CREDENTIAL: JSON.stringify(publicKeyCredentialToJSON(credentials)),
1044
+ SECRET_HASH: this.clientSecret && await calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
1045
+ },
1046
+ Session: authResponse.Session
1047
+ });
1048
+ if (challengeResponse.AuthenticationResult) {
1049
+ challengeResponse.AuthenticationResult = adaptExpiresIn(challengeResponse.AuthenticationResult);
1050
+ }
1051
+ return challengeResponse;
1052
+ }
1053
+ /**
1054
+ * Registers a new WebAuthn device for the current user.
1055
+ * This method initiates the WebAuthn registration process by requesting the necessary options from Cognito,
1056
+ * then creates a new public key credential using the WebAuthn API, and finally
1057
+ * completes the registration by sending the credential back to Cognito.
1058
+ *
1059
+ * @param accessToken Access token of the current user.
1060
+ */
1061
+ async registerWebAuthnDevice(accessToken) {
1062
+ const { CredentialCreationOptions } = await this.startWebAuthnRegistration({
1063
+ AccessToken: accessToken
1064
+ });
1065
+ const credentials = await navigator.credentials.create({
1066
+ publicKey: CredentialCreationOptions
1067
+ });
1068
+ if (!(credentials instanceof PublicKeyCredential)) {
1069
+ throw new Error("Invalid credentials returned from WebAuthn API");
1070
+ }
1071
+ await this.completeWebAuthnRegistration({
1072
+ AccessToken: accessToken,
1073
+ Credential: credentials
1074
+ });
1075
+ }
943
1076
  /**
944
1077
  * Returns a new session based on the given refresh token.
945
1078
  *
@@ -951,18 +1084,13 @@ var CognitoClient = class {
951
1084
  async refreshSession(refreshToken, username) {
952
1085
  const refreshTokenPayload = {
953
1086
  AuthFlow: "REFRESH_TOKEN_AUTH",
954
- ClientId: this.userPoolClientId,
955
1087
  AuthParameters: {
956
1088
  REFRESH_TOKEN: refreshToken,
957
1089
  SECRET_HASH: this.clientSecret && username && await calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
958
1090
  },
959
1091
  ClientMetadata: {}
960
1092
  };
961
- const { AuthenticationResult } = await cognitoRequest(
962
- refreshTokenPayload,
963
- "InitiateAuth" /* InitiateAuth */,
964
- this.cognitoEndpoint
965
- );
1093
+ const { AuthenticationResult } = await this.initiateAuth(refreshTokenPayload);
966
1094
  if (!AuthenticationResult) {
967
1095
  throw new InitAuthError(
968
1096
  "Authentication failed, no authentication result returned",
@@ -972,7 +1100,7 @@ var CognitoClient = class {
972
1100
  if (!AuthenticationResult.RefreshToken) {
973
1101
  AuthenticationResult.RefreshToken = refreshToken;
974
1102
  }
975
- return adaptExpiresIn(AuthenticationResult);
1103
+ return AuthenticationResult;
976
1104
  }
977
1105
  /**
978
1106
  *
@@ -1027,15 +1155,40 @@ var CognitoClient = class {
1027
1155
  };
1028
1156
  await cognitoRequest(changePasswordPayload, "ChangePassword" /* ChangePassword */, this.cognitoEndpoint);
1029
1157
  }
1158
+ /**
1159
+ * Gets the user information.
1160
+ * @param accessToken Access token of the current user.
1161
+ * @returns User information.
1162
+ */
1030
1163
  async getUser(accessToken) {
1031
1164
  const getUserPayload = {
1032
1165
  AccessToken: accessToken
1033
1166
  };
1034
1167
  return cognitoRequest(getUserPayload, "GetUser" /* GetUser */, this.cognitoEndpoint);
1035
1168
  }
1169
+ /**
1170
+ * Associates a software token with the user.
1171
+ * @param params Request to associate a software token with the user.
1172
+ * @param params.AccessToken Access token of the current user.
1173
+ * @param params.Session Optional session identifier for the authentication process.
1174
+ * @param params.ClientMetadata Optional metadata to pass to the service.
1175
+ * @param params.UserContextData Optional user context data.
1176
+ * @param params.AnalyticsMetadata Optional analytics metadata.
1177
+ * @param params.FriendlyDeviceName Optional friendly name for the device.
1178
+ * @returns
1179
+ */
1036
1180
  async associateSoftwareToken(params) {
1037
1181
  return cognitoRequest(params, "AssociateSoftwareToken" /* AssociateSoftwareToken */, this.cognitoEndpoint);
1038
1182
  }
1183
+ /**
1184
+ * Verifies a software token.
1185
+ * @param params Request to verify a software token.
1186
+ * @param params.AccessToken Access token of the current user.
1187
+ * @param params.FriendlyDeviceName Optional friendly name for the device.
1188
+ * @param params.Session Optional session identifier for the authentication process.
1189
+ * @param params.UserCode The user code to verify.
1190
+ * @returns
1191
+ */
1039
1192
  async verifySoftwareToken(params) {
1040
1193
  return cognitoRequest(params, "VerifySoftwareToken" /* VerifySoftwareToken */, this.cognitoEndpoint);
1041
1194
  }
@@ -1178,6 +1331,59 @@ var CognitoClient = class {
1178
1331
  };
1179
1332
  await cognitoRequest(resendConfirmationCodeRequest, "ResendConfirmationCode" /* ResendConfirmationCode */, this.cognitoEndpoint);
1180
1333
  }
1334
+ async startWebAuthnRegistration(request) {
1335
+ const response = await cognitoRequest(request, "StartWebAuthnRegistration" /* StartWebAuthnRegistration */, this.cognitoEndpoint);
1336
+ response.CredentialCreationOptions.challenge = base64UrlToUint8Array(
1337
+ response.CredentialCreationOptions.challenge
1338
+ );
1339
+ response.CredentialCreationOptions.user.id = base64UrlToUint8Array(
1340
+ response.CredentialCreationOptions.user.id
1341
+ );
1342
+ response.CredentialCreationOptions.excludeCredentials = (response.CredentialCreationOptions.excludeCredentials || []).map((excludeCred) => ({
1343
+ ...excludeCred,
1344
+ id: base64UrlToUint8Array(excludeCred.id)
1345
+ }));
1346
+ return response;
1347
+ }
1348
+ /**
1349
+ * Completes registration of a passkey authenticator for the currently signed-in user.
1350
+ * @param request Request to complete WebAuthn registration.
1351
+ * @param request.AccessToken Access token of the current user.
1352
+ * @param request.Credential The credential object returned by the WebAuthn API.
1353
+ */
1354
+ async completeWebAuthnRegistration(request) {
1355
+ await cognitoRequest(
1356
+ {
1357
+ AccessToken: request.AccessToken,
1358
+ Credential: publicKeyCredentialToJSON(request.Credential)
1359
+ },
1360
+ "CompleteWebAuthnRegistration" /* CompleteWebAuthnRegistration */,
1361
+ this.cognitoEndpoint
1362
+ );
1363
+ }
1364
+ /**
1365
+ * Deletes a registered passkey, or WebAuthn, authenticator for the currently signed-in user.
1366
+ *
1367
+ * @param request Request to delete a WebAuthn credential.
1368
+ * @param request.AccessToken Access token of the current user.
1369
+ * @param request.CredentialId The ID of the credential to delete.
1370
+ */
1371
+ async deleteWebAuthnCredential(request) {
1372
+ await cognitoRequest(request, "DeleteWebAuthnCredential" /* DeleteWebAuthnCredential */, this.cognitoEndpoint);
1373
+ }
1374
+ /**
1375
+ * Lists all registered WebAuthn credentials for the currently signed-in user.
1376
+ *
1377
+ * @param request Request to list WebAuthn credentials.
1378
+ * @param request.AccessToken Access token of the current user.
1379
+ * @param request.MaxResults Maximum number of credentials to return.
1380
+ * @param request.NextToken Pagination token to continue listing credentials.
1381
+ * @returns
1382
+ */
1383
+ async listWebAuthnCredentials(request) {
1384
+ const response = await cognitoRequest(request, "ListWebAuthnCredentials" /* ListWebAuthnCredentials */, this.cognitoEndpoint);
1385
+ return response;
1386
+ }
1181
1387
  /**
1182
1388
  * Returns a link to Cognito`s Hosted UI for OAuth2 authentication.
1183
1389
  * This method works in conjunction with @see handleCodeFlow .
@@ -1319,5 +1525,30 @@ export {
1319
1525
  VerifyUserAttributeError,
1320
1526
  VerifyUserAttributeException,
1321
1527
  adaptExpiresIn,
1322
- cognitoRequest
1528
+ base64UrlToUint8Array,
1529
+ calculateHKDF,
1530
+ calculateS,
1531
+ calculateSecretHash,
1532
+ calculateSignature,
1533
+ calculateU,
1534
+ cognitoRequest,
1535
+ decodeJwt,
1536
+ digest,
1537
+ formatTimestamp,
1538
+ generateA,
1539
+ generateSmallA,
1540
+ getPasswordAuthenticationKey,
1541
+ hashBuffer,
1542
+ hashHexString,
1543
+ hmac,
1544
+ padHex,
1545
+ publicKeyCredentialToJSON,
1546
+ randomBytes,
1547
+ removeUndefined,
1548
+ uint8ArrayFromBase64String,
1549
+ uint8ArrayFromHexString,
1550
+ uint8ArrayFromString,
1551
+ uint8ArrayToBase64String,
1552
+ uint8ArrayToBase64UrlString,
1553
+ uint8ArrayToHexString
1323
1554
  };
@@ -9,7 +9,7 @@ export interface CognitoBaseRequest {
9
9
  IpAddress?: string;
10
10
  };
11
11
  }
12
- export interface InitiateAuthUserSrpAuthRequest extends CognitoBaseRequest {
12
+ export interface _InitiateAuthUserSrpAuthRequest extends CognitoBaseRequest {
13
13
  AuthFlow: 'USER_SRP_AUTH';
14
14
  AuthParameters: {
15
15
  USERNAME: string;
@@ -17,7 +17,7 @@ export interface InitiateAuthUserSrpAuthRequest extends CognitoBaseRequest {
17
17
  SECRET_HASH?: string;
18
18
  };
19
19
  }
20
- export interface InitiateAuthUserPasswordAuthRequest extends CognitoBaseRequest {
20
+ export interface _InitiateAuthUserPasswordAuthRequest extends CognitoBaseRequest {
21
21
  AuthFlow: 'USER_PASSWORD_AUTH';
22
22
  AuthParameters: {
23
23
  USERNAME: string;
@@ -25,21 +25,31 @@ export interface InitiateAuthUserPasswordAuthRequest extends CognitoBaseRequest
25
25
  SECRET_HASH?: string;
26
26
  };
27
27
  }
28
- export interface InitiateAuthRefreshTokenAuthRequest extends CognitoBaseRequest {
28
+ export interface _InitiateAuthRefreshTokenAuthRequest extends CognitoBaseRequest {
29
29
  AuthFlow: 'REFRESH_TOKEN_AUTH';
30
30
  AuthParameters: {
31
31
  REFRESH_TOKEN: string;
32
32
  SECRET_HASH?: string;
33
+ USERNAME?: never;
33
34
  };
34
35
  }
35
- export interface InitiateAuthCustomAuthRequest extends CognitoBaseRequest {
36
+ export interface _InitiateAuthCustomAuthRequest extends CognitoBaseRequest {
36
37
  AuthFlow: 'CUSTOM_AUTH';
37
38
  AuthParameters: {
38
39
  USERNAME: string;
39
40
  SECRET_HASH?: string;
40
41
  };
41
42
  }
42
- export type InitiateAuthRequest = InitiateAuthUserSrpAuthRequest | InitiateAuthRefreshTokenAuthRequest | InitiateAuthCustomAuthRequest | InitiateAuthUserPasswordAuthRequest;
43
+ export interface _InitiateAuthUserAuthRequest extends CognitoBaseRequest {
44
+ AuthFlow: 'USER_AUTH';
45
+ AuthParameters: {
46
+ USERNAME: string;
47
+ PREFERRED_CHALLENGE?: AuthChallenge;
48
+ SECRET_HASH?: string;
49
+ };
50
+ }
51
+ type _InitiateAuthRequest = _InitiateAuthUserSrpAuthRequest | _InitiateAuthUserPasswordAuthRequest | _InitiateAuthRefreshTokenAuthRequest | _InitiateAuthCustomAuthRequest | _InitiateAuthUserAuthRequest;
52
+ export type InitiateAuthRequest = Omit<_InitiateAuthUserSrpAuthRequest, 'ClientId'> | Omit<_InitiateAuthUserPasswordAuthRequest, 'ClientId'> | Omit<_InitiateAuthRefreshTokenAuthRequest, 'ClientId'> | Omit<_InitiateAuthCustomAuthRequest, 'ClientId'> | Omit<_InitiateAuthUserAuthRequest, 'ClientId'>;
43
53
  export interface RespondToAuthChallengeBaseRequest extends CognitoBaseRequest {
44
54
  Session?: string;
45
55
  }
@@ -112,6 +122,7 @@ export interface _RespondToAuthChallengeMfaSetupRequest extends RespondToAuthCha
112
122
  SOFTWARE_TOKEN_MFA_CODE?: string;
113
123
  SECRET_HASH?: string;
114
124
  };
125
+ Session?: never;
115
126
  }
116
127
  export interface _RespondToAuthChallengeSelectMfaTypeRequest extends RespondToAuthChallengeBaseRequest {
117
128
  ChallengeName: 'SELECT_MFA_TYPE';
@@ -121,8 +132,16 @@ export interface _RespondToAuthChallengeSelectMfaTypeRequest extends RespondToAu
121
132
  SECRET_HASH?: string;
122
133
  };
123
134
  }
124
- type _RespondToAuthChallengeRequest = _RespondToAuthChallengePasswordVerifierRequest | _RespondToAuthChallengeSmsMfaRequest | _RespondToAuthChallengeCustomChallengeNameRequest | _RespondToAuthChallengeNewPasswordRequiredRequest | _RespondToAuthChallengeSoftwareTokenMfaRequest | _RespondToAuthChallengeDeviceSrpAuthRequest | _RespondToAuthChallengeDevicePasswordVerifierRequest | _RespondToAuthChallengeMfaSetupRequest | _RespondToAuthChallengeSelectMfaTypeRequest;
125
- export type RespondToAuthChallengeRequest = Omit<_RespondToAuthChallengePasswordVerifierRequest, 'ClientId'> | Omit<_RespondToAuthChallengeSmsMfaRequest, 'ClientId'> | Omit<_RespondToAuthChallengeCustomChallengeNameRequest, 'ClientId'> | Omit<_RespondToAuthChallengeNewPasswordRequiredRequest, 'ClientId'> | Omit<_RespondToAuthChallengeSoftwareTokenMfaRequest, 'ClientId'> | Omit<_RespondToAuthChallengeDeviceSrpAuthRequest, 'ClientId'> | Omit<_RespondToAuthChallengeDevicePasswordVerifierRequest, 'ClientId'> | Omit<_RespondToAuthChallengeMfaSetupRequest, 'ClientId'> | Omit<_RespondToAuthChallengeSelectMfaTypeRequest, 'ClientId'>;
135
+ export interface _RespondToAuthChallengeWebAuthnRequest extends RespondToAuthChallengeBaseRequest {
136
+ ChallengeName: 'WEB_AUTHN';
137
+ ChallengeResponses: {
138
+ USERNAME: string;
139
+ CREDENTIAL: any;
140
+ SECRET_HASH?: string;
141
+ };
142
+ }
143
+ type _RespondToAuthChallengeRequest = _RespondToAuthChallengePasswordVerifierRequest | _RespondToAuthChallengeSmsMfaRequest | _RespondToAuthChallengeCustomChallengeNameRequest | _RespondToAuthChallengeNewPasswordRequiredRequest | _RespondToAuthChallengeSoftwareTokenMfaRequest | _RespondToAuthChallengeDeviceSrpAuthRequest | _RespondToAuthChallengeDevicePasswordVerifierRequest | _RespondToAuthChallengeMfaSetupRequest | _RespondToAuthChallengeSelectMfaTypeRequest | _RespondToAuthChallengeWebAuthnRequest;
144
+ export type RespondToAuthChallengeRequest = Omit<_RespondToAuthChallengePasswordVerifierRequest, 'ClientId'> | Omit<_RespondToAuthChallengeSmsMfaRequest, 'ClientId'> | Omit<_RespondToAuthChallengeCustomChallengeNameRequest, 'ClientId'> | Omit<_RespondToAuthChallengeNewPasswordRequiredRequest, 'ClientId'> | Omit<_RespondToAuthChallengeSoftwareTokenMfaRequest, 'ClientId'> | Omit<_RespondToAuthChallengeDeviceSrpAuthRequest, 'ClientId'> | Omit<_RespondToAuthChallengeDevicePasswordVerifierRequest, 'ClientId'> | Omit<_RespondToAuthChallengeMfaSetupRequest, 'ClientId'> | Omit<_RespondToAuthChallengeSelectMfaTypeRequest, 'ClientId'> | Omit<_RespondToAuthChallengeWebAuthnRequest, 'ClientId'>;
126
145
  export interface UserAttribute {
127
146
  Name: string;
128
147
  Value: string;
@@ -258,7 +277,11 @@ export declare enum ServiceTarget {
258
277
  AssociateSoftwareToken = "AssociateSoftwareToken",
259
278
  VerifySoftwareToken = "VerifySoftwareToken",
260
279
  ListDevices = "ListDevices",
261
- SetUserMFAPreference = "SetUserMFAPreference"
280
+ SetUserMFAPreference = "SetUserMFAPreference",
281
+ StartWebAuthnRegistration = "StartWebAuthnRegistration",
282
+ CompleteWebAuthnRegistration = "CompleteWebAuthnRegistration",
283
+ DeleteWebAuthnCredential = "DeleteWebAuthnCredential",
284
+ ListWebAuthnCredentials = "ListWebAuthnCredentials"
262
285
  }
263
286
  export interface AssociateSoftwareTokenRequest {
264
287
  AccessToken?: string;
@@ -321,12 +344,16 @@ export interface NewDeviceMetadata {
321
344
  DeviceKey?: string;
322
345
  DeviceGroupKey?: string;
323
346
  }
324
- export interface InitiateAuthAuthenticationResponse {
347
+ export type AuthChallenge = InitiateAuthChallengeResponse['ChallengeName'];
348
+ export interface InitiateAuthBaseResponse {
349
+ AvailableChallenges: [];
350
+ Session: string;
351
+ }
352
+ export interface InitiateAuthAuthenticationResponse extends InitiateAuthBaseResponse {
325
353
  AuthenticationResult: AuthenticationResult;
326
354
  ChallengeName?: never;
327
- session?: never;
328
355
  }
329
- export interface InitiateAuthPasswordVerifierChallengeResponse {
356
+ export interface InitiateAuthPasswordVerifierChallengeResponse extends InitiateAuthBaseResponse {
330
357
  AuthenticationResult?: never;
331
358
  ChallengeName: 'PASSWORD_VERIFIER';
332
359
  ChallengeParameters: {
@@ -336,20 +363,48 @@ export interface InitiateAuthPasswordVerifierChallengeResponse {
336
363
  USERNAME: string;
337
364
  USER_ID_FOR_SRP: string;
338
365
  };
339
- session?: never;
340
366
  }
341
- export interface InitiateAuthSoftwareTokenMfaChallengeResponse {
367
+ export interface InitiateAuthSoftwareTokenMfaChallengeResponse extends InitiateAuthBaseResponse {
342
368
  AuthenticationResult?: never;
343
369
  ChallengeName: 'SOFTWARE_TOKEN_MFA';
370
+ }
371
+ export interface InitiateAuthWebAuthResponse extends InitiateAuthBaseResponse {
372
+ AuthenticationResult?: never;
373
+ ChallengeName: 'WEB_AUTHN';
344
374
  Session: string;
375
+ ChallengeParameters: {
376
+ CREDENTIAL_REQUEST_OPTIONS: string;
377
+ };
345
378
  }
346
- export interface InitiateEmailOtpChallengeResponse {
379
+ export interface InitiateEmailOtpChallengeResponse extends InitiateAuthBaseResponse {
380
+ AuthenticationResult?: never;
347
381
  ChallengeName: 'EMAIL_OTP';
348
382
  ChallengeParameters: {
349
383
  CODE_DELIVERY_DELIVERY_MEDIUM: string;
350
384
  CODE_DELIVERY_DESTINATION: string;
351
385
  };
352
- session: string;
386
+ Session: string;
387
+ }
388
+ export interface InitAuthSelectChallengeResponse extends InitiateAuthBaseResponse {
389
+ AuthenticationResult?: never;
390
+ ChallengeName: 'SELECT_CHALLENGE';
391
+ ChallengeParameters: never;
392
+ }
393
+ export interface InitAuthPasswordChallengeResponse extends InitiateAuthBaseResponse {
394
+ AuthenticationResult?: never;
395
+ ChallengeName: 'PASSWORD';
396
+ ChallengeParameters: never;
397
+ }
398
+ export interface InitAuthPasswordSRPChallengeResponse extends InitiateAuthBaseResponse {
399
+ AuthenticationResult?: never;
400
+ ChallengeName: 'PASSWORD_SRP';
401
+ ChallengeParameters: never;
402
+ }
403
+ export interface InitAuthMfaSetupChallengeResponse extends InitiateAuthBaseResponse {
404
+ AuthenticationResult?: never;
405
+ ChallengeName: 'MFA_SETUP';
406
+ ChallengeParameters: never;
407
+ MFAS_CAN_SETUP: ('SMS_MFA' | 'SOFTWARE_TOKEN_MFA')[];
353
408
  }
354
409
  export interface MfaOption {
355
410
  DeliveryMedium: 'SMS' | 'EMAIL';
@@ -377,7 +432,38 @@ export interface SetUserMFAPreferenceRequest {
377
432
  PreferredMfa?: boolean;
378
433
  };
379
434
  }
380
- export type InitiateAuthChallengeResponse = InitiateAuthPasswordVerifierChallengeResponse | InitiateAuthSoftwareTokenMfaChallengeResponse;
435
+ export interface StartWebAuthnRegistrationRequest {
436
+ AccessToken: string;
437
+ }
438
+ export interface StartWebAuthnRegistrationResponse {
439
+ CredentialCreationOptions: any;
440
+ }
441
+ export interface CompleteWebAuthnRegistrationRequest {
442
+ AccessToken: string;
443
+ Credential: PublicKeyCredential;
444
+ }
445
+ export interface DeleteWebAuthnCredentialRequest {
446
+ AccessToken: string;
447
+ CredentialId: string;
448
+ }
449
+ export interface ListWebAuthnCredentialsRequest {
450
+ AccessToken: string;
451
+ MaxResults?: number;
452
+ NextToken?: string;
453
+ }
454
+ export interface WebAuthnCredential {
455
+ AuthenticatorTransports: string[];
456
+ CreatedAt: string;
457
+ CredentialId: string;
458
+ FriendlyCredentialName: string;
459
+ RelyingPartyId: string;
460
+ AuthenticatorAttachment?: string;
461
+ }
462
+ export interface ListWebAuthnCredentialsResponse {
463
+ Credentials: WebAuthnCredential[];
464
+ NextToken?: string;
465
+ }
466
+ export type InitiateAuthChallengeResponse = InitiateAuthPasswordVerifierChallengeResponse | InitiateAuthSoftwareTokenMfaChallengeResponse | InitiateAuthWebAuthResponse | InitiateEmailOtpChallengeResponse | InitAuthSelectChallengeResponse | InitAuthPasswordChallengeResponse | InitAuthPasswordSRPChallengeResponse | InitAuthMfaSetupChallengeResponse;
381
467
  export type InitiateAuthResponse = InitiateAuthAuthenticationResponse | InitiateAuthPasswordVerifierChallengeResponse | InitiateAuthChallengeResponse;
382
468
  type CognitoResponseMap = {
383
469
  [ServiceTarget.InitiateAuth]: InitiateAuthResponse;
@@ -400,9 +486,13 @@ type CognitoResponseMap = {
400
486
  [ServiceTarget.VerifySoftwareToken]: VerifySoftwareTokenResponse;
401
487
  [ServiceTarget.ListDevices]: ListDevicesResponse;
402
488
  [ServiceTarget.SetUserMFAPreference]: void;
489
+ [ServiceTarget.StartWebAuthnRegistration]: StartWebAuthnRegistrationResponse;
490
+ [ServiceTarget.CompleteWebAuthnRegistration]: void;
491
+ [ServiceTarget.DeleteWebAuthnCredential]: void;
492
+ [ServiceTarget.ListWebAuthnCredentials]: ListWebAuthnCredentialsResponse;
403
493
  };
404
494
  type CognitoRequestMap = {
405
- [ServiceTarget.InitiateAuth]: InitiateAuthRequest;
495
+ [ServiceTarget.InitiateAuth]: _InitiateAuthRequest;
406
496
  [ServiceTarget.RespondToAuthChallenge]: _RespondToAuthChallengeRequest;
407
497
  [ServiceTarget.SignUp]: SignUpRequest;
408
498
  [ServiceTarget.ConfirmSignUp]: ConfirmSignUpRequest;
@@ -438,6 +528,10 @@ type CognitoRequestMap = {
438
528
  [ServiceTarget.VerifySoftwareToken]: VerifySoftwareTokenRequest;
439
529
  [ServiceTarget.ListDevices]: ListDevicesRequest;
440
530
  [ServiceTarget.SetUserMFAPreference]: SetUserMFAPreferenceRequest;
531
+ [ServiceTarget.StartWebAuthnRegistration]: StartWebAuthnRegistrationRequest;
532
+ [ServiceTarget.CompleteWebAuthnRegistration]: any;
533
+ [ServiceTarget.DeleteWebAuthnCredential]: DeleteWebAuthnCredentialRequest;
534
+ [ServiceTarget.ListWebAuthnCredentials]: ListWebAuthnCredentialsRequest;
441
535
  };
442
536
  export declare function adaptExpiresIn(auth: AuthenticationResult): {
443
537
  ExpiresIn: number;
@@ -458,6 +552,7 @@ export declare class CognitoClient {
458
552
  private readonly clientSecret?;
459
553
  constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth, clientSecret }: CognitoClientProps);
460
554
  static getDecodedTokenFromSession(auth: AuthenticationResult): DecodedTokens;
555
+ initiateAuth(request: InitiateAuthRequest): Promise<InitiateAuthResponse>;
461
556
  /**
462
557
  *
463
558
  * Performs user authentication with username and password through ALLOW_USER_SRP_AUTH .
@@ -479,6 +574,19 @@ export declare class CognitoClient {
479
574
  * @throws {InitAuthError}
480
575
  */
481
576
  authenticateUser(username: string, password: string): Promise<InitiateAuthResponse>;
577
+ /**
578
+ * Initiates the authentication process for a user using a preferred challenge, such as WEB_AUTHN.
579
+ */
580
+ authenticateWebAuthn(username: string): Promise<InitiateAuthResponse>;
581
+ /**
582
+ * Registers a new WebAuthn device for the current user.
583
+ * This method initiates the WebAuthn registration process by requesting the necessary options from Cognito,
584
+ * then creates a new public key credential using the WebAuthn API, and finally
585
+ * completes the registration by sending the credential back to Cognito.
586
+ *
587
+ * @param accessToken Access token of the current user.
588
+ */
589
+ registerWebAuthnDevice(accessToken: string): Promise<void>;
482
590
  /**
483
591
  * Returns a new session based on the given refresh token.
484
592
  *
@@ -516,8 +624,33 @@ export declare class CognitoClient {
516
624
  * @throws {ChangePasswordError}
517
625
  */
518
626
  changePassword(currentPassword: string, newPassword: string, accessToken: string): Promise<void>;
627
+ /**
628
+ * Gets the user information.
629
+ * @param accessToken Access token of the current user.
630
+ * @returns User information.
631
+ */
519
632
  getUser(accessToken: string): Promise<GetUserResponse>;
633
+ /**
634
+ * Associates a software token with the user.
635
+ * @param params Request to associate a software token with the user.
636
+ * @param params.AccessToken Access token of the current user.
637
+ * @param params.Session Optional session identifier for the authentication process.
638
+ * @param params.ClientMetadata Optional metadata to pass to the service.
639
+ * @param params.UserContextData Optional user context data.
640
+ * @param params.AnalyticsMetadata Optional analytics metadata.
641
+ * @param params.FriendlyDeviceName Optional friendly name for the device.
642
+ * @returns
643
+ */
520
644
  associateSoftwareToken(params: AssociateSoftwareTokenRequest): Promise<AssociateSoftwareResponse>;
645
+ /**
646
+ * Verifies a software token.
647
+ * @param params Request to verify a software token.
648
+ * @param params.AccessToken Access token of the current user.
649
+ * @param params.FriendlyDeviceName Optional friendly name for the device.
650
+ * @param params.Session Optional session identifier for the authentication process.
651
+ * @param params.UserCode The user code to verify.
652
+ * @returns
653
+ */
521
654
  verifySoftwareToken(params: VerifySoftwareTokenRequest): Promise<VerifySoftwareTokenResponse>;
522
655
  /**
523
656
  * Responds to an authentication challenge.
@@ -602,6 +735,32 @@ export declare class CognitoClient {
602
735
  * @throws {ResendConfirmationCodeError}
603
736
  */
604
737
  resendConfirmationCode(username: string): Promise<void>;
738
+ startWebAuthnRegistration(request: StartWebAuthnRegistrationRequest): Promise<StartWebAuthnRegistrationResponse>;
739
+ /**
740
+ * Completes registration of a passkey authenticator for the currently signed-in user.
741
+ * @param request Request to complete WebAuthn registration.
742
+ * @param request.AccessToken Access token of the current user.
743
+ * @param request.Credential The credential object returned by the WebAuthn API.
744
+ */
745
+ completeWebAuthnRegistration(request: CompleteWebAuthnRegistrationRequest): Promise<void>;
746
+ /**
747
+ * Deletes a registered passkey, or WebAuthn, authenticator for the currently signed-in user.
748
+ *
749
+ * @param request Request to delete a WebAuthn credential.
750
+ * @param request.AccessToken Access token of the current user.
751
+ * @param request.CredentialId The ID of the credential to delete.
752
+ */
753
+ deleteWebAuthnCredential(request: DeleteWebAuthnCredentialRequest): Promise<void>;
754
+ /**
755
+ * Lists all registered WebAuthn credentials for the currently signed-in user.
756
+ *
757
+ * @param request Request to list WebAuthn credentials.
758
+ * @param request.AccessToken Access token of the current user.
759
+ * @param request.MaxResults Maximum number of credentials to return.
760
+ * @param request.NextToken Pagination token to continue listing credentials.
761
+ * @returns
762
+ */
763
+ listWebAuthnCredentials(request: ListWebAuthnCredentialsRequest): Promise<ListWebAuthnCredentialsResponse>;
605
764
  /**
606
765
  * Returns a link to Cognito`s Hosted UI for OAuth2 authentication.
607
766
  * This method works in conjunction with @see handleCodeFlow .
@@ -1,5 +1,5 @@
1
1
  import { ChangePasswordError, ConfirmForgotPasswordError, ConfirmSignUpError, ForgotPasswordError, GlobalSignOutError, InitAuthError, ResendConfirmationCodeError, RespondToAuthChallengeError, RevokeTokenError, SignUpError, UpdateUserAttributesError, VerifyUserAttributeError, InitiateAuthException, COMMON_EXCEPTIONS, CommonError, VerifySoftwareTokenError, AssociateSoftwareTokenError, SetUserMFAPreferenceError, ListDevicesError, GetUserError } from './error.js';
2
- import { calculateSecretHash, calculateSignature, calculateU, decodeJwt, digest, generateA, generateSmallA, getPasswordAuthenticationKey, randomBytes, uint8ArrayFromString, uint8ArrayToBase64String } from './utils.js';
2
+ import { base64UrlToUint8Array, calculateSecretHash, calculateSignature, calculateU, decodeJwt, digest, generateA, generateSmallA, getPasswordAuthenticationKey, publicKeyCredentialToJSON, randomBytes, uint8ArrayFromString, uint8ArrayToBase64String } from './utils.js';
3
3
  /**
4
4
  * List of used and supported Cognito API calls.
5
5
  * @see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_Operations.html for more details
@@ -23,6 +23,10 @@ export var ServiceTarget;
23
23
  ServiceTarget["VerifySoftwareToken"] = "VerifySoftwareToken";
24
24
  ServiceTarget["ListDevices"] = "ListDevices";
25
25
  ServiceTarget["SetUserMFAPreference"] = "SetUserMFAPreference";
26
+ ServiceTarget["StartWebAuthnRegistration"] = "StartWebAuthnRegistration";
27
+ ServiceTarget["CompleteWebAuthnRegistration"] = "CompleteWebAuthnRegistration";
28
+ ServiceTarget["DeleteWebAuthnCredential"] = "DeleteWebAuthnCredential";
29
+ ServiceTarget["ListWebAuthnCredentials"] = "ListWebAuthnCredentials";
26
30
  })(ServiceTarget || (ServiceTarget = {}));
27
31
  /**
28
32
  * Cognito supported federated identities public providers.
@@ -119,6 +123,11 @@ export async function cognitoRequest(body, serviceTarget, cognitoEndpoint) {
119
123
  * Lightweight AWS Cogito client without any AWS SDK dependencies.
120
124
  */
121
125
  export class CognitoClient {
126
+ cognitoEndpoint;
127
+ cognitoPoolName;
128
+ userPoolClientId;
129
+ oAuth;
130
+ clientSecret;
122
131
  constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth, clientSecret }) {
123
132
  const [cognitoPoolRegion, cognitoPoolName] = userPoolId.split('_');
124
133
  this.cognitoEndpoint = (endpoint || `https://cognito-idp.${cognitoPoolRegion}.amazonaws.com`).replace(/\/$/, '');
@@ -135,6 +144,16 @@ export class CognitoClient {
135
144
  accessToken
136
145
  };
137
146
  }
147
+ async initiateAuth(request) {
148
+ const cognitoResponse = await cognitoRequest({
149
+ ...request,
150
+ ClientId: this.userPoolClientId
151
+ }, ServiceTarget.InitiateAuth, this.cognitoEndpoint);
152
+ if (cognitoResponse.AuthenticationResult) {
153
+ cognitoResponse.AuthenticationResult = adaptExpiresIn(cognitoResponse.AuthenticationResult);
154
+ }
155
+ return cognitoResponse;
156
+ }
138
157
  /**
139
158
  *
140
159
  * Performs user authentication with username and password through ALLOW_USER_SRP_AUTH .
@@ -148,16 +167,15 @@ export class CognitoClient {
148
167
  async authenticateUserSrp(username, password) {
149
168
  const smallA = await generateSmallA();
150
169
  const A = generateA(smallA);
151
- const initUserSrpAuthResponse = await cognitoRequest({
170
+ const initUserSrpAuthResponse = await this.initiateAuth({
152
171
  AuthFlow: 'USER_SRP_AUTH',
153
- ClientId: this.userPoolClientId,
154
172
  AuthParameters: {
155
173
  USERNAME: username,
156
174
  SRP_A: A.toString(16),
157
175
  SECRET_HASH: this.clientSecret && (await calculateSecretHash(this.clientSecret, this.userPoolClientId, username))
158
176
  },
159
177
  ClientMetadata: {}
160
- }, ServiceTarget.InitiateAuth, this.cognitoEndpoint);
178
+ });
161
179
  if (initUserSrpAuthResponse.ChallengeName !== 'PASSWORD_VERIFIER') {
162
180
  return initUserSrpAuthResponse;
163
181
  }
@@ -195,7 +213,6 @@ export class CognitoClient {
195
213
  async authenticateUser(username, password) {
196
214
  const initiateAuthPayload = {
197
215
  AuthFlow: 'USER_PASSWORD_AUTH',
198
- ClientId: this.userPoolClientId,
199
216
  AuthParameters: {
200
217
  USERNAME: username,
201
218
  PASSWORD: password,
@@ -203,13 +220,73 @@ export class CognitoClient {
203
220
  },
204
221
  ClientMetadata: {}
205
222
  };
206
- const initUserPasswordAuthResponse = await cognitoRequest(initiateAuthPayload, ServiceTarget.InitiateAuth, this.cognitoEndpoint);
223
+ const initUserPasswordAuthResponse = await this.initiateAuth(initiateAuthPayload);
207
224
  if (!initUserPasswordAuthResponse.AuthenticationResult) {
208
225
  return initUserPasswordAuthResponse;
209
226
  }
210
- initUserPasswordAuthResponse.AuthenticationResult = adaptExpiresIn(initUserPasswordAuthResponse.AuthenticationResult);
211
227
  return initUserPasswordAuthResponse;
212
228
  }
229
+ /**
230
+ * Initiates the authentication process for a user using a preferred challenge, such as WEB_AUTHN.
231
+ */
232
+ async authenticateWebAuthn(username) {
233
+ const webAuthnPayload = {
234
+ AuthFlow: 'USER_AUTH',
235
+ AuthParameters: {
236
+ USERNAME: username,
237
+ PREFERRED_CHALLENGE: 'WEB_AUTHN'
238
+ }
239
+ };
240
+ const authResponse = await this.initiateAuth(webAuthnPayload);
241
+ if (authResponse.ChallengeName !== 'WEB_AUTHN') {
242
+ throw new InitAuthError('Authentication failed, expected WEB_AUTHN challenge but received: ' + authResponse.ChallengeName, InitiateAuthException.InternalErrorException);
243
+ }
244
+ const credentialRequestOptions = JSON.parse(authResponse.ChallengeParameters.CREDENTIAL_REQUEST_OPTIONS);
245
+ credentialRequestOptions.challenge = base64UrlToUint8Array(credentialRequestOptions.challenge);
246
+ credentialRequestOptions.allowCredentials = (credentialRequestOptions.allowCredentials || []).map((allowCred) => ({
247
+ ...allowCred,
248
+ id: base64UrlToUint8Array(allowCred.id)
249
+ }));
250
+ const credentials = await navigator.credentials.get({
251
+ publicKey: credentialRequestOptions
252
+ });
253
+ const challengeResponse = await this.respondToAuthChallenge({
254
+ ChallengeName: 'WEB_AUTHN',
255
+ ChallengeResponses: {
256
+ USERNAME: username,
257
+ CREDENTIAL: JSON.stringify(publicKeyCredentialToJSON(credentials)),
258
+ SECRET_HASH: this.clientSecret && (await calculateSecretHash(this.clientSecret, this.userPoolClientId, username))
259
+ },
260
+ Session: authResponse.Session
261
+ });
262
+ if (challengeResponse.AuthenticationResult) {
263
+ challengeResponse.AuthenticationResult = adaptExpiresIn(challengeResponse.AuthenticationResult);
264
+ }
265
+ return challengeResponse;
266
+ }
267
+ /**
268
+ * Registers a new WebAuthn device for the current user.
269
+ * This method initiates the WebAuthn registration process by requesting the necessary options from Cognito,
270
+ * then creates a new public key credential using the WebAuthn API, and finally
271
+ * completes the registration by sending the credential back to Cognito.
272
+ *
273
+ * @param accessToken Access token of the current user.
274
+ */
275
+ async registerWebAuthnDevice(accessToken) {
276
+ const { CredentialCreationOptions } = await this.startWebAuthnRegistration({
277
+ AccessToken: accessToken
278
+ });
279
+ const credentials = await navigator.credentials.create({
280
+ publicKey: CredentialCreationOptions
281
+ });
282
+ if (!(credentials instanceof PublicKeyCredential)) {
283
+ throw new Error('Invalid credentials returned from WebAuthn API');
284
+ }
285
+ await this.completeWebAuthnRegistration({
286
+ AccessToken: accessToken,
287
+ Credential: credentials
288
+ });
289
+ }
213
290
  /**
214
291
  * Returns a new session based on the given refresh token.
215
292
  *
@@ -221,7 +298,6 @@ export class CognitoClient {
221
298
  async refreshSession(refreshToken, username) {
222
299
  const refreshTokenPayload = {
223
300
  AuthFlow: 'REFRESH_TOKEN_AUTH',
224
- ClientId: this.userPoolClientId,
225
301
  AuthParameters: {
226
302
  REFRESH_TOKEN: refreshToken,
227
303
  SECRET_HASH: this.clientSecret &&
@@ -230,14 +306,14 @@ export class CognitoClient {
230
306
  },
231
307
  ClientMetadata: {}
232
308
  };
233
- const { AuthenticationResult } = await cognitoRequest(refreshTokenPayload, ServiceTarget.InitiateAuth, this.cognitoEndpoint);
309
+ const { AuthenticationResult } = await this.initiateAuth(refreshTokenPayload);
234
310
  if (!AuthenticationResult) {
235
311
  throw new InitAuthError('Authentication failed, no authentication result returned', InitiateAuthException.InternalErrorException);
236
312
  }
237
313
  if (!AuthenticationResult.RefreshToken) {
238
314
  AuthenticationResult.RefreshToken = refreshToken;
239
315
  }
240
- return adaptExpiresIn(AuthenticationResult);
316
+ return AuthenticationResult;
241
317
  }
242
318
  /**
243
319
  *
@@ -292,15 +368,40 @@ export class CognitoClient {
292
368
  };
293
369
  await cognitoRequest(changePasswordPayload, ServiceTarget.ChangePassword, this.cognitoEndpoint);
294
370
  }
371
+ /**
372
+ * Gets the user information.
373
+ * @param accessToken Access token of the current user.
374
+ * @returns User information.
375
+ */
295
376
  async getUser(accessToken) {
296
377
  const getUserPayload = {
297
378
  AccessToken: accessToken
298
379
  };
299
380
  return cognitoRequest(getUserPayload, ServiceTarget.GetUser, this.cognitoEndpoint);
300
381
  }
382
+ /**
383
+ * Associates a software token with the user.
384
+ * @param params Request to associate a software token with the user.
385
+ * @param params.AccessToken Access token of the current user.
386
+ * @param params.Session Optional session identifier for the authentication process.
387
+ * @param params.ClientMetadata Optional metadata to pass to the service.
388
+ * @param params.UserContextData Optional user context data.
389
+ * @param params.AnalyticsMetadata Optional analytics metadata.
390
+ * @param params.FriendlyDeviceName Optional friendly name for the device.
391
+ * @returns
392
+ */
301
393
  async associateSoftwareToken(params) {
302
394
  return cognitoRequest(params, ServiceTarget.AssociateSoftwareToken, this.cognitoEndpoint);
303
395
  }
396
+ /**
397
+ * Verifies a software token.
398
+ * @param params Request to verify a software token.
399
+ * @param params.AccessToken Access token of the current user.
400
+ * @param params.FriendlyDeviceName Optional friendly name for the device.
401
+ * @param params.Session Optional session identifier for the authentication process.
402
+ * @param params.UserCode The user code to verify.
403
+ * @returns
404
+ */
304
405
  async verifySoftwareToken(params) {
305
406
  return cognitoRequest(params, ServiceTarget.VerifySoftwareToken, this.cognitoEndpoint);
306
407
  }
@@ -439,6 +540,51 @@ export class CognitoClient {
439
540
  };
440
541
  await cognitoRequest(resendConfirmationCodeRequest, ServiceTarget.ResendConfirmationCode, this.cognitoEndpoint);
441
542
  }
543
+ async startWebAuthnRegistration(request) {
544
+ const response = await cognitoRequest(request, ServiceTarget.StartWebAuthnRegistration, this.cognitoEndpoint);
545
+ response.CredentialCreationOptions.challenge = base64UrlToUint8Array(response.CredentialCreationOptions.challenge);
546
+ response.CredentialCreationOptions.user.id = base64UrlToUint8Array(response.CredentialCreationOptions.user.id);
547
+ response.CredentialCreationOptions.excludeCredentials = (response.CredentialCreationOptions.excludeCredentials || []).map((excludeCred) => ({
548
+ ...excludeCred,
549
+ id: base64UrlToUint8Array(excludeCred.id)
550
+ }));
551
+ return response;
552
+ }
553
+ /**
554
+ * Completes registration of a passkey authenticator for the currently signed-in user.
555
+ * @param request Request to complete WebAuthn registration.
556
+ * @param request.AccessToken Access token of the current user.
557
+ * @param request.Credential The credential object returned by the WebAuthn API.
558
+ */
559
+ async completeWebAuthnRegistration(request) {
560
+ await cognitoRequest({
561
+ AccessToken: request.AccessToken,
562
+ Credential: publicKeyCredentialToJSON(request.Credential)
563
+ }, ServiceTarget.CompleteWebAuthnRegistration, this.cognitoEndpoint);
564
+ }
565
+ /**
566
+ * Deletes a registered passkey, or WebAuthn, authenticator for the currently signed-in user.
567
+ *
568
+ * @param request Request to delete a WebAuthn credential.
569
+ * @param request.AccessToken Access token of the current user.
570
+ * @param request.CredentialId The ID of the credential to delete.
571
+ */
572
+ async deleteWebAuthnCredential(request) {
573
+ await cognitoRequest(request, ServiceTarget.DeleteWebAuthnCredential, this.cognitoEndpoint);
574
+ }
575
+ /**
576
+ * Lists all registered WebAuthn credentials for the currently signed-in user.
577
+ *
578
+ * @param request Request to list WebAuthn credentials.
579
+ * @param request.AccessToken Access token of the current user.
580
+ * @param request.MaxResults Maximum number of credentials to return.
581
+ * @param request.NextToken Pagination token to continue listing credentials.
582
+ * @returns
583
+ */
584
+ async listWebAuthnCredentials(request) {
585
+ const response = await cognitoRequest(request, ServiceTarget.ListWebAuthnCredentials, this.cognitoEndpoint);
586
+ return response;
587
+ }
442
588
  /**
443
589
  * Returns a link to Cognito`s Hosted UI for OAuth2 authentication.
444
590
  * This method works in conjunction with @see handleCodeFlow .
package/lib/error.js CHANGED
@@ -401,6 +401,8 @@ export var RevokeTokenException;
401
401
  RevokeTokenException["UnsupportedTokenTypeException"] = "UnsupportedTokenTypeException";
402
402
  })(RevokeTokenException || (RevokeTokenException = {}));
403
403
  export class CognitoError extends Error {
404
+ errorType;
405
+ cognitoException;
404
406
  constructor(message, errorType, cognitoException) {
405
407
  super(message);
406
408
  this.errorType = errorType;
@@ -408,108 +410,126 @@ export class CognitoError extends Error {
408
410
  }
409
411
  }
410
412
  export class CommonError extends CognitoError {
413
+ cognitoException;
411
414
  constructor(message, cognitoException) {
412
415
  super(message, 'CommonError', cognitoException);
413
416
  this.cognitoException = cognitoException;
414
417
  }
415
418
  }
416
419
  export class InitAuthError extends CognitoError {
420
+ cognitoException;
417
421
  constructor(message, cognitoException) {
418
422
  super(message, 'InitAuthError', cognitoException);
419
423
  this.cognitoException = cognitoException;
420
424
  }
421
425
  }
422
426
  export class RespondToAuthChallengeError extends CognitoError {
427
+ cognitoException;
423
428
  constructor(message, cognitoException) {
424
429
  super(message, 'RespondToAuthChallengeError', cognitoException);
425
430
  this.cognitoException = cognitoException;
426
431
  }
427
432
  }
428
433
  export class SignUpError extends CognitoError {
434
+ cognitoException;
429
435
  constructor(message, cognitoException) {
430
436
  super(message, 'SignUpError', cognitoException);
431
437
  this.cognitoException = cognitoException;
432
438
  }
433
439
  }
434
440
  export class ConfirmSignUpError extends CognitoError {
441
+ cognitoException;
435
442
  constructor(message, cognitoException) {
436
443
  super(message, 'ConfirmSignUpError', cognitoException);
437
444
  this.cognitoException = cognitoException;
438
445
  }
439
446
  }
440
447
  export class ChangePasswordError extends CognitoError {
448
+ cognitoException;
441
449
  constructor(message, cognitoException) {
442
450
  super(message, 'ChangePasswordError', cognitoException);
443
451
  this.cognitoException = cognitoException;
444
452
  }
445
453
  }
446
454
  export class RevokeTokenError extends CognitoError {
455
+ cognitoException;
447
456
  constructor(message, cognitoException) {
448
457
  super(message, 'RevokeTokenError', cognitoException);
449
458
  this.cognitoException = cognitoException;
450
459
  }
451
460
  }
452
461
  export class ForgotPasswordError extends CognitoError {
462
+ cognitoException;
453
463
  constructor(message, cognitoException) {
454
464
  super(message, 'ForgotPasswordError', cognitoException);
455
465
  this.cognitoException = cognitoException;
456
466
  }
457
467
  }
458
468
  export class ConfirmForgotPasswordError extends CognitoError {
469
+ cognitoException;
459
470
  constructor(message, cognitoException) {
460
471
  super(message, 'ConfirmForgotPasswordError', cognitoException);
461
472
  this.cognitoException = cognitoException;
462
473
  }
463
474
  }
464
475
  export class ResendConfirmationCodeError extends CognitoError {
476
+ cognitoException;
465
477
  constructor(message, cognitoException) {
466
478
  super(message, 'ResendConfirmationCodeError', cognitoException);
467
479
  this.cognitoException = cognitoException;
468
480
  }
469
481
  }
470
482
  export class UpdateUserAttributesError extends CognitoError {
483
+ cognitoException;
471
484
  constructor(message, cognitoException) {
472
485
  super(message, 'UpdateUserAttributesError', cognitoException);
473
486
  this.cognitoException = cognitoException;
474
487
  }
475
488
  }
476
489
  export class VerifyUserAttributeError extends CognitoError {
490
+ cognitoException;
477
491
  constructor(message, cognitoException) {
478
492
  super(message, 'VerifyUserAttributeError', cognitoException);
479
493
  this.cognitoException = cognitoException;
480
494
  }
481
495
  }
482
496
  export class GlobalSignOutError extends CognitoError {
497
+ cognitoException;
483
498
  constructor(message, cognitoException) {
484
499
  super(message, 'GlobalSignOutError', cognitoException);
485
500
  this.cognitoException = cognitoException;
486
501
  }
487
502
  }
488
503
  export class VerifySoftwareTokenError extends CognitoError {
504
+ cognitoException;
489
505
  constructor(message, cognitoException) {
490
506
  super(message, 'VerifySoftwareTokenError', cognitoException);
491
507
  this.cognitoException = cognitoException;
492
508
  }
493
509
  }
494
510
  export class AssociateSoftwareTokenError extends CognitoError {
511
+ cognitoException;
495
512
  constructor(message, cognitoException) {
496
513
  super(message, 'AssociateSoftwareTokenError', cognitoException);
497
514
  this.cognitoException = cognitoException;
498
515
  }
499
516
  }
500
517
  export class SetUserMFAPreferenceError extends CognitoError {
518
+ cognitoException;
501
519
  constructor(message, cognitoException) {
502
520
  super(message, 'SetUserMFAPreferenceError', cognitoException);
503
521
  this.cognitoException = cognitoException;
504
522
  }
505
523
  }
506
524
  export class ListDevicesError extends CognitoError {
525
+ cognitoException;
507
526
  constructor(message, cognitoException) {
508
527
  super(message, 'ListDevicesError', cognitoException);
509
528
  this.cognitoException = cognitoException;
510
529
  }
511
530
  }
512
531
  export class GetUserError extends CognitoError {
532
+ cognitoException;
513
533
  constructor(message, cognitoException) {
514
534
  super(message, 'GetUserError', cognitoException);
515
535
  this.cognitoException = cognitoException;
package/lib/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './cognito-client.js';
2
2
  export * from './error.js';
3
+ export * from './utils.js';
package/lib/index.js CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './cognito-client.js';
2
2
  export * from './error.js';
3
+ export * from './utils.js';
package/lib/utils.d.ts CHANGED
@@ -1,9 +1,13 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
+ /// <reference types="node" resolution-mode="require"/>
2
3
  export declare function uint8ArrayFromHexString(hexString: string): Uint8Array;
3
4
  export declare function uint8ArrayFromString(str: string): Uint8Array;
4
5
  export declare function uint8ArrayFromBase64String(str: string): Uint8Array;
5
6
  export declare function uint8ArrayToHexString(bytes: Uint8Array): string;
6
- export declare function uint8ArrayToBase64String(bytes: Uint8Array): string;
7
+ export declare function uint8ArrayToBase64String(bytes: Uint8Array | ArrayBuffer): string;
8
+ export declare function uint8ArrayToBase64UrlString(bytes: Uint8Array | ArrayBuffer | undefined): string | undefined;
9
+ export declare function base64UrlToUint8Array(base64: string): Uint8Array;
10
+ export declare function publicKeyCredentialToJSON(cred: any): any;
7
11
  export declare function padHex(bigInt: bigint): string;
8
12
  export declare function hashHexString(str: string): Promise<string>;
9
13
  export declare function hashBuffer(buffer: Uint8Array): Promise<string>;
@@ -27,3 +31,4 @@ export declare function formatTimestamp(date: Date): string;
27
31
  export declare function calculateSecretHash(clientSecret: string, userPoolClientId: string, username: string): Promise<string>;
28
32
  export declare function digest(algorithm: AlgorithmIdentifier, data: Uint8Array): Promise<Uint8Array>;
29
33
  export declare function hmac(algorithm: AlgorithmIdentifier, key: Uint8Array, data: Uint8Array): Promise<Uint8Array>;
34
+ export declare function removeUndefined(obj: any): any;
package/lib/utils.js CHANGED
@@ -20,8 +20,49 @@ export function uint8ArrayToHexString(bytes) {
20
20
  return bytes.reduce((str, byte) => str + byte.toString(16).padStart(2, '0'), '');
21
21
  }
22
22
  export function uint8ArrayToBase64String(bytes) {
23
+ if (bytes instanceof ArrayBuffer) {
24
+ const byteArray = new Uint8Array(bytes);
25
+ return btoa(String.fromCharCode(...byteArray));
26
+ }
23
27
  return btoa(String.fromCharCode(...bytes));
24
28
  }
29
+ export function uint8ArrayToBase64UrlString(bytes) {
30
+ if (bytes === undefined) {
31
+ return undefined;
32
+ }
33
+ const base64String = uint8ArrayToBase64String(bytes);
34
+ return base64String.replaceAll('+', '-').replaceAll('/', '_').replace(/=+$/, '');
35
+ }
36
+ export function base64UrlToUint8Array(base64) {
37
+ const binary = atob(base64.replace(/-/g, '+').replace(/_/g, '/'));
38
+ const len = binary.length;
39
+ const bytes = new Uint8Array(len);
40
+ for (let i = 0; i < len; i++) {
41
+ bytes[i] = binary.charCodeAt(i);
42
+ }
43
+ return bytes;
44
+ }
45
+ export function publicKeyCredentialToJSON(cred) {
46
+ return removeUndefined({
47
+ authenticatorAttachment: cred.authenticatorAttachment,
48
+ clientExtensionResults: cred.getClientExtensionResults(),
49
+ id: cred.id,
50
+ rawId: uint8ArrayToBase64UrlString(cred.rawId),
51
+ response: {
52
+ attestationObject: uint8ArrayToBase64UrlString(cred.response.attestationObject),
53
+ authenticatorData: cred.response.authenticatorData
54
+ ? uint8ArrayToBase64UrlString(cred.response.authenticatorData)
55
+ : undefined,
56
+ clientDataJSON: uint8ArrayToBase64UrlString(cred.response.clientDataJSON),
57
+ publicKey: cred.response.getPublicKey ? uint8ArrayToBase64UrlString(cred.response.getPublicKey()) : undefined,
58
+ publicKeyAlgorithm: cred.response.getPublicKeyAlgorithm ? cred.response.getPublicKeyAlgorithm() : undefined,
59
+ transports: cred.response.getTransports ? cred.response.getTransports() : undefined,
60
+ signature: cred.response.signature ? uint8ArrayToBase64UrlString(cred.response.signature) : undefined,
61
+ userHandle: cred.response.userHandle ? uint8ArrayToBase64UrlString(cred.response.userHandle) : undefined
62
+ },
63
+ type: cred.type
64
+ });
65
+ }
25
66
  const N = BigInt('0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1' +
26
67
  '29024E088A67CC74020BBEA63B139B22514A08798E3404DD' +
27
68
  'EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245' +
@@ -151,3 +192,18 @@ export async function hmac(algorithm, key, data) {
151
192
  const signature = await crypto.subtle.sign('HMAC', cryptoKey, data);
152
193
  return new Uint8Array(signature);
153
194
  }
195
+ export function removeUndefined(obj) {
196
+ if (Array.isArray(obj)) {
197
+ return obj.map(item => removeUndefined(item)).filter(item => item !== undefined);
198
+ }
199
+ if (obj !== null && typeof obj === 'object') {
200
+ return Object.entries(obj).reduce((acc, [key, value]) => {
201
+ const cleaned = removeUndefined(value);
202
+ if (cleaned !== undefined) {
203
+ acc[key] = cleaned;
204
+ }
205
+ return acc;
206
+ }, {});
207
+ }
208
+ return obj !== undefined ? obj : undefined;
209
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vardario/cognito-client",
3
- "version": "5.1.0",
3
+ "version": "5.2.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Sahin Vardar",
@@ -27,7 +27,7 @@
27
27
  "devDependencies": {
28
28
  "@aws-sdk/client-cognito-identity-provider": "^3.465.0",
29
29
  "@types/jsdom": "^21.1.5",
30
- "@types/node": "^20",
30
+ "@types/node": "^24",
31
31
  "@typescript-eslint/eslint-plugin": "^6.11.0",
32
32
  "@typescript-eslint/parser": "^6.11.0",
33
33
  "esbuild": "^0.25.8",
@@ -36,15 +36,15 @@
36
36
  "eslint-plugin-unused-imports": "^4.1.4",
37
37
  "husky": "^8.0.3",
38
38
  "isomorphic-fetch": "^3.0.0",
39
- "jsdom": "^22.1.0",
40
- "lint-staged": "^15.1.0",
39
+ "jsdom": "^26.1.0",
40
+ "lint-staged": "^16.1.4",
41
41
  "prettier": "^3.1.0",
42
42
  "prettier-package-json": "^2.8.0",
43
- "semantic-release": "^22.0.8",
44
- "testcontainers": "^10.2.2",
43
+ "semantic-release": "^24.2.7",
44
+ "testcontainers": "^11.5.1",
45
45
  "tsx": "^4.7.1",
46
46
  "typescript": "^5.2.2",
47
- "vitest": "^0.34.6",
47
+ "vitest": "^3.2.4",
48
48
  "vitest-fetch-mock": "^0.2.2"
49
49
  },
50
50
  "lint-staged": {