@vardario/cognito-client 0.1.4 → 0.1.5

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.
@@ -0,0 +1,292 @@
1
+ import { SessionStorage } from './session-storage/index.js';
2
+ export interface UserAttribute {
3
+ Name: string;
4
+ Value: string;
5
+ }
6
+ /**
7
+ * Cognito related OAuth props.
8
+ */
9
+ export interface OAuth2Props {
10
+ /**
11
+ * Cognito domain for OAuth2 token endpoints.
12
+ */
13
+ cognitoDomain: string;
14
+ /**
15
+ * Requested OAuth scopes
16
+ * @example ['email', 'openid']
17
+ */
18
+ scopes: string[];
19
+ /**
20
+ * Redirect URL after a successful OAuth2 authentication.
21
+ */
22
+ redirectUrl: string;
23
+ /**
24
+ * Response type.
25
+ */
26
+ responseType: 'code';
27
+ }
28
+ export interface CognitoClientProps {
29
+ /**
30
+ * Cognito User Pool ID
31
+ * @example eu-central-1_lv6wixN9f
32
+ */
33
+ userPoolId: string;
34
+ /**
35
+ * Cognito User Pool Client ID
36
+ */
37
+ userPoolClientId: string;
38
+ /**
39
+ * Optional Cognito endpoint. Useful for local testing.
40
+ * If not defined the endpoint will be determined by @see userPoolId .
41
+ */
42
+ endpoint?: string;
43
+ /**
44
+ * Session storage.
45
+ * You can either choose on of the provided build in session
46
+ * storages. Or provider your own one based on @see SessionStorage .
47
+ *
48
+ * <ul>
49
+ * <li>
50
+ * @see CookieSessionStorage
51
+ * </li>
52
+ * <li>
53
+ * @see MemorySessionStorage
54
+ * </li>
55
+ * </ul>
56
+ */
57
+ sessionStorage: SessionStorage;
58
+ /**
59
+ * Cognito OAuth related options. See @see OAuthProps .
60
+ */
61
+ oAuth2?: OAuth2Props;
62
+ }
63
+ /**
64
+ * Cognito User Session
65
+ */
66
+ export interface Session {
67
+ /**
68
+ * JWT Access Token
69
+ */
70
+ accessToken: string;
71
+ /**
72
+ * JWT ID Token
73
+ */
74
+ idToken: string;
75
+ /**
76
+ * JWT refresh token
77
+ */
78
+ refreshToken: string;
79
+ /**
80
+ * Validity of the session in time stamp as milliseconds.
81
+ */
82
+ expiresIn: number;
83
+ }
84
+ /**
85
+ * Represents the decoded values from a JWT ID token.
86
+ */
87
+ export interface IdToken extends Record<string, string | string[] | number | boolean> {
88
+ 'cognito:username': string;
89
+ 'cognito:groups': string[];
90
+ email_verified: boolean;
91
+ email: string;
92
+ iss: string;
93
+ origin_jti: string;
94
+ aud: string;
95
+ event_id: string;
96
+ token_use: 'id';
97
+ auth_time: number;
98
+ exp: number;
99
+ iat: number;
100
+ jti: string;
101
+ sub: string;
102
+ }
103
+ export interface AccessToken extends Record<string, string | string[] | number | boolean> {
104
+ auth_time: number;
105
+ client_id: string;
106
+ event_id: string;
107
+ exp: number;
108
+ iat: number;
109
+ iss: string;
110
+ jti: string;
111
+ origin_jti: string;
112
+ scope: string;
113
+ sub: string;
114
+ token_use: 'access';
115
+ username: string;
116
+ }
117
+ export interface DecodedTokens {
118
+ idToken: IdToken;
119
+ accessToken: AccessToken;
120
+ }
121
+ /**
122
+ * List of used and supported Cognito API calls.
123
+ * @see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_Operations.html for more details
124
+ */
125
+ export declare enum CognitoServiceTarget {
126
+ InitiateAuth = "InitiateAuth",
127
+ RespondToAuthChallenge = "RespondToAuthChallenge",
128
+ SignUp = "SignUp",
129
+ ConfirmSignUp = "ConfirmSignUp",
130
+ ChangePassword = "ChangePassword",
131
+ RevokeToken = "RevokeToken",
132
+ ForgotPassword = "ForgotPassword",
133
+ ConfirmForgotPassword = "ConfirmForgotPassword",
134
+ ResendConfirmationCode = "ResendConfirmationCode",
135
+ UpdateUserAttributes = "UpdateUserAttributes",
136
+ VerifyUserAttribute = "VerifyUserAttribute"
137
+ }
138
+ /**
139
+ * Cognito supported federated identities public providers.
140
+ * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html for more information.
141
+ */
142
+ export declare enum CognitoIdentityProvider {
143
+ Cognito = "COGNITO",
144
+ Google = "Google",
145
+ Facebook = "Facebook",
146
+ Amazon = "LoginWithAmazon",
147
+ Apple = "SignInWithApple"
148
+ }
149
+ export interface AuthenticationResult {
150
+ AccessToken: string;
151
+ ExpiresIn: number;
152
+ IdToken: string;
153
+ TokenType: string;
154
+ RefreshToken: string;
155
+ }
156
+ export interface AuthenticationResponse {
157
+ AuthenticationResult: AuthenticationResult;
158
+ }
159
+ export interface ChallengeResponse {
160
+ ChallengeName: 'PASSWORD_VERIFIER';
161
+ ChallengeParameters: {
162
+ SALT: string;
163
+ SECRET_BLOCK: string;
164
+ SRP_B: string;
165
+ USERNAME: string;
166
+ USER_ID_FOR_SRP: string;
167
+ };
168
+ }
169
+ /**
170
+ * Lightweight AWS Cogito client without any AWS SDK dependencies.
171
+ */
172
+ export declare class CognitoClient {
173
+ private readonly cognitoEndpoint;
174
+ private readonly cognitoPoolName;
175
+ private readonly userPoolClientId;
176
+ private readonly sessionStorage;
177
+ private readonly oAuth?;
178
+ constructor({ userPoolId, userPoolClientId, endpoint, sessionStorage, oAuth2: oAuth }: CognitoClientProps);
179
+ static getDecodedTokenFromSession(session: Session): DecodedTokens;
180
+ private cognitoRequest;
181
+ private static authResultToSession;
182
+ /**
183
+ *
184
+ * Performs user authentication with username and password through ALLOW_USER_SRP_AUTH .
185
+ * @see https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html for more details
186
+ *
187
+ * @param username Username
188
+ * @param password Password
189
+ * @throws {AuthException}
190
+ */
191
+ authenticateUserSrp(username: string, password: string): Promise<Session>;
192
+ /**
193
+ *
194
+ * Performs user authentication with username and password through USER_PASSWORD_AUTH .
195
+ * @see https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html for more details
196
+ *
197
+ * @param username Username
198
+ * @param password Password
199
+ * @throws {AuthException}
200
+ */
201
+ authenticateUser(username: string, password: string): Promise<Session>;
202
+ private refreshSession;
203
+ /**
204
+ * Returns the current auth session.
205
+ * The auth session is only defined when we previously had a successful user authentication.
206
+ * This function will also take care to refresh the session with the refresh token in case
207
+ * the current session has expired.
208
+ *
209
+ * @throws {AuthException}
210
+ */
211
+ getSession(): Promise<Session | undefined>;
212
+ /**
213
+ *
214
+ * @param username Username
215
+ * @param password Password
216
+ *
217
+ * @throws {AuthException}
218
+ */
219
+ signUp(username: string, password: string, userAttributes?: UserAttribute[]): Promise<{
220
+ id: string;
221
+ confirmed: boolean;
222
+ }>;
223
+ /**
224
+ * Confirms the user registration via verification code.
225
+ *
226
+ * @param username Username
227
+ * @param code Confirmation code the user gets through the registration E-Mail
228
+ *
229
+ * @throws {AuthException}
230
+ */
231
+ confirmSignUp(username: string, code: string): Promise<void>;
232
+ /**
233
+ *
234
+ * @param currentPassword Current user password.
235
+ * @param newPassword New user password.
236
+ *
237
+ * @throws {AuthException}
238
+ */
239
+ changePassword(currentPassword: string, newPassword: string): Promise<void>;
240
+ updateUserAttributes(userAttributes: UserAttribute[]): Promise<void>;
241
+ verifyUserAttribute(attributeName: string, code: string): Promise<void>;
242
+ /**
243
+ * Sign out the user and remove the current user session.
244
+ *
245
+ * @throws {AuthException}
246
+ */
247
+ signOut(): Promise<void>;
248
+ /**
249
+ * Request forgot password.
250
+ * @param username Username
251
+ *
252
+ * @throws {AuthException}
253
+ */
254
+ forgotPassword(username: string): Promise<void>;
255
+ /**
256
+ * Confirms the new password via the given code send via cognito triggered by @see forgotPassword .
257
+ *
258
+ * @param username Username
259
+ * @param newPassword New password
260
+ * @param confirmationCode Confirmation code which the user got through E-mail
261
+ *
262
+ * @throws {AuthException}
263
+ */
264
+ confirmForgotPassword(username: string, newPassword: string, confirmationCode: string): Promise<void>;
265
+ /**
266
+ * Triggers cognito to resend the confirmation code
267
+ * @param username Username
268
+ */
269
+ resendConfirmationCode(username: string): Promise<void>;
270
+ /**
271
+ * Returns a link to Cognito`s Hosted UI for OAuth2 authentication.
272
+ * This method works in conjunction with @see handleCodeFlow .
273
+ *
274
+ * @param identityProvider When provided, this will generate a link which
275
+ * tells Cognito`s Hosted UI to redirect to the given federated identity provider.
276
+ *
277
+ * @throws {Error}
278
+ */
279
+ generateOAuthSignInUrl(identityProvider?: CognitoIdentityProvider): string;
280
+ /**
281
+ *
282
+ * Handles Cognito`s OAuth2 code flow after redirection from Cognito`s Hosted UI.
283
+ * The method call assumes that @see generateOAuthSignInUrl was used to
284
+ * generated the link to the Hosted UI.
285
+ *
286
+ * @param returnUrl The full return URL from redirection after a successful OAuth2
287
+ * authentication.
288
+ *
289
+ * @throws {Error}
290
+ */
291
+ handleCodeFlow(returnUrl: string): Promise<Session>;
292
+ }
@@ -0,0 +1,409 @@
1
+ import addSeconds from 'date-fns/addSeconds';
2
+ import { sha256 } from 'hash.js';
3
+ import { BigInteger } from 'jsbn';
4
+ import randomBytes from 'randombytes';
5
+ import { AuthError, AuthException, getAuthError } from './error.js';
6
+ import { calculateSignature, calculateU, decodeJwt, generateA, generateSmallA, getPasswordAuthenticationKey, } from './utils.js';
7
+ /**
8
+ * List of used and supported Cognito API calls.
9
+ * @see https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_Operations.html for more details
10
+ */
11
+ export var CognitoServiceTarget;
12
+ (function (CognitoServiceTarget) {
13
+ CognitoServiceTarget["InitiateAuth"] = "InitiateAuth";
14
+ CognitoServiceTarget["RespondToAuthChallenge"] = "RespondToAuthChallenge";
15
+ CognitoServiceTarget["SignUp"] = "SignUp";
16
+ CognitoServiceTarget["ConfirmSignUp"] = "ConfirmSignUp";
17
+ CognitoServiceTarget["ChangePassword"] = "ChangePassword";
18
+ CognitoServiceTarget["RevokeToken"] = "RevokeToken";
19
+ CognitoServiceTarget["ForgotPassword"] = "ForgotPassword";
20
+ CognitoServiceTarget["ConfirmForgotPassword"] = "ConfirmForgotPassword";
21
+ CognitoServiceTarget["ResendConfirmationCode"] = "ResendConfirmationCode";
22
+ CognitoServiceTarget["UpdateUserAttributes"] = "UpdateUserAttributes";
23
+ CognitoServiceTarget["VerifyUserAttribute"] = "VerifyUserAttribute";
24
+ })(CognitoServiceTarget || (CognitoServiceTarget = {}));
25
+ /**
26
+ * Cognito supported federated identities public providers.
27
+ * @see https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-identity.html for more information.
28
+ */
29
+ export var CognitoIdentityProvider;
30
+ (function (CognitoIdentityProvider) {
31
+ CognitoIdentityProvider["Cognito"] = "COGNITO";
32
+ CognitoIdentityProvider["Google"] = "Google";
33
+ CognitoIdentityProvider["Facebook"] = "Facebook";
34
+ CognitoIdentityProvider["Amazon"] = "LoginWithAmazon";
35
+ CognitoIdentityProvider["Apple"] = "SignInWithApple";
36
+ })(CognitoIdentityProvider || (CognitoIdentityProvider = {}));
37
+ /**
38
+ * Lightweight AWS Cogito client without any AWS SDK dependencies.
39
+ */
40
+ export class CognitoClient {
41
+ constructor({ userPoolId, userPoolClientId, endpoint, sessionStorage, oAuth2: oAuth }) {
42
+ const [cognitoPoolRegion, cognitoPoolName] = userPoolId.split('_');
43
+ this.cognitoEndpoint = (endpoint || `https://cognito-idp.${cognitoPoolRegion}.amazonaws.com`).replace(/\/$/, '');
44
+ this.cognitoPoolName = cognitoPoolName;
45
+ this.userPoolClientId = userPoolClientId;
46
+ this.sessionStorage = sessionStorage;
47
+ this.oAuth = oAuth;
48
+ }
49
+ static getDecodedTokenFromSession(session) {
50
+ const { payload: idToken } = decodeJwt(session.idToken);
51
+ const { payload: accessToken } = decodeJwt(session.accessToken);
52
+ return {
53
+ idToken,
54
+ accessToken,
55
+ };
56
+ }
57
+ async cognitoRequest(body, serviceTarget) {
58
+ const respondToAuthChallenge = await fetch(this.cognitoEndpoint, {
59
+ headers: {
60
+ 'x-amz-target': `AWSCognitoIdentityProviderService.${serviceTarget}`,
61
+ 'content-type': 'application/x-amz-json-1.1',
62
+ },
63
+ method: 'POST',
64
+ body: JSON.stringify(body),
65
+ });
66
+ if (respondToAuthChallenge.status < 200 || respondToAuthChallenge.status > 299) {
67
+ const errorMessage = (await respondToAuthChallenge.json());
68
+ throw getAuthError(errorMessage);
69
+ }
70
+ return respondToAuthChallenge.json();
71
+ }
72
+ static authResultToSession(authenticationResult) {
73
+ return {
74
+ accessToken: authenticationResult.AccessToken,
75
+ idToken: authenticationResult.IdToken,
76
+ expiresIn: addSeconds(new Date(), authenticationResult.ExpiresIn).getTime(),
77
+ refreshToken: authenticationResult.RefreshToken,
78
+ };
79
+ }
80
+ /**
81
+ *
82
+ * Performs user authentication with username and password through ALLOW_USER_SRP_AUTH .
83
+ * @see https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html for more details
84
+ *
85
+ * @param username Username
86
+ * @param password Password
87
+ * @throws {AuthException}
88
+ */
89
+ async authenticateUserSrp(username, password) {
90
+ const smallA = generateSmallA();
91
+ const A = generateA(smallA);
92
+ const initiateAuthPayload = {
93
+ AuthFlow: 'USER_SRP_AUTH',
94
+ ClientId: this.userPoolClientId,
95
+ AuthParameters: {
96
+ USERNAME: username,
97
+ SRP_A: A.toString(16),
98
+ },
99
+ ClientMetadata: {},
100
+ };
101
+ const challenge = (await this.cognitoRequest(initiateAuthPayload, CognitoServiceTarget.InitiateAuth));
102
+ const B = new BigInteger(challenge.ChallengeParameters.SRP_B, 16);
103
+ const salt = new BigInteger(challenge.ChallengeParameters.SALT, 16);
104
+ const U = calculateU(A, B);
105
+ const hkdf = getPasswordAuthenticationKey(this.cognitoPoolName, challenge.ChallengeParameters.USER_ID_FOR_SRP, password, B, U, smallA, salt);
106
+ const { signature, timeStamp } = calculateSignature(this.cognitoPoolName, challenge.ChallengeParameters.USER_ID_FOR_SRP, challenge.ChallengeParameters.SECRET_BLOCK, hkdf);
107
+ const respondToAuthChallengePayload = {
108
+ ChallengeName: 'PASSWORD_VERIFIER',
109
+ ClientId: this.userPoolClientId,
110
+ ChallengeResponses: {
111
+ PASSWORD_CLAIM_SECRET_BLOCK: challenge.ChallengeParameters.SECRET_BLOCK,
112
+ PASSWORD_CLAIM_SIGNATURE: signature,
113
+ USERNAME: challenge.ChallengeParameters.USER_ID_FOR_SRP,
114
+ TIMESTAMP: timeStamp,
115
+ },
116
+ ClientMetadata: {},
117
+ };
118
+ const { AuthenticationResult } = await this.cognitoRequest(respondToAuthChallengePayload, CognitoServiceTarget.RespondToAuthChallenge);
119
+ const session = CognitoClient.authResultToSession(AuthenticationResult);
120
+ this.sessionStorage.setSession(session);
121
+ return session;
122
+ }
123
+ /**
124
+ *
125
+ * Performs user authentication with username and password through USER_PASSWORD_AUTH .
126
+ * @see https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-authentication-flow.html for more details
127
+ *
128
+ * @param username Username
129
+ * @param password Password
130
+ * @throws {AuthException}
131
+ */
132
+ async authenticateUser(username, password) {
133
+ const initiateAuthPayload = {
134
+ AuthFlow: 'USER_PASSWORD_AUTH',
135
+ ClientId: this.userPoolClientId,
136
+ AuthParameters: {
137
+ USERNAME: username,
138
+ PASSWORD: password,
139
+ },
140
+ ClientMetadata: {},
141
+ };
142
+ const { AuthenticationResult } = (await this.cognitoRequest(initiateAuthPayload, CognitoServiceTarget.InitiateAuth));
143
+ const session = CognitoClient.authResultToSession(AuthenticationResult);
144
+ this.sessionStorage.setSession(session);
145
+ return session;
146
+ }
147
+ async refreshSession(session) {
148
+ const refreshTokenPayload = {
149
+ AuthFlow: 'REFRESH_TOKEN_AUTH',
150
+ ClientId: this.userPoolClientId,
151
+ AuthParameters: {
152
+ REFRESH_TOKEN: session.refreshToken,
153
+ },
154
+ ClientMetadata: {},
155
+ };
156
+ const { AuthenticationResult } = (await this.cognitoRequest(refreshTokenPayload, CognitoServiceTarget.InitiateAuth));
157
+ const newSession = CognitoClient.authResultToSession({
158
+ ...AuthenticationResult,
159
+ RefreshToken: session.refreshToken,
160
+ });
161
+ this.sessionStorage.setSession(newSession);
162
+ return newSession;
163
+ }
164
+ /**
165
+ * Returns the current auth session.
166
+ * The auth session is only defined when we previously had a successful user authentication.
167
+ * This function will also take care to refresh the session with the refresh token in case
168
+ * the current session has expired.
169
+ *
170
+ * @throws {AuthException}
171
+ */
172
+ async getSession() {
173
+ const session = this.sessionStorage.getSession();
174
+ if (session) {
175
+ if (new Date().getTime() >= session.expiresIn) {
176
+ return this.refreshSession(session);
177
+ }
178
+ }
179
+ return session;
180
+ }
181
+ /**
182
+ *
183
+ * @param username Username
184
+ * @param password Password
185
+ *
186
+ * @throws {AuthException}
187
+ */
188
+ async signUp(username, password, userAttributes) {
189
+ const signUpPayload = {
190
+ ClientId: this.userPoolClientId,
191
+ Username: username,
192
+ Password: password,
193
+ UserAttributes: userAttributes,
194
+ };
195
+ const data = await this.cognitoRequest(signUpPayload, CognitoServiceTarget.SignUp);
196
+ return {
197
+ id: data.UserSub,
198
+ confirmed: data.UserConfirmed,
199
+ };
200
+ }
201
+ /**
202
+ * Confirms the user registration via verification code.
203
+ *
204
+ * @param username Username
205
+ * @param code Confirmation code the user gets through the registration E-Mail
206
+ *
207
+ * @throws {AuthException}
208
+ */
209
+ async confirmSignUp(username, code) {
210
+ const confirmSignUpPayload = {
211
+ ClientId: this.userPoolClientId,
212
+ ConfirmationCode: code,
213
+ Username: username,
214
+ };
215
+ const result = await this.cognitoRequest(confirmSignUpPayload, CognitoServiceTarget.ConfirmSignUp);
216
+ }
217
+ /**
218
+ *
219
+ * @param currentPassword Current user password.
220
+ * @param newPassword New user password.
221
+ *
222
+ * @throws {AuthException}
223
+ */
224
+ async changePassword(currentPassword, newPassword) {
225
+ const session = await this.getSession();
226
+ if (session === undefined) {
227
+ throw new AuthException('User must be authenticated', AuthError.UserNotAuthenticated);
228
+ }
229
+ const changePasswordPayload = {
230
+ PreviousPassword: currentPassword,
231
+ ProposedPassword: newPassword,
232
+ AccessToken: session.accessToken,
233
+ };
234
+ const result = await this.cognitoRequest(changePasswordPayload, CognitoServiceTarget.ChangePassword);
235
+ }
236
+ async updateUserAttributes(userAttributes) {
237
+ const session = await this.getSession();
238
+ if (session === undefined) {
239
+ throw new AuthException('User must be authenticated', AuthError.UserNotAuthenticated);
240
+ }
241
+ const updateUserAttributesPayload = {
242
+ UserAttributes: userAttributes,
243
+ AccessToken: session.accessToken,
244
+ };
245
+ const result = await this.cognitoRequest(updateUserAttributesPayload, CognitoServiceTarget.UpdateUserAttributes);
246
+ }
247
+ async verifyUserAttribute(attributeName, code) {
248
+ const session = await this.getSession();
249
+ if (session === undefined) {
250
+ throw new AuthException('User must be authenticated', AuthError.UserNotAuthenticated);
251
+ }
252
+ const verifyUserAttributePayload = {
253
+ AttributeName: attributeName,
254
+ Code: code,
255
+ AccessToken: session.accessToken,
256
+ };
257
+ const result = await this.cognitoRequest(verifyUserAttributePayload, CognitoServiceTarget.VerifyUserAttribute);
258
+ }
259
+ /**
260
+ * Sign out the user and remove the current user session.
261
+ *
262
+ * @throws {AuthException}
263
+ */
264
+ async signOut() {
265
+ const session = await this.getSession();
266
+ if (session === undefined) {
267
+ throw new AuthException('User must be authenticated', AuthError.UserNotAuthenticated);
268
+ }
269
+ const revokeTokenPayload = {
270
+ Token: session.refreshToken,
271
+ ClientId: this.userPoolClientId,
272
+ };
273
+ this.sessionStorage.setSession(undefined);
274
+ await this.cognitoRequest(revokeTokenPayload, CognitoServiceTarget.RevokeToken);
275
+ }
276
+ /**
277
+ * Request forgot password.
278
+ * @param username Username
279
+ *
280
+ * @throws {AuthException}
281
+ */
282
+ async forgotPassword(username) {
283
+ const forgotPasswordPayload = {
284
+ ClientId: this.userPoolClientId,
285
+ Username: username,
286
+ };
287
+ await this.cognitoRequest(forgotPasswordPayload, CognitoServiceTarget.ForgotPassword);
288
+ }
289
+ /**
290
+ * Confirms the new password via the given code send via cognito triggered by @see forgotPassword .
291
+ *
292
+ * @param username Username
293
+ * @param newPassword New password
294
+ * @param confirmationCode Confirmation code which the user got through E-mail
295
+ *
296
+ * @throws {AuthException}
297
+ */
298
+ async confirmForgotPassword(username, newPassword, confirmationCode) {
299
+ const confirmForgotPasswordPayload = {
300
+ ClientId: this.userPoolClientId,
301
+ Username: username,
302
+ ConfirmationCode: confirmationCode,
303
+ Password: newPassword,
304
+ };
305
+ await this.cognitoRequest(confirmForgotPasswordPayload, CognitoServiceTarget.ConfirmForgotPassword);
306
+ }
307
+ /**
308
+ * Triggers cognito to resend the confirmation code
309
+ * @param username Username
310
+ */
311
+ async resendConfirmationCode(username) {
312
+ const resendConfirmationCodePayLoad = {
313
+ ClientId: this.userPoolClientId,
314
+ Username: username,
315
+ };
316
+ await this.cognitoRequest(resendConfirmationCodePayLoad, CognitoServiceTarget.ResendConfirmationCode);
317
+ }
318
+ /**
319
+ * Returns a link to Cognito`s Hosted UI for OAuth2 authentication.
320
+ * This method works in conjunction with @see handleCodeFlow .
321
+ *
322
+ * @param identityProvider When provided, this will generate a link which
323
+ * tells Cognito`s Hosted UI to redirect to the given federated identity provider.
324
+ *
325
+ * @throws {Error}
326
+ */
327
+ generateOAuthSignInUrl(identityProvider) {
328
+ if (this.oAuth === undefined) {
329
+ throw Error('You have to define oAuth options to use generateFederatedSignUrl');
330
+ }
331
+ const state = randomBytes(32).toString('hex');
332
+ const pkce = randomBytes(128).toString('hex');
333
+ const code_challenge = Buffer.from(sha256().update(pkce).digest())
334
+ .toString('base64')
335
+ .replace(/\+/g, '-')
336
+ .replace(/\//g, '_')
337
+ .replace(/=+$/, '');
338
+ const queryParams = new URLSearchParams();
339
+ queryParams.append('redirect_uri', this.oAuth.redirectUrl);
340
+ queryParams.append('response_type', this.oAuth.responseType);
341
+ queryParams.append('client_id', this.userPoolClientId);
342
+ identityProvider && queryParams.append('identity_provider', identityProvider);
343
+ queryParams.append('scope', this.oAuth.scopes.join(' '));
344
+ queryParams.append('state', state);
345
+ queryParams.append('code_challenge', code_challenge);
346
+ queryParams.append('code_challenge_method', 'S256');
347
+ this.sessionStorage.setOauthVerificationParams({
348
+ state,
349
+ pkce,
350
+ });
351
+ return `${this.oAuth.cognitoDomain}/oauth2/authorize?${queryParams.toString()}`;
352
+ }
353
+ /**
354
+ *
355
+ * Handles Cognito`s OAuth2 code flow after redirection from Cognito`s Hosted UI.
356
+ * The method call assumes that @see generateOAuthSignInUrl was used to
357
+ * generated the link to the Hosted UI.
358
+ *
359
+ * @param returnUrl The full return URL from redirection after a successful OAuth2
360
+ * authentication.
361
+ *
362
+ * @throws {Error}
363
+ */
364
+ async handleCodeFlow(returnUrl) {
365
+ if (this.oAuth === undefined) {
366
+ throw Error('You have to define oAuth options to use handleCodeFlow');
367
+ }
368
+ const url = new URL(returnUrl);
369
+ const code = url.searchParams.get('code');
370
+ const state = url.searchParams.get('state');
371
+ if (code === null || state === null) {
372
+ throw Error('code or state parameter is missing from return url.');
373
+ }
374
+ const oAuthVerificationParams = this.sessionStorage.getOauthVerificationParams();
375
+ if (oAuthVerificationParams === undefined) {
376
+ throw new Error('OAuth verification parameters are missing, did you forgot to call generateOAuthSignInUrl ?');
377
+ }
378
+ if (oAuthVerificationParams.state !== state) {
379
+ throw new Error('state parameter does not match with previous value generated by previous call of generateOAuthSignInUrl .');
380
+ }
381
+ const urlParams = new URLSearchParams();
382
+ urlParams.append('grant_type', 'authorization_code');
383
+ urlParams.append('code', code);
384
+ urlParams.append('client_id', this.userPoolClientId);
385
+ urlParams.append('redirect_uri', this.oAuth.redirectUrl);
386
+ urlParams.append('code_verifier', oAuthVerificationParams.pkce);
387
+ const tokenEndpoint = `${this.oAuth.cognitoDomain}/oauth2/token`;
388
+ const response = await fetch(tokenEndpoint, {
389
+ method: 'POST',
390
+ headers: {
391
+ 'Content-Type': 'application/x-www-form-urlencoded',
392
+ },
393
+ body: urlParams.toString(),
394
+ });
395
+ const { access_token, refresh_token, id_token, expires_in, token_type, error } = await response.json();
396
+ if (error) {
397
+ throw new Error(error);
398
+ }
399
+ const session = CognitoClient.authResultToSession({
400
+ AccessToken: access_token,
401
+ RefreshToken: refresh_token,
402
+ IdToken: id_token,
403
+ ExpiresIn: expires_in,
404
+ TokenType: token_type,
405
+ });
406
+ this.sessionStorage.setSession(session);
407
+ return session;
408
+ }
409
+ }
@@ -0,0 +1 @@
1
+ import "isomorphic-fetch";