@vardario/cognito-client 2.0.0 → 2.1.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.
@@ -1,7 +1,158 @@
1
+ export interface CognitoBaseRequest {
2
+ ClientId: string;
3
+ ClientMetadata?: Record<string, string>;
4
+ AnalyticsMetadata?: {
5
+ AnalyticsEndpointId: string;
6
+ };
7
+ UserContextData?: {
8
+ EncodedData?: string;
9
+ IpAddress?: string;
10
+ };
11
+ }
12
+ export interface AuthIntiUserSrpRequest extends CognitoBaseRequest {
13
+ AuthFlow: 'USER_SRP_AUTH';
14
+ AuthParameters: {
15
+ USERNAME: string;
16
+ SRP_A: string;
17
+ SECRET_HASH?: string;
18
+ };
19
+ }
20
+ export interface AuthIntiUserPasswordRequest extends CognitoBaseRequest {
21
+ AuthFlow: 'USER_PASSWORD_AUTH';
22
+ AuthParameters: {
23
+ USERNAME: string;
24
+ PASSWORD: string;
25
+ SECRET_HASH?: string;
26
+ };
27
+ }
28
+ export interface AuthIntiRefreshTokenRequest extends CognitoBaseRequest {
29
+ AuthFlow: 'REFRESH_TOKEN_AUTH';
30
+ AuthParameters: {
31
+ REFRESH_TOKEN: string;
32
+ SECRET_HASH?: string;
33
+ };
34
+ }
35
+ export interface AuthIntiCustomAuthRequest extends CognitoBaseRequest {
36
+ AuthFlow: 'CUSTOM_AUTH';
37
+ AuthParameters: {
38
+ USERNAME: string;
39
+ SECRET_HASH?: string;
40
+ };
41
+ }
42
+ export type AuthIntiRequest = AuthIntiUserSrpRequest | AuthIntiRefreshTokenRequest | AuthIntiCustomAuthRequest | AuthIntiUserPasswordRequest;
43
+ export interface RespondToAuthChallengeBaseRequest extends CognitoBaseRequest {
44
+ Session?: string;
45
+ }
46
+ export interface RespondToAuthChallengePasswordVerifierRequest extends RespondToAuthChallengeBaseRequest {
47
+ ChallengeName: 'PASSWORD_VERIFIER';
48
+ ChallengeResponses: {
49
+ USERNAME: string;
50
+ PASSWORD_CLAIM_SECRET_BLOCK: string;
51
+ PASSWORD_CLAIM_SIGNATURE: string;
52
+ TIMESTAMP: string;
53
+ SECRET_HASH?: string;
54
+ };
55
+ }
56
+ export interface RespondToAuthChallengeSmsMfaRequest extends RespondToAuthChallengeBaseRequest {
57
+ ChallengeName: 'SMS_MFA';
58
+ ChallengeResponses: {
59
+ USERNAME: string;
60
+ SMS_MFA_CODE: string;
61
+ SECRET_HASH?: string;
62
+ };
63
+ }
64
+ export interface RespondToAuthChallengeCustomChallengeNameRequest extends RespondToAuthChallengeBaseRequest {
65
+ ChallengeName: 'CUSTOM_CHALLENGE';
66
+ ChallengeResponses: {
67
+ USERNAME: string;
68
+ ANSWER: string;
69
+ SECRET_HASH?: string;
70
+ };
71
+ }
72
+ export interface RespondToAuthChallengeNewPasswordRequiredRequest extends RespondToAuthChallengeBaseRequest {
73
+ ChallengeName: 'NEW_PASSWORD_REQUIRED';
74
+ ChallengeResponses: {
75
+ USERNAME: string;
76
+ NEW_PASSWORD: string;
77
+ SECRET_HASH?: string;
78
+ };
79
+ }
80
+ export interface RespondToAuthChallengeSoftwareTokenMfaRequest extends RespondToAuthChallengeBaseRequest {
81
+ ChallengeName: 'SOFTWARE_TOKEN_MFA';
82
+ ChallengeResponses: {
83
+ USERNAME: string;
84
+ SOFTWARE_TOKEN_MFA_CODE: string;
85
+ SECRET_HASH?: string;
86
+ };
87
+ }
88
+ export interface RespondToAuthChallengeDeviceSrpAuthRequest extends RespondToAuthChallengeBaseRequest {
89
+ ChallengeName: 'DEVICE_SRP_AUTH';
90
+ ChallengeResponses: {
91
+ USERNAME: string;
92
+ SRP_A: string;
93
+ SECRET_HASH?: string;
94
+ };
95
+ }
96
+ export interface RespondToAuthChallengeDevicePasswordVerifierRequest extends RespondToAuthChallengeBaseRequest {
97
+ ChallengeName: 'DEVICE_PASSWORD_VERIFIER';
98
+ ChallengeResponses: {
99
+ USERNAME: string;
100
+ PASSWORD_CLAIM_SECRET_BLOCK: string;
101
+ PASSWORD_CLAIM_SIGNATURE: string;
102
+ TIMESTAMP: string;
103
+ DEVICE_KEY: string;
104
+ SECRET_HASH?: string;
105
+ };
106
+ }
107
+ export interface RespondToAuthChallengeMfaSetupRequest extends RespondToAuthChallengeBaseRequest {
108
+ ChallengeName: 'MFA_SETUP';
109
+ ChallengeResponses: {
110
+ USERNAME: string;
111
+ SMS_MFA_CODE?: string;
112
+ SOFTWARE_TOKEN_MFA_CODE?: string;
113
+ SECRET_HASH?: string;
114
+ };
115
+ }
116
+ export interface RespondToAuthChallengeSelectMfaTypeRequest extends RespondToAuthChallengeBaseRequest {
117
+ ChallengeName: 'SELECT_MFA_TYPE';
118
+ ChallengeResponses: {
119
+ USERNAME: string;
120
+ SOFTWARE_TOKEN_MFA_CODE?: string;
121
+ SECRET_HASH?: string;
122
+ };
123
+ }
124
+ export type RespondToAuthChallengeRequest = RespondToAuthChallengePasswordVerifierRequest | RespondToAuthChallengeSmsMfaRequest | RespondToAuthChallengeCustomChallengeNameRequest | RespondToAuthChallengeNewPasswordRequiredRequest | RespondToAuthChallengeSoftwareTokenMfaRequest | RespondToAuthChallengeDeviceSrpAuthRequest | RespondToAuthChallengeDevicePasswordVerifierRequest | RespondToAuthChallengeMfaSetupRequest | RespondToAuthChallengeSelectMfaTypeRequest;
1
125
  export interface UserAttribute {
2
126
  Name: string;
3
127
  Value: string;
4
128
  }
129
+ export interface ConfirmForgotPasswordRequest extends CognitoBaseRequest {
130
+ ConfirmationCode: string;
131
+ Password: string;
132
+ Username: string;
133
+ SecretHash?: string;
134
+ }
135
+ export interface ConfirmSignUpRequest extends CognitoBaseRequest {
136
+ ConfirmationCode: string;
137
+ Username: string;
138
+ SecretHash?: string;
139
+ ForceAliasCreation?: boolean;
140
+ }
141
+ export interface ForgotPasswordRequest extends CognitoBaseRequest {
142
+ Username: string;
143
+ SecretHash?: string;
144
+ }
145
+ export interface SignUpRequest extends CognitoBaseRequest {
146
+ Username: string;
147
+ Password: string;
148
+ SecretHash?: string;
149
+ UserAttributes?: UserAttribute[];
150
+ ValidationData?: UserAttribute[];
151
+ }
152
+ export interface ResendConfirmationCodeRequest extends CognitoBaseRequest {
153
+ Username: string;
154
+ SecretHash?: string;
155
+ }
5
156
  /**
6
157
  * Cognito related OAuth props.
7
158
  */
@@ -43,6 +194,10 @@ export interface CognitoClientProps {
43
194
  * Cognito OAuth related options. See @see OAuthProps .
44
195
  */
45
196
  oAuth2?: OAuth2Props;
197
+ /**
198
+ * Optional Cognito User Pool Client Secret.
199
+ */
200
+ clientSecret?: string;
46
201
  }
47
202
  /**
48
203
  * Cognito User Session
@@ -159,7 +314,8 @@ export declare class CognitoClient {
159
314
  private readonly cognitoPoolName;
160
315
  private readonly userPoolClientId;
161
316
  private readonly oAuth?;
162
- constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth }: CognitoClientProps);
317
+ private readonly clientSecret?;
318
+ constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth, clientSecret }: CognitoClientProps);
163
319
  static getDecodedTokenFromSession(session: Session): DecodedTokens;
164
320
  /**
165
321
  *
@@ -186,10 +342,11 @@ export declare class CognitoClient {
186
342
  * Returns a new session based on the given refresh token.
187
343
  *
188
344
  * @param refreshToken
345
+ * @param username
189
346
  * @returns @see Session
190
347
  * @throws {InitiateAuthException}
191
348
  */
192
- refreshSession(refreshToken: string): Promise<Session>;
349
+ refreshSession(refreshToken: string, username?: string): Promise<Session>;
193
350
  /**
194
351
  *
195
352
  * @param username Username
@@ -2,7 +2,7 @@ import hashJs from 'hash.js';
2
2
  import { BigInteger } from 'jsbn';
3
3
  import { Buffer } from 'buffer';
4
4
  import { CognitoCommonException, CognitoError } from './error.js';
5
- import { calculateSignature, calculateU, decodeJwt, generateA, generateSmallA, getPasswordAuthenticationKey, randomBytes } from './utils.js';
5
+ import { calculateSecretHash, calculateSignature, calculateU, decodeJwt, generateA, generateSmallA, getPasswordAuthenticationKey, randomBytes } from './utils.js';
6
6
  /**
7
7
  * List of used and supported Cognito API calls.
8
8
  * @see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_Operations.html for more details
@@ -79,12 +79,13 @@ export async function cognitoRequest(body, serviceTarget, cognitoEndpoint) {
79
79
  * Lightweight AWS Cogito client without any AWS SDK dependencies.
80
80
  */
81
81
  export class CognitoClient {
82
- constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth }) {
82
+ constructor({ userPoolId, userPoolClientId, endpoint, oAuth2: oAuth, clientSecret }) {
83
83
  const [cognitoPoolRegion, cognitoPoolName] = userPoolId.split('_');
84
84
  this.cognitoEndpoint = (endpoint || `https://cognito-idp.${cognitoPoolRegion}.amazonaws.com`).replace(/\/$/, '');
85
85
  this.cognitoPoolName = cognitoPoolName;
86
86
  this.userPoolClientId = userPoolClientId;
87
87
  this.oAuth = oAuth;
88
+ this.clientSecret = clientSecret;
88
89
  }
89
90
  static getDecodedTokenFromSession(session) {
90
91
  const { payload: idToken } = decodeJwt(session.idToken);
@@ -112,7 +113,8 @@ export class CognitoClient {
112
113
  ClientId: this.userPoolClientId,
113
114
  AuthParameters: {
114
115
  USERNAME: username,
115
- SRP_A: A.toString(16)
116
+ SRP_A: A.toString(16),
117
+ SECRET_HASH: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
116
118
  },
117
119
  ClientMetadata: {}
118
120
  };
@@ -122,18 +124,20 @@ export class CognitoClient {
122
124
  const U = calculateU(A, B);
123
125
  const hkdf = getPasswordAuthenticationKey(this.cognitoPoolName, challenge.ChallengeParameters.USER_ID_FOR_SRP, password, B, U, smallA, salt);
124
126
  const { signature, timeStamp } = calculateSignature(this.cognitoPoolName, challenge.ChallengeParameters.USER_ID_FOR_SRP, challenge.ChallengeParameters.SECRET_BLOCK, hkdf);
125
- const respondToAuthChallengePayload = {
127
+ const respondToAuthChallengeRequest = {
126
128
  ChallengeName: 'PASSWORD_VERIFIER',
127
129
  ClientId: this.userPoolClientId,
128
130
  ChallengeResponses: {
129
131
  PASSWORD_CLAIM_SECRET_BLOCK: challenge.ChallengeParameters.SECRET_BLOCK,
130
132
  PASSWORD_CLAIM_SIGNATURE: signature,
131
133
  USERNAME: challenge.ChallengeParameters.USER_ID_FOR_SRP,
132
- TIMESTAMP: timeStamp
134
+ TIMESTAMP: timeStamp,
135
+ SECRET_HASH: this.clientSecret &&
136
+ calculateSecretHash(this.clientSecret, this.userPoolClientId, challenge.ChallengeParameters.USER_ID_FOR_SRP)
133
137
  },
134
138
  ClientMetadata: {}
135
139
  };
136
- const { AuthenticationResult } = await cognitoRequest(respondToAuthChallengePayload, CognitoServiceTarget.RespondToAuthChallenge, this.cognitoEndpoint);
140
+ const { AuthenticationResult } = await cognitoRequest(respondToAuthChallengeRequest, CognitoServiceTarget.RespondToAuthChallenge, this.cognitoEndpoint);
137
141
  return authResultToSession(AuthenticationResult);
138
142
  }
139
143
  /**
@@ -151,7 +155,8 @@ export class CognitoClient {
151
155
  ClientId: this.userPoolClientId,
152
156
  AuthParameters: {
153
157
  USERNAME: username,
154
- PASSWORD: password
158
+ PASSWORD: password,
159
+ SECRET_HASH: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
155
160
  },
156
161
  ClientMetadata: {}
157
162
  };
@@ -163,15 +168,17 @@ export class CognitoClient {
163
168
  * Returns a new session based on the given refresh token.
164
169
  *
165
170
  * @param refreshToken
171
+ * @param username
166
172
  * @returns @see Session
167
173
  * @throws {InitiateAuthException}
168
174
  */
169
- async refreshSession(refreshToken) {
175
+ async refreshSession(refreshToken, username) {
170
176
  const refreshTokenPayload = {
171
177
  AuthFlow: 'REFRESH_TOKEN_AUTH',
172
178
  ClientId: this.userPoolClientId,
173
179
  AuthParameters: {
174
- REFRESH_TOKEN: refreshToken
180
+ REFRESH_TOKEN: refreshToken,
181
+ SECRET_HASH: this.clientSecret && username && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
175
182
  },
176
183
  ClientMetadata: {}
177
184
  };
@@ -189,13 +196,14 @@ export class CognitoClient {
189
196
  * @throws {SignUpException}
190
197
  */
191
198
  async signUp(username, password, userAttributes) {
192
- const signUpPayload = {
199
+ const signUpRequest = {
193
200
  ClientId: this.userPoolClientId,
194
201
  Username: username,
195
202
  Password: password,
196
- UserAttributes: userAttributes
203
+ UserAttributes: userAttributes,
204
+ SecretHash: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
197
205
  };
198
- const data = await cognitoRequest(signUpPayload, CognitoServiceTarget.SignUp, this.cognitoEndpoint);
206
+ const data = await cognitoRequest(signUpRequest, CognitoServiceTarget.SignUp, this.cognitoEndpoint);
199
207
  return {
200
208
  id: data.UserSub,
201
209
  confirmed: data.UserConfirmed
@@ -210,12 +218,13 @@ export class CognitoClient {
210
218
  * @throws {ConfirmSignUpException}
211
219
  */
212
220
  async confirmSignUp(username, code) {
213
- const confirmSignUpPayload = {
221
+ const confirmSignUpRequest = {
214
222
  ClientId: this.userPoolClientId,
215
223
  ConfirmationCode: code,
216
- Username: username
224
+ Username: username,
225
+ SecretHash: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
217
226
  };
218
- await cognitoRequest(confirmSignUpPayload, CognitoServiceTarget.ConfirmSignUp, this.cognitoEndpoint);
227
+ await cognitoRequest(confirmSignUpRequest, CognitoServiceTarget.ConfirmSignUp, this.cognitoEndpoint);
219
228
  }
220
229
  /**
221
230
  *
@@ -283,11 +292,12 @@ export class CognitoClient {
283
292
  * @throws {ForgotPasswordException}
284
293
  */
285
294
  async forgotPassword(username) {
286
- const forgotPasswordPayload = {
295
+ const forgotPasswordRequest = {
287
296
  ClientId: this.userPoolClientId,
288
- Username: username
297
+ Username: username,
298
+ SecretHash: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
289
299
  };
290
- await cognitoRequest(forgotPasswordPayload, CognitoServiceTarget.ForgotPassword, this.cognitoEndpoint);
300
+ await cognitoRequest(forgotPasswordRequest, CognitoServiceTarget.ForgotPassword, this.cognitoEndpoint);
291
301
  }
292
302
  /**
293
303
  * Confirms the new password via the given code send via cognito triggered by @see forgotPassword .
@@ -299,13 +309,14 @@ export class CognitoClient {
299
309
  * @throws {ConfirmForgotPasswordException}
300
310
  */
301
311
  async confirmForgotPassword(username, newPassword, confirmationCode) {
302
- const confirmForgotPasswordPayload = {
312
+ const confirmForgotPasswordRequest = {
303
313
  ClientId: this.userPoolClientId,
304
314
  Username: username,
305
315
  ConfirmationCode: confirmationCode,
306
- Password: newPassword
316
+ Password: newPassword,
317
+ SecretHash: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
307
318
  };
308
- await cognitoRequest(confirmForgotPasswordPayload, CognitoServiceTarget.ConfirmForgotPassword, this.cognitoEndpoint);
319
+ await cognitoRequest(confirmForgotPasswordRequest, CognitoServiceTarget.ConfirmForgotPassword, this.cognitoEndpoint);
309
320
  }
310
321
  /**
311
322
  * Triggers cognito to resend the confirmation code
@@ -314,11 +325,12 @@ export class CognitoClient {
314
325
  * @throws {ResendConfirmationCodeException}
315
326
  */
316
327
  async resendConfirmationCode(username) {
317
- const resendConfirmationCodePayLoad = {
328
+ const resendConfirmationCodeRequest = {
318
329
  ClientId: this.userPoolClientId,
319
- Username: username
330
+ Username: username,
331
+ SecretHash: this.clientSecret && calculateSecretHash(this.clientSecret, this.userPoolClientId, username)
320
332
  };
321
- await cognitoRequest(resendConfirmationCodePayLoad, CognitoServiceTarget.ResendConfirmationCode, this.cognitoEndpoint);
333
+ await cognitoRequest(resendConfirmationCodeRequest, CognitoServiceTarget.ResendConfirmationCode, this.cognitoEndpoint);
322
334
  }
323
335
  /**
324
336
  * Returns a link to Cognito`s Hosted UI for OAuth2 authentication.
package/lib/utils.d.ts CHANGED
@@ -21,3 +21,4 @@ export declare function decodeJwt<T = unknown>(jwt: string): {
21
21
  };
22
22
  export declare function randomBytes(num: number): Promise<Buffer>;
23
23
  export declare function formatTimestamp(date: Date): string;
24
+ export declare function calculateSecretHash(clientSecret: string, userPoolClientId: string, username: string): string;
package/lib/utils.js CHANGED
@@ -123,3 +123,11 @@ export async function randomBytes(num) {
123
123
  export function formatTimestamp(date) {
124
124
  return formatInTimeZone(date, 'UTC', "EEE MMM d HH:mm:ss 'UTC' yyyy");
125
125
  }
126
+ export function calculateSecretHash(clientSecret, userPoolClientId, username) {
127
+ const message = `${username}${userPoolClientId}`;
128
+ const hash = Buffer.from(hashJs
129
+ .hmac(hashJs.sha256, clientSecret)
130
+ .update(message)
131
+ .digest()).toString('base64');
132
+ return hash;
133
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vardario/cognito-client",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "author": "Sahin Vardar",