@aws-amplify/auth 5.6.3 → 5.6.4-unstable.bdaee91.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,3270 +0,0 @@
1
- // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
- // SPDX-License-Identifier: Apache-2.0
3
-
4
- import {
5
- AuthOptions,
6
- FederatedResponse,
7
- SignUpParams,
8
- FederatedUser,
9
- ConfirmSignUpOptions,
10
- SignOutOpts,
11
- CurrentUserOpts,
12
- GetPreferredMFAOpts,
13
- SignInOpts,
14
- isUsernamePasswordOpts,
15
- isCognitoHostedOpts,
16
- isFederatedSignInOptions,
17
- isFederatedSignInOptionsCustom,
18
- hasCustomState,
19
- FederatedSignInOptionsCustom,
20
- LegacyProvider,
21
- FederatedSignInOptions,
22
- AwsCognitoOAuthOpts,
23
- ClientMetaData,
24
- } from '../types';
25
-
26
- import {
27
- Amplify,
28
- AuthAction,
29
- ConsoleLogger as Logger,
30
- Credentials,
31
- CustomUserAgentDetails,
32
- getAmplifyUserAgent,
33
- Hub,
34
- StorageHelper,
35
- ICredentials,
36
- Platform,
37
- browserOrNode,
38
- parseAWSExports,
39
- UniversalStorage,
40
- urlSafeDecode,
41
- HubCallback,
42
- } from '@aws-amplify/core';
43
- import {
44
- CookieStorage,
45
- AuthenticationDetails,
46
- ICognitoUserPoolData,
47
- ICognitoUserData,
48
- ISignUpResult,
49
- CognitoUser,
50
- MFAOption,
51
- CognitoUserSession,
52
- IAuthenticationCallback,
53
- ICognitoUserAttributeData,
54
- CognitoUserAttribute,
55
- CognitoIdToken,
56
- CognitoRefreshToken,
57
- CognitoAccessToken,
58
- NodeCallback,
59
- CodeDeliveryDetails,
60
- } from 'amazon-cognito-identity-js';
61
- import {
62
- addAuthCategoryToCognitoUserAgent,
63
- addFrameworkToCognitoUserAgent,
64
- InternalCognitoUser,
65
- InternalCognitoUserPool,
66
- } from 'amazon-cognito-identity-js/internals';
67
-
68
- import { parse } from 'url';
69
- import OAuth from '../OAuth/OAuth';
70
- import { default as urlListener } from '../urlListener';
71
- import { AuthError, NoUserPoolError } from '../Errors';
72
- import {
73
- AuthErrorTypes,
74
- AutoSignInOptions,
75
- CognitoHostedUIIdentityProvider,
76
- IAuthDevice,
77
- } from '../types/Auth';
78
- import { getAuthUserAgentDetails, getAuthUserAgentValue } from '../utils';
79
-
80
- const logger = new Logger('AuthClass');
81
- const USER_ADMIN_SCOPE = 'aws.cognito.signin.user.admin';
82
-
83
- // 10 sec, following this guide https://www.nngroup.com/articles/response-times-3-important-limits/
84
- const OAUTH_FLOW_MS_TIMEOUT = 10 * 1000;
85
-
86
- const AMPLIFY_SYMBOL = (
87
- typeof Symbol !== 'undefined' && typeof Symbol.for === 'function'
88
- ? Symbol.for('amplify_default')
89
- : '@@amplify_default'
90
- ) as Symbol;
91
-
92
- const dispatchAuthEvent = (event: string, data: any, message: string) => {
93
- Hub.dispatch('auth', { event, data, message }, 'Auth', AMPLIFY_SYMBOL);
94
- };
95
-
96
- // Cognito Documentation for max device
97
- // tslint:disable-next-line:max-line-length
98
- // https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_ListDevices.html#API_ListDevices_RequestSyntax
99
- const MAX_DEVICES = 60;
100
-
101
- const MAX_AUTOSIGNIN_POLLING_MS = 3 * 60 * 1000;
102
-
103
- /**
104
- * Provide authentication steps
105
- */
106
- export class InternalAuthClass {
107
- private _config: AuthOptions;
108
- private userPool: InternalCognitoUserPool = null;
109
- private user: any = null;
110
- private _oAuthHandler: OAuth;
111
- private _storage;
112
- private _storageSync;
113
- private oAuthFlowInProgress: boolean = false;
114
- private pendingSignIn: ReturnType<
115
- InternalAuthClass['signInWithPassword']
116
- > | null;
117
- private autoSignInInitiated: boolean = false;
118
- private inflightSessionPromise: Promise<CognitoUserSession> | null = null;
119
- private inflightSessionPromiseCounter: number = 0;
120
- Credentials = Credentials;
121
-
122
- /**
123
- * Initialize Auth with AWS configurations
124
- * @param {Object} config - Configuration of the Auth
125
- */
126
- constructor(config: AuthOptions) {
127
- this.configure(config);
128
- this.currentCredentials = this.currentCredentials.bind(this);
129
- this.currentUserCredentials = this.currentUserCredentials.bind(this);
130
-
131
- Hub.listen('auth', ({ payload }) => {
132
- const { event } = payload;
133
- switch (event) {
134
- case 'verify':
135
- case 'signIn':
136
- this._storage.setItem('amplify-signin-with-hostedUI', 'false');
137
- break;
138
- case 'signOut':
139
- this._storage.removeItem('amplify-signin-with-hostedUI');
140
- break;
141
- case 'cognitoHostedUI':
142
- this._storage.setItem('amplify-signin-with-hostedUI', 'true');
143
- break;
144
- }
145
- });
146
-
147
- addAuthCategoryToCognitoUserAgent();
148
- addFrameworkToCognitoUserAgent(Platform.framework);
149
- Platform.observeFrameworkChanges(() => {
150
- addFrameworkToCognitoUserAgent(Platform.framework);
151
- });
152
- }
153
-
154
- public getModuleName() {
155
- return 'InternalAuth';
156
- }
157
-
158
- configure(config?) {
159
- if (!config) return this._config || {};
160
- logger.debug('configure Auth');
161
- const conf = Object.assign(
162
- {},
163
- this._config,
164
- parseAWSExports(config).Auth,
165
- config
166
- );
167
- this._config = conf;
168
- const {
169
- userPoolId,
170
- userPoolWebClientId,
171
- cookieStorage,
172
- oauth,
173
- region,
174
- identityPoolId,
175
- mandatorySignIn,
176
- refreshHandlers,
177
- identityPoolRegion,
178
- clientMetadata,
179
- endpoint,
180
- storage,
181
- } = this._config;
182
-
183
- if (!storage) {
184
- // backward compatability
185
- if (cookieStorage) this._storage = new CookieStorage(cookieStorage);
186
- else {
187
- this._storage = config.ssr
188
- ? new UniversalStorage()
189
- : new StorageHelper().getStorage();
190
- }
191
- } else {
192
- if (!this._isValidAuthStorage(storage)) {
193
- logger.error('The storage in the Auth config is not valid!');
194
- throw new Error('Empty storage object');
195
- }
196
- this._storage = storage;
197
- }
198
-
199
- this._storageSync = Promise.resolve();
200
- if (typeof this._storage['sync'] === 'function') {
201
- this._storageSync = this._storage['sync']();
202
- }
203
-
204
- if (userPoolId) {
205
- const userPoolData: ICognitoUserPoolData = {
206
- UserPoolId: userPoolId,
207
- ClientId: userPoolWebClientId,
208
- endpoint,
209
- };
210
- userPoolData.Storage = this._storage;
211
-
212
- this.userPool = new InternalCognitoUserPool(
213
- userPoolData,
214
- this.wrapRefreshSessionCallback
215
- );
216
- }
217
-
218
- this.Credentials.configure({
219
- mandatorySignIn,
220
- region,
221
- userPoolId,
222
- identityPoolId,
223
- refreshHandlers,
224
- storage: this._storage,
225
- identityPoolRegion,
226
- });
227
-
228
- // initialize cognitoauth client if hosted ui options provided
229
- // to keep backward compatibility:
230
- const cognitoHostedUIConfig = oauth
231
- ? isCognitoHostedOpts(this._config.oauth)
232
- ? oauth
233
- : (<any>oauth).awsCognito
234
- : undefined;
235
-
236
- if (cognitoHostedUIConfig) {
237
- const cognitoAuthParams = Object.assign(
238
- {
239
- cognitoClientId: userPoolWebClientId,
240
- UserPoolId: userPoolId,
241
- domain: cognitoHostedUIConfig['domain'],
242
- scopes: cognitoHostedUIConfig['scope'],
243
- redirectSignIn: cognitoHostedUIConfig['redirectSignIn'],
244
- redirectSignOut: cognitoHostedUIConfig['redirectSignOut'],
245
- responseType: cognitoHostedUIConfig['responseType'],
246
- Storage: this._storage,
247
- urlOpener: cognitoHostedUIConfig['urlOpener'],
248
- clientMetadata,
249
- },
250
- cognitoHostedUIConfig['options']
251
- );
252
-
253
- this._oAuthHandler = new OAuth({
254
- scopes: cognitoAuthParams.scopes,
255
- config: cognitoAuthParams,
256
- cognitoClientId: cognitoAuthParams.cognitoClientId,
257
- });
258
-
259
- // **NOTE** - Remove this in a future major release as it is a breaking change
260
- // Prevents _handleAuthResponse from being called multiple times in Expo
261
- // See https://github.com/aws-amplify/amplify-js/issues/4388
262
- const usedResponseUrls = {};
263
- // Only register urlListener once
264
- if (this.getModuleName() === 'Auth') {
265
- urlListener(({ url }) => {
266
- if (usedResponseUrls[url]) {
267
- return;
268
- }
269
-
270
- usedResponseUrls[url] = true;
271
- this._handleAuthResponse(url);
272
- });
273
- }
274
- }
275
-
276
- dispatchAuthEvent(
277
- 'configured',
278
- null,
279
- `The Auth category has been configured successfully`
280
- );
281
-
282
- if (
283
- !this.autoSignInInitiated &&
284
- typeof this._storage['getItem'] === 'function'
285
- ) {
286
- const pollingInitiated = this.isTrueStorageValue(
287
- 'amplify-polling-started'
288
- );
289
- if (pollingInitiated) {
290
- dispatchAuthEvent(
291
- 'autoSignIn_failure',
292
- null,
293
- AuthErrorTypes.AutoSignInError
294
- );
295
- this._storage.removeItem('amplify-auto-sign-in');
296
- }
297
- this._storage.removeItem('amplify-polling-started');
298
- }
299
- return this._config;
300
- }
301
-
302
- wrapRefreshSessionCallback = (callback: NodeCallback.Any) => {
303
- const wrapped: NodeCallback.Any = (error, data) => {
304
- if (data) {
305
- dispatchAuthEvent('tokenRefresh', undefined, `New token retrieved`);
306
- } else {
307
- dispatchAuthEvent(
308
- 'tokenRefresh_failure',
309
- error,
310
- `Failed to retrieve new token`
311
- );
312
- }
313
- return callback(error, data);
314
- };
315
- return wrapped;
316
- } // prettier-ignore
317
-
318
- /**
319
- * Sign up with username, password and other attributes like phone, email
320
- * @param {String | object} params - The user attributes used for signin
321
- * @param {String[]} restOfAttrs - for the backward compatability
322
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
323
- * @return - A promise resolves callback data if success
324
- */
325
- public signUp(
326
- params: string | SignUpParams,
327
- ...restOfAttrs: any
328
- ): Promise<ISignUpResult>;
329
- public signUp(
330
- params: string | SignUpParams,
331
- restOfAttrs?: string[],
332
- customUserAgentDetails?: CustomUserAgentDetails
333
- ): Promise<ISignUpResult> {
334
- if (!this.userPool) {
335
- return this.rejectNoUserPool();
336
- }
337
-
338
- let username: string = null;
339
- let password: string = null;
340
- const attributes: CognitoUserAttribute[] = [];
341
- let validationData: CognitoUserAttribute[] = null;
342
- let clientMetadata;
343
- let autoSignIn: AutoSignInOptions = { enabled: false };
344
- let autoSignInValidationData = {};
345
- let autoSignInClientMetaData: ClientMetaData = {};
346
-
347
- if (params && typeof params === 'string') {
348
- username = params;
349
- password = restOfAttrs ? restOfAttrs[0] : null;
350
- const email: string = restOfAttrs ? restOfAttrs[1] : null;
351
- const phone_number: string = restOfAttrs ? restOfAttrs[2] : null;
352
-
353
- if (email)
354
- attributes.push(
355
- new CognitoUserAttribute({ Name: 'email', Value: email })
356
- );
357
-
358
- if (phone_number)
359
- attributes.push(
360
- new CognitoUserAttribute({
361
- Name: 'phone_number',
362
- Value: phone_number,
363
- })
364
- );
365
- } else if (params && typeof params === 'object') {
366
- username = params['username'];
367
- password = params['password'];
368
-
369
- if (params && params.clientMetadata) {
370
- clientMetadata = params.clientMetadata;
371
- } else if (this._config.clientMetadata) {
372
- clientMetadata = this._config.clientMetadata;
373
- }
374
-
375
- const attrs = params['attributes'];
376
- if (attrs) {
377
- Object.keys(attrs).map(key => {
378
- attributes.push(
379
- new CognitoUserAttribute({ Name: key, Value: attrs[key] })
380
- );
381
- });
382
- }
383
-
384
- const validationDataObject = params['validationData'];
385
- if (validationDataObject) {
386
- validationData = [];
387
- Object.keys(validationDataObject).map(key => {
388
- validationData.push(
389
- new CognitoUserAttribute({
390
- Name: key,
391
- Value: validationDataObject[key],
392
- })
393
- );
394
- });
395
- }
396
-
397
- autoSignIn = params.autoSignIn ?? { enabled: false };
398
- if (autoSignIn.enabled) {
399
- this._storage.setItem('amplify-auto-sign-in', 'true');
400
- autoSignInValidationData = autoSignIn.validationData ?? {};
401
- autoSignInClientMetaData = autoSignIn.clientMetaData ?? {};
402
- }
403
- } else {
404
- return this.rejectAuthError(AuthErrorTypes.SignUpError);
405
- }
406
-
407
- if (!username) {
408
- return this.rejectAuthError(AuthErrorTypes.EmptyUsername);
409
- }
410
- if (!password) {
411
- return this.rejectAuthError(AuthErrorTypes.EmptyPassword);
412
- }
413
-
414
- logger.debug('signUp attrs:', attributes);
415
- logger.debug('signUp validation data:', validationData);
416
-
417
- return new Promise((resolve, reject) => {
418
- const userAgentDetails = getAuthUserAgentDetails(
419
- AuthAction.SignUp,
420
- customUserAgentDetails
421
- );
422
- this.userPool.signUp(
423
- username,
424
- password,
425
- attributes,
426
- validationData,
427
- (err, data) => {
428
- if (err) {
429
- dispatchAuthEvent(
430
- 'signUp_failure',
431
- err,
432
- `${username} failed to signup`
433
- );
434
- reject(err);
435
- } else {
436
- dispatchAuthEvent(
437
- 'signUp',
438
- data,
439
- `${username} has signed up successfully`
440
- );
441
- if (autoSignIn.enabled) {
442
- this.handleAutoSignIn(
443
- username,
444
- password,
445
- autoSignInValidationData,
446
- autoSignInClientMetaData,
447
- data,
448
- userAgentDetails
449
- );
450
- }
451
- resolve(data);
452
- }
453
- },
454
- clientMetadata,
455
- getAmplifyUserAgent(userAgentDetails)
456
- );
457
- });
458
- }
459
-
460
- private handleAutoSignIn(
461
- username: string,
462
- password: string,
463
- validationData: {},
464
- clientMetadata: any,
465
- data: any,
466
- customUserAgentDetails: CustomUserAgentDetails
467
- ) {
468
- this.autoSignInInitiated = true;
469
- const authDetails = new AuthenticationDetails({
470
- Username: username,
471
- Password: password,
472
- ValidationData: validationData,
473
- ClientMetadata: clientMetadata,
474
- });
475
- if (data.userConfirmed) {
476
- this.signInAfterUserConfirmed(authDetails, customUserAgentDetails);
477
- } else if (this._config.signUpVerificationMethod === 'link') {
478
- this.handleLinkAutoSignIn(authDetails, customUserAgentDetails);
479
- } else {
480
- this.handleCodeAutoSignIn(authDetails, customUserAgentDetails);
481
- }
482
- }
483
-
484
- private handleCodeAutoSignIn(
485
- authDetails: AuthenticationDetails,
486
- customUserAgentDetails: CustomUserAgentDetails
487
- ) {
488
- const listenEvent = ({ payload }) => {
489
- if (payload.event === 'confirmSignUp') {
490
- this.signInAfterUserConfirmed(
491
- authDetails,
492
- customUserAgentDetails,
493
- listenEvent
494
- );
495
- }
496
- };
497
- Hub.listen('auth', listenEvent);
498
- }
499
-
500
- private handleLinkAutoSignIn(
501
- authDetails: AuthenticationDetails,
502
- customUserAgentDetails: CustomUserAgentDetails
503
- ) {
504
- this._storage.setItem('amplify-polling-started', 'true');
505
- const start = Date.now();
506
- const autoSignInPollingIntervalId = setInterval(() => {
507
- if (Date.now() - start > MAX_AUTOSIGNIN_POLLING_MS) {
508
- clearInterval(autoSignInPollingIntervalId);
509
- dispatchAuthEvent(
510
- 'autoSignIn_failure',
511
- null,
512
- 'Please confirm your account and use your credentials to sign in.'
513
- );
514
- this._storage.removeItem('amplify-auto-sign-in');
515
- } else {
516
- this.signInAfterUserConfirmed(
517
- authDetails,
518
- customUserAgentDetails,
519
- undefined,
520
- autoSignInPollingIntervalId
521
- );
522
- }
523
- }, 5000);
524
- }
525
-
526
- private async signInAfterUserConfirmed(
527
- authDetails: AuthenticationDetails,
528
- customUserAgentDetails: CustomUserAgentDetails,
529
- listenEvent?: HubCallback,
530
- autoSignInPollingIntervalId?: ReturnType<typeof setInterval>
531
- ) {
532
- const user = this.createCognitoUser(authDetails.getUsername());
533
- try {
534
- await user.authenticateUser(
535
- authDetails,
536
- this.authCallbacks(
537
- user,
538
- value => {
539
- dispatchAuthEvent(
540
- 'autoSignIn',
541
- value,
542
- `${authDetails.getUsername()} has signed in successfully`
543
- );
544
- if (listenEvent) {
545
- Hub.remove('auth', listenEvent);
546
- }
547
- if (autoSignInPollingIntervalId) {
548
- clearInterval(autoSignInPollingIntervalId);
549
- this._storage.removeItem('amplify-polling-started');
550
- }
551
- this._storage.removeItem('amplify-auto-sign-in');
552
- },
553
- error => {
554
- logger.error(error);
555
- this._storage.removeItem('amplify-auto-sign-in');
556
- },
557
- customUserAgentDetails
558
- ),
559
- getAmplifyUserAgent(customUserAgentDetails)
560
- );
561
- } catch (error) {
562
- logger.error(error);
563
- }
564
- }
565
-
566
- /**
567
- * Send the verification code to confirm sign up
568
- * @param {String} username - The username to be confirmed
569
- * @param {String} code - The verification code
570
- * @param {ConfirmSignUpOptions} options - other options for confirm signup
571
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
572
- * @return - A promise resolves callback data if success
573
- */
574
- public confirmSignUp(
575
- username: string,
576
- code: string,
577
- options?: ConfirmSignUpOptions,
578
- customUserAgentDetails?: CustomUserAgentDetails
579
- ): Promise<any> {
580
- if (!this.userPool) {
581
- return this.rejectNoUserPool();
582
- }
583
- if (!username) {
584
- return this.rejectAuthError(AuthErrorTypes.EmptyUsername);
585
- }
586
- if (!code) {
587
- return this.rejectAuthError(AuthErrorTypes.EmptyCode);
588
- }
589
-
590
- const user = this.createCognitoUser(username);
591
- const forceAliasCreation =
592
- options && typeof options.forceAliasCreation === 'boolean'
593
- ? options.forceAliasCreation
594
- : true;
595
-
596
- let clientMetadata;
597
- if (options && options.clientMetadata) {
598
- clientMetadata = options.clientMetadata;
599
- } else if (this._config.clientMetadata) {
600
- clientMetadata = this._config.clientMetadata;
601
- }
602
- return new Promise((resolve, reject) => {
603
- user.confirmRegistration(
604
- code,
605
- forceAliasCreation,
606
- (err, data) => {
607
- if (err) {
608
- reject(err);
609
- } else {
610
- dispatchAuthEvent(
611
- 'confirmSignUp',
612
- data,
613
- `${username} has been confirmed successfully`
614
- );
615
- const autoSignIn = this.isTrueStorageValue('amplify-auto-sign-in');
616
- if (autoSignIn && !this.autoSignInInitiated) {
617
- dispatchAuthEvent(
618
- 'autoSignIn_failure',
619
- null,
620
- AuthErrorTypes.AutoSignInError
621
- );
622
- this._storage.removeItem('amplify-auto-sign-in');
623
- }
624
- resolve(data);
625
- }
626
- },
627
- clientMetadata,
628
- getAuthUserAgentValue(AuthAction.ConfirmSignUp, customUserAgentDetails)
629
- );
630
- });
631
- }
632
-
633
- private isTrueStorageValue(value: string) {
634
- const item = this._storage.getItem(value);
635
- return item ? item === 'true' : false;
636
- }
637
-
638
- /**
639
- * Resend the verification code
640
- * @param {String} username - The username to be confirmed
641
- * @param {ClientMetadata} clientMetadata - Metadata to be passed to Cognito Lambda triggers
642
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
643
- * @return - A promise resolves code delivery details if successful
644
- */
645
- public resendSignUp(
646
- username: string,
647
- clientMetadata: ClientMetaData = this._config.clientMetadata,
648
- customUserAgentDetails?: CustomUserAgentDetails
649
- ): Promise<any> {
650
- if (!this.userPool) {
651
- return this.rejectNoUserPool();
652
- }
653
- if (!username) {
654
- return this.rejectAuthError(AuthErrorTypes.EmptyUsername);
655
- }
656
-
657
- const user = this.createCognitoUser(username);
658
- return new Promise((resolve, reject) => {
659
- user.resendConfirmationCode(
660
- (err, data) => {
661
- if (err) {
662
- reject(err);
663
- } else {
664
- resolve(data);
665
- }
666
- },
667
- clientMetadata,
668
- getAuthUserAgentValue(AuthAction.ResendSignUp, customUserAgentDetails)
669
- );
670
- });
671
- }
672
-
673
- /**
674
- * Sign in
675
- * @param {String | SignInOpts} usernameOrSignInOpts - The username to be signed in or the sign in options
676
- * @param {String} pw - The password of the username
677
- * @param {ClientMetaData} clientMetadata - Client metadata for custom workflows
678
- * @return - A promise resolves the CognitoUser
679
- */
680
- public signIn(
681
- usernameOrSignInOpts: string | SignInOpts,
682
- pw?: string,
683
- clientMetadata: ClientMetaData = this._config.clientMetadata,
684
- customUserAgentDetails?: CustomUserAgentDetails
685
- ): Promise<CognitoUser | any> {
686
- if (!this.userPool) {
687
- return this.rejectNoUserPool();
688
- }
689
-
690
- let username = null;
691
- let password = null;
692
- let validationData = {};
693
-
694
- // for backward compatibility
695
- if (typeof usernameOrSignInOpts === 'string') {
696
- username = usernameOrSignInOpts;
697
- password = pw;
698
- } else if (isUsernamePasswordOpts(usernameOrSignInOpts)) {
699
- if (typeof pw !== 'undefined') {
700
- logger.warn(
701
- 'The password should be defined under the first parameter object!'
702
- );
703
- }
704
- username = usernameOrSignInOpts.username;
705
- password = usernameOrSignInOpts.password;
706
- validationData = usernameOrSignInOpts.validationData;
707
- } else {
708
- return this.rejectAuthError(AuthErrorTypes.InvalidUsername);
709
- }
710
- if (!username) {
711
- return this.rejectAuthError(AuthErrorTypes.EmptyUsername);
712
- }
713
- const authDetails = new AuthenticationDetails({
714
- Username: username,
715
- Password: password,
716
- ValidationData: validationData,
717
- ClientMetadata: clientMetadata,
718
- });
719
- const userAgentDetails = getAuthUserAgentDetails(
720
- AuthAction.SignIn,
721
- customUserAgentDetails
722
- );
723
- if (password) {
724
- return this.signInWithPassword(authDetails, userAgentDetails);
725
- } else {
726
- return this.signInWithoutPassword(authDetails, userAgentDetails);
727
- }
728
- }
729
-
730
- /**
731
- * Return an object with the authentication callbacks
732
- * @param {InternalCognitoUser} user - the cognito user object
733
- * @param {} resolve - function called when resolving the current step
734
- * @param {} reject - function called when rejecting the current step
735
- * @return - an object with the callback methods for user authentication
736
- */
737
- private authCallbacks(
738
- user: InternalCognitoUser,
739
- resolve: (value?: InternalCognitoUser | any) => void,
740
- reject: (value?: any) => void,
741
- customUserAgentDetails: CustomUserAgentDetails
742
- ): IAuthenticationCallback {
743
- const that = this;
744
- return {
745
- onSuccess: async session => {
746
- logger.debug(session);
747
- delete user['challengeName'];
748
- delete user['challengeParam'];
749
- try {
750
- await this.Credentials.clear();
751
- const cred = await this.Credentials.set(session, 'session');
752
- logger.debug('succeed to get cognito credentials', cred);
753
- } catch (e) {
754
- logger.debug('cannot get cognito credentials', e);
755
- } finally {
756
- try {
757
- // In order to get user attributes and MFA methods
758
- // We need to trigger currentUserPoolUser again
759
- const currentUser = await this._currentUserPoolUser(
760
- undefined,
761
- customUserAgentDetails
762
- );
763
- that.user = currentUser;
764
- dispatchAuthEvent(
765
- 'signIn',
766
- currentUser,
767
- `A user ${user.getUsername()} has been signed in`
768
- );
769
- resolve(currentUser);
770
- } catch (e) {
771
- logger.error('Failed to get the signed in user', e);
772
- reject(e);
773
- }
774
- }
775
- },
776
- onFailure: err => {
777
- logger.debug('signIn failure', err);
778
- dispatchAuthEvent(
779
- 'signIn_failure',
780
- err,
781
- `${user.getUsername()} failed to signin`
782
- );
783
- reject(err);
784
- },
785
- customChallenge: challengeParam => {
786
- logger.debug('signIn custom challenge answer required');
787
- user['challengeName'] = 'CUSTOM_CHALLENGE';
788
- user['challengeParam'] = challengeParam;
789
- resolve(user);
790
- },
791
- mfaRequired: (challengeName, challengeParam) => {
792
- logger.debug('signIn MFA required');
793
- user['challengeName'] = challengeName;
794
- user['challengeParam'] = challengeParam;
795
- resolve(user);
796
- },
797
- mfaSetup: (challengeName, challengeParam) => {
798
- logger.debug('signIn mfa setup', challengeName);
799
- user['challengeName'] = challengeName;
800
- user['challengeParam'] = challengeParam;
801
- resolve(user);
802
- },
803
- newPasswordRequired: (userAttributes, requiredAttributes) => {
804
- logger.debug('signIn new password');
805
- user['challengeName'] = 'NEW_PASSWORD_REQUIRED';
806
- user['challengeParam'] = {
807
- userAttributes,
808
- requiredAttributes,
809
- };
810
- resolve(user);
811
- },
812
- totpRequired: (challengeName, challengeParam) => {
813
- logger.debug('signIn totpRequired');
814
- user['challengeName'] = challengeName;
815
- user['challengeParam'] = challengeParam;
816
- resolve(user);
817
- },
818
- selectMFAType: (challengeName, challengeParam) => {
819
- logger.debug('signIn selectMFAType', challengeName);
820
- user['challengeName'] = challengeName;
821
- user['challengeParam'] = challengeParam;
822
- resolve(user);
823
- },
824
- };
825
- }
826
-
827
- /**
828
- * Sign in with a password
829
- * @private
830
- * @param {AuthenticationDetails} authDetails - the user sign in data
831
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
832
- * @return - A promise resolves the CognitoUser object if success or mfa required
833
- */
834
- private signInWithPassword(
835
- authDetails: AuthenticationDetails,
836
- customUserAgentDetails: CustomUserAgentDetails
837
- ): Promise<InternalCognitoUser | any> {
838
- if (this.pendingSignIn) {
839
- throw new Error('Pending sign-in attempt already in progress');
840
- }
841
-
842
- const user = this.createCognitoUser(authDetails.getUsername());
843
-
844
- this.pendingSignIn = new Promise((resolve, reject) => {
845
- user.authenticateUser(
846
- authDetails,
847
- this.authCallbacks(
848
- user,
849
- value => {
850
- this.pendingSignIn = null;
851
- resolve(value);
852
- },
853
- error => {
854
- this.pendingSignIn = null;
855
- reject(error);
856
- },
857
- customUserAgentDetails
858
- ),
859
- getAmplifyUserAgent(customUserAgentDetails)
860
- );
861
- });
862
-
863
- return this.pendingSignIn;
864
- }
865
-
866
- /**
867
- * Sign in without a password
868
- * @private
869
- * @param {AuthenticationDetails} authDetails - the user sign in data
870
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
871
- * @return - A promise resolves the InternalCognitoUser object if success or mfa required
872
- */
873
- private signInWithoutPassword(
874
- authDetails: AuthenticationDetails,
875
- customUserAgentDetails: CustomUserAgentDetails
876
- ): Promise<InternalCognitoUser | any> {
877
- const user = this.createCognitoUser(authDetails.getUsername());
878
- user.setAuthenticationFlowType('CUSTOM_AUTH');
879
-
880
- return new Promise((resolve, reject) => {
881
- user.initiateAuth(
882
- authDetails,
883
- this.authCallbacks(user, resolve, reject, customUserAgentDetails),
884
- getAmplifyUserAgent(customUserAgentDetails)
885
- );
886
- });
887
- }
888
-
889
- /**
890
- * This was previously used by an authenticated user to get MFAOptions,
891
- * but no longer returns a meaningful response. Refer to the documentation for
892
- * how to setup and use MFA: https://docs.amplify.aws/lib/auth/mfa/q/platform/js
893
- * @deprecated
894
- * @param {CognitoUser} user - the current user
895
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
896
- * @return - A promise resolves the current preferred mfa option if success
897
- */
898
- public getMFAOptions(
899
- user: CognitoUser | any,
900
- customUserAgentDetails?: CustomUserAgentDetails
901
- ): Promise<MFAOption[]> {
902
- const internalUser: InternalCognitoUser | any = user;
903
-
904
- return new Promise((res, rej) => {
905
- internalUser.getMFAOptions((err, mfaOptions) => {
906
- if (err) {
907
- logger.debug('get MFA Options failed', err);
908
- rej(err);
909
- return;
910
- }
911
- logger.debug('get MFA options success', mfaOptions);
912
- res(mfaOptions);
913
- return;
914
- }, getAuthUserAgentValue(AuthAction.GetMFAOptions, customUserAgentDetails));
915
- });
916
- }
917
-
918
- /**
919
- * get preferred mfa method
920
- * @param {CognitoUser} user - the current cognito user
921
- * @param {GetPreferredMFAOpts} params - options for getting the current user preferred MFA
922
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
923
- */
924
- public getPreferredMFA(
925
- user: CognitoUser | any,
926
- params?: GetPreferredMFAOpts,
927
- customUserAgentDetails?: CustomUserAgentDetails
928
- ): Promise<string> {
929
- const internalUser: InternalCognitoUser | any = user;
930
- const that = this;
931
- return new Promise((res, rej) => {
932
- const clientMetadata = this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
933
-
934
- const bypassCache = params ? params.bypassCache : false;
935
- const userAgentValue = getAuthUserAgentValue(
936
- AuthAction.GetPreferredMFA,
937
- customUserAgentDetails
938
- );
939
- internalUser.getUserData(
940
- async (err, data) => {
941
- if (err) {
942
- logger.debug('getting preferred mfa failed', err);
943
- if (this.isSessionInvalid(err)) {
944
- try {
945
- await this.cleanUpInvalidSession(user, userAgentValue);
946
- } catch (cleanUpError) {
947
- rej(
948
- new Error(
949
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
950
- )
951
- );
952
- return;
953
- }
954
- }
955
- rej(err);
956
- return;
957
- }
958
-
959
- const mfaType = that._getMfaTypeFromUserData(data);
960
- if (!mfaType) {
961
- rej('invalid MFA Type');
962
- return;
963
- } else {
964
- res(mfaType);
965
- return;
966
- }
967
- },
968
- { bypassCache, clientMetadata },
969
- userAgentValue
970
- );
971
- });
972
- }
973
-
974
- private _getMfaTypeFromUserData(data) {
975
- let ret = null;
976
- const preferredMFA = data.PreferredMfaSetting;
977
- // if the user has used Auth.setPreferredMFA() to setup the mfa type
978
- // then the "PreferredMfaSetting" would exist in the response
979
- if (preferredMFA) {
980
- ret = preferredMFA;
981
- } else {
982
- // if mfaList exists but empty, then its noMFA
983
- const mfaList = data.UserMFASettingList;
984
- if (!mfaList) {
985
- // if SMS was enabled by using Auth.enableSMS(),
986
- // the response would contain MFAOptions
987
- // as for now Cognito only supports for SMS, so we will say it is 'SMS_MFA'
988
- // if it does not exist, then it should be NOMFA
989
- const MFAOptions = data.MFAOptions;
990
- if (MFAOptions) {
991
- ret = 'SMS_MFA';
992
- } else {
993
- ret = 'NOMFA';
994
- }
995
- } else if (mfaList.length === 0) {
996
- ret = 'NOMFA';
997
- } else {
998
- logger.debug('invalid case for getPreferredMFA', data);
999
- }
1000
- }
1001
- return ret;
1002
- }
1003
-
1004
- private _getUserData(
1005
- user: InternalCognitoUser,
1006
- params,
1007
- userAgentValue: string
1008
- ) {
1009
- return new Promise((res, rej) => {
1010
- user.getUserData(
1011
- async (err, data) => {
1012
- if (err) {
1013
- logger.debug('getting user data failed', err);
1014
- if (this.isSessionInvalid(err)) {
1015
- try {
1016
- await this.cleanUpInvalidSession(user, userAgentValue);
1017
- } catch (cleanUpError) {
1018
- rej(
1019
- new Error(
1020
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1021
- )
1022
- );
1023
- return;
1024
- }
1025
- }
1026
- rej(err);
1027
- return;
1028
- } else {
1029
- res(data);
1030
- }
1031
- },
1032
- params,
1033
- userAgentValue
1034
- );
1035
- });
1036
- }
1037
-
1038
- /**
1039
- * set preferred MFA method
1040
- * @param {CognitoUser} user - the current Cognito user
1041
- * @param {string} mfaMethod - preferred mfa method
1042
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1043
- * @return - A promise resolve if success
1044
- */
1045
- public async setPreferredMFA(
1046
- user: CognitoUser | any,
1047
- mfaMethod: 'TOTP' | 'SMS' | 'NOMFA' | 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA',
1048
- customUserAgentDetails?: CustomUserAgentDetails
1049
- ): Promise<string> {
1050
- const internalUser: InternalCognitoUser | any = user;
1051
- const userAgentValue = getAuthUserAgentValue(
1052
- AuthAction.SetPreferredMFA,
1053
- customUserAgentDetails
1054
- );
1055
- const clientMetadata = this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
1056
-
1057
- const userData = await this._getUserData(
1058
- user,
1059
- {
1060
- bypassCache: true,
1061
- clientMetadata,
1062
- },
1063
- userAgentValue
1064
- );
1065
- let smsMfaSettings = null;
1066
- let totpMfaSettings = null;
1067
-
1068
- switch (mfaMethod) {
1069
- case 'TOTP':
1070
- case 'SOFTWARE_TOKEN_MFA':
1071
- totpMfaSettings = {
1072
- PreferredMfa: true,
1073
- Enabled: true,
1074
- };
1075
- break;
1076
- case 'SMS':
1077
- case 'SMS_MFA':
1078
- smsMfaSettings = {
1079
- PreferredMfa: true,
1080
- Enabled: true,
1081
- };
1082
- break;
1083
- case 'NOMFA':
1084
- const mfaList = userData['UserMFASettingList'];
1085
- const currentMFAType = await this._getMfaTypeFromUserData(userData);
1086
- if (currentMFAType === 'NOMFA') {
1087
- return Promise.resolve('No change for mfa type');
1088
- } else if (currentMFAType === 'SMS_MFA') {
1089
- smsMfaSettings = {
1090
- PreferredMfa: false,
1091
- Enabled: false,
1092
- };
1093
- } else if (currentMFAType === 'SOFTWARE_TOKEN_MFA') {
1094
- totpMfaSettings = {
1095
- PreferredMfa: false,
1096
- Enabled: false,
1097
- };
1098
- } else {
1099
- return this.rejectAuthError(AuthErrorTypes.InvalidMFA);
1100
- }
1101
- // if there is a UserMFASettingList in the response
1102
- // we need to disable every mfa type in that list
1103
- if (mfaList && mfaList.length !== 0) {
1104
- // to disable SMS or TOTP if exists in that list
1105
- mfaList.forEach(mfaType => {
1106
- if (mfaType === 'SMS_MFA') {
1107
- smsMfaSettings = {
1108
- PreferredMfa: false,
1109
- Enabled: false,
1110
- };
1111
- } else if (mfaType === 'SOFTWARE_TOKEN_MFA') {
1112
- totpMfaSettings = {
1113
- PreferredMfa: false,
1114
- Enabled: false,
1115
- };
1116
- }
1117
- });
1118
- }
1119
- break;
1120
- default:
1121
- logger.debug('no validmfa method provided');
1122
- return this.rejectAuthError(AuthErrorTypes.NoMFA);
1123
- }
1124
-
1125
- const that = this;
1126
- return new Promise<string>((res, rej) => {
1127
- internalUser.setUserMfaPreference(
1128
- smsMfaSettings,
1129
- totpMfaSettings,
1130
- (err, result) => {
1131
- if (err) {
1132
- logger.debug('Set user mfa preference error', err);
1133
- return rej(err);
1134
- }
1135
- logger.debug('Set user mfa success', result);
1136
- logger.debug('Caching the latest user data into local');
1137
- // cache the latest result into user data
1138
- internalUser.getUserData(
1139
- async (err, data) => {
1140
- if (err) {
1141
- logger.debug('getting user data failed', err);
1142
- if (this.isSessionInvalid(err)) {
1143
- try {
1144
- await this.cleanUpInvalidSession(user, userAgentValue);
1145
- } catch (cleanUpError) {
1146
- rej(
1147
- new Error(
1148
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1149
- )
1150
- );
1151
- return;
1152
- }
1153
- }
1154
- return rej(err);
1155
- } else {
1156
- return res(result);
1157
- }
1158
- },
1159
- {
1160
- bypassCache: true,
1161
- clientMetadata,
1162
- },
1163
- userAgentValue
1164
- );
1165
- },
1166
- userAgentValue
1167
- );
1168
- });
1169
- }
1170
-
1171
- /**
1172
- * disable SMS
1173
- * @deprecated
1174
- * @param {CognitoUser} user - the current user
1175
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1176
- * @return - A promise resolves is success
1177
- */
1178
- public disableSMS(
1179
- user: CognitoUser,
1180
- customUserAgentDetails?: CustomUserAgentDetails
1181
- ): Promise<string> {
1182
- const internalUser = user as InternalCognitoUser;
1183
-
1184
- return new Promise((res, rej) => {
1185
- internalUser.disableMFA((err, data) => {
1186
- if (err) {
1187
- logger.debug('disable mfa failed', err);
1188
- rej(err);
1189
- return;
1190
- }
1191
- logger.debug('disable mfa succeed', data);
1192
- res(data);
1193
- return;
1194
- }, getAuthUserAgentValue(AuthAction.DisableSMS, customUserAgentDetails));
1195
- });
1196
- }
1197
-
1198
- /**
1199
- * enable SMS
1200
- * @deprecated
1201
- * @param {CognitoUser} user - the current user
1202
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1203
- * @return - A promise resolves is success
1204
- */
1205
- public enableSMS(
1206
- user: CognitoUser,
1207
- customUserAgentDetails?: CustomUserAgentDetails
1208
- ): Promise<string> {
1209
- const internalUser = user as InternalCognitoUser;
1210
-
1211
- return new Promise((res, rej) => {
1212
- internalUser.enableMFA((err, data) => {
1213
- if (err) {
1214
- logger.debug('enable mfa failed', err);
1215
- rej(err);
1216
- return;
1217
- }
1218
- logger.debug('enable mfa succeed', data);
1219
- res(data);
1220
- return;
1221
- }, getAuthUserAgentValue(AuthAction.EnableSMS, customUserAgentDetails));
1222
- });
1223
- }
1224
-
1225
- /**
1226
- * Setup TOTP
1227
- * @param {CognitoUser} user - the current user
1228
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1229
- * @return - A promise resolves with the secret code if success
1230
- */
1231
- public setupTOTP(
1232
- user: CognitoUser | any,
1233
- customUserAgentDetails?: CustomUserAgentDetails
1234
- ): Promise<string> {
1235
- const internalUser: InternalCognitoUser | any = user;
1236
-
1237
- return new Promise((res, rej) => {
1238
- internalUser.associateSoftwareToken(
1239
- {
1240
- onFailure: err => {
1241
- logger.debug('associateSoftwareToken failed', err);
1242
- rej(err);
1243
- return;
1244
- },
1245
- associateSecretCode: secretCode => {
1246
- logger.debug('associateSoftwareToken success', secretCode);
1247
- res(secretCode);
1248
- return;
1249
- },
1250
- },
1251
- getAuthUserAgentValue(AuthAction.SetupTOTP, customUserAgentDetails)
1252
- );
1253
- });
1254
- }
1255
-
1256
- /**
1257
- * verify TOTP setup
1258
- * @param {CognitoUser} user - the current user
1259
- * @param {string} challengeAnswer - challenge answer
1260
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1261
- * @return - A promise resolves is success
1262
- */
1263
- public verifyTotpToken(
1264
- user: CognitoUser | any,
1265
- challengeAnswer: string,
1266
- customUserAgentDetails?: CustomUserAgentDetails
1267
- ): Promise<CognitoUserSession> {
1268
- logger.debug('verification totp token', user, challengeAnswer);
1269
- const internalUser: InternalCognitoUser | any = user;
1270
-
1271
- let signInUserSession;
1272
- if (
1273
- internalUser &&
1274
- typeof internalUser.getSignInUserSession === 'function'
1275
- ) {
1276
- signInUserSession = (user as InternalCognitoUser).getSignInUserSession();
1277
- }
1278
- const isLoggedIn = signInUserSession?.isValid();
1279
-
1280
- return new Promise((res, rej) => {
1281
- internalUser.verifySoftwareToken(
1282
- challengeAnswer,
1283
- 'My TOTP device',
1284
- {
1285
- onFailure: err => {
1286
- logger.debug('verifyTotpToken failed', err);
1287
- rej(err);
1288
- return;
1289
- },
1290
- onSuccess: data => {
1291
- if (!isLoggedIn) {
1292
- dispatchAuthEvent(
1293
- 'signIn',
1294
- internalUser,
1295
- `A user ${internalUser.getUsername()} has been signed in`
1296
- );
1297
- }
1298
- dispatchAuthEvent(
1299
- 'verify',
1300
- internalUser,
1301
- `A user ${internalUser.getUsername()} has been verified`
1302
- );
1303
- logger.debug('verifyTotpToken success', data);
1304
- res(data);
1305
- return;
1306
- },
1307
- },
1308
- getAuthUserAgentValue(
1309
- AuthAction.VerifyTotpToken,
1310
- customUserAgentDetails
1311
- )
1312
- );
1313
- });
1314
- }
1315
-
1316
- /**
1317
- * Send MFA code to confirm sign in
1318
- * @param {Object} user - The CognitoUser object
1319
- * @param {String} code - The confirmation code
1320
- * @param {string} mfaType - optional mfaType: 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA'
1321
- * @param {ClientMetaData} clientMetadata - optional client metadata defaults to config
1322
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1323
- */
1324
- public confirmSignIn(
1325
- user: CognitoUser | any,
1326
- code: string,
1327
- mfaType?: 'SMS_MFA' | 'SOFTWARE_TOKEN_MFA' | null,
1328
- clientMetadata: ClientMetaData = this._config.clientMetadata,
1329
- customUserAgentDetails?: CustomUserAgentDetails
1330
- ): Promise<CognitoUser | any> {
1331
- const internalUser: InternalCognitoUser | any = user;
1332
-
1333
- if (!code) {
1334
- return this.rejectAuthError(AuthErrorTypes.EmptyCode);
1335
- }
1336
-
1337
- const that = this;
1338
- const userAgentDetails = getAuthUserAgentDetails(
1339
- AuthAction.ConfirmSignIn,
1340
- customUserAgentDetails
1341
- );
1342
- return new Promise((resolve, reject) => {
1343
- internalUser.sendMFACode(
1344
- code,
1345
- {
1346
- onSuccess: async session => {
1347
- logger.debug(session);
1348
- try {
1349
- await this.Credentials.clear();
1350
- const cred = await this.Credentials.set(session, 'session');
1351
- logger.debug('succeed to get cognito credentials', cred);
1352
- } catch (e) {
1353
- logger.debug('cannot get cognito credentials', e);
1354
- } finally {
1355
- that.user = internalUser;
1356
- try {
1357
- const currentUser = await this._currentUserPoolUser(
1358
- undefined,
1359
- userAgentDetails
1360
- );
1361
- Object.assign(internalUser, {
1362
- attributes: currentUser.attributes,
1363
- });
1364
- } catch (e) {
1365
- logger.debug('cannot get updated Cognito User', e);
1366
- }
1367
- dispatchAuthEvent(
1368
- 'signIn',
1369
- internalUser,
1370
- `A user ${internalUser.getUsername()} has been signed in`
1371
- );
1372
- resolve(internalUser);
1373
- }
1374
- },
1375
- onFailure: err => {
1376
- logger.debug('confirm signIn failure', err);
1377
- reject(err);
1378
- },
1379
- },
1380
- mfaType,
1381
- clientMetadata,
1382
- getAmplifyUserAgent(userAgentDetails)
1383
- );
1384
- });
1385
- }
1386
-
1387
- public completeNewPassword(
1388
- user: CognitoUser | any,
1389
- password: string,
1390
- requiredAttributes: any = {},
1391
- clientMetadata: ClientMetaData = this._config.clientMetadata,
1392
- customUserAgentDetails?: CustomUserAgentDetails
1393
- ): Promise<CognitoUser | any> {
1394
- const internalUser: InternalCognitoUser | any = user;
1395
-
1396
- if (!password) {
1397
- return this.rejectAuthError(AuthErrorTypes.EmptyPassword);
1398
- }
1399
-
1400
- const that = this;
1401
- return new Promise((resolve, reject) => {
1402
- internalUser.completeNewPasswordChallenge(
1403
- password,
1404
- requiredAttributes,
1405
- {
1406
- onSuccess: async session => {
1407
- logger.debug(session);
1408
- try {
1409
- await this.Credentials.clear();
1410
- const cred = await this.Credentials.set(session, 'session');
1411
- logger.debug('succeed to get cognito credentials', cred);
1412
- } catch (e) {
1413
- logger.debug('cannot get cognito credentials', e);
1414
- } finally {
1415
- that.user = internalUser;
1416
- dispatchAuthEvent(
1417
- 'signIn',
1418
- internalUser,
1419
- `A user ${internalUser.getUsername()} has been signed in`
1420
- );
1421
- resolve(internalUser);
1422
- }
1423
- },
1424
- onFailure: err => {
1425
- logger.debug('completeNewPassword failure', err);
1426
- dispatchAuthEvent(
1427
- 'completeNewPassword_failure',
1428
- err,
1429
- `${this.user} failed to complete the new password flow`
1430
- );
1431
- reject(err);
1432
- },
1433
- mfaRequired: (challengeName, challengeParam) => {
1434
- logger.debug('signIn MFA required');
1435
- internalUser['challengeName'] = challengeName;
1436
- internalUser['challengeParam'] = challengeParam;
1437
- resolve(internalUser);
1438
- },
1439
- mfaSetup: (challengeName, challengeParam) => {
1440
- logger.debug('signIn mfa setup', challengeName);
1441
- internalUser['challengeName'] = challengeName;
1442
- internalUser['challengeParam'] = challengeParam;
1443
- resolve(internalUser);
1444
- },
1445
- totpRequired: (challengeName, challengeParam) => {
1446
- logger.debug('signIn mfa setup', challengeName);
1447
- internalUser['challengeName'] = challengeName;
1448
- internalUser['challengeParam'] = challengeParam;
1449
- resolve(internalUser);
1450
- },
1451
- },
1452
- clientMetadata,
1453
- getAuthUserAgentValue(
1454
- AuthAction.CompleteNewPassword,
1455
- customUserAgentDetails
1456
- )
1457
- );
1458
- });
1459
- }
1460
-
1461
- /**
1462
- * Send the answer to a custom challenge
1463
- * @param {CognitoUser} user - The CognitoUser object
1464
- * @param {String} challengeResponses - The confirmation code
1465
- * @param {ClientMetaData} clientMetadata - optional client metadata defaults to config
1466
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1467
- *
1468
- */
1469
- public sendCustomChallengeAnswer(
1470
- user: CognitoUser | any,
1471
- challengeResponses: string,
1472
- clientMetadata: ClientMetaData = this._config.clientMetadata,
1473
- customUserAgentDetails?: CustomUserAgentDetails
1474
- ): Promise<CognitoUser | any> {
1475
- const internalUser: InternalCognitoUser | any = user;
1476
-
1477
- if (!this.userPool) {
1478
- return this.rejectNoUserPool();
1479
- }
1480
- if (!challengeResponses) {
1481
- return this.rejectAuthError(AuthErrorTypes.EmptyChallengeResponse);
1482
- }
1483
-
1484
- const that = this;
1485
- const userAgentDetails = getAuthUserAgentDetails(
1486
- AuthAction.SendCustomChallengeAnswer,
1487
- customUserAgentDetails
1488
- );
1489
- return new Promise((resolve, reject) => {
1490
- internalUser.sendCustomChallengeAnswer(
1491
- challengeResponses,
1492
- this.authCallbacks(internalUser, resolve, reject, userAgentDetails),
1493
- clientMetadata,
1494
- getAmplifyUserAgent(userAgentDetails)
1495
- );
1496
- });
1497
- }
1498
-
1499
- /**
1500
- * Delete an authenticated users' attributes
1501
- * @param {CognitoUser} user - The currently logged in user object
1502
- * @param {string[]} attributeNames - Attributes to delete
1503
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1504
- * @return {Promise}
1505
- **/
1506
- public deleteUserAttributes(
1507
- user: CognitoUser | any,
1508
- attributeNames: string[],
1509
- customUserAgentDetails?: CustomUserAgentDetails
1510
- ) {
1511
- const internalUser: InternalCognitoUser | any = user;
1512
- const that = this;
1513
- const userAgentValue = getAuthUserAgentValue(
1514
- AuthAction.DeleteUserAttributes,
1515
- customUserAgentDetails
1516
- );
1517
- return new Promise((resolve, reject) => {
1518
- that._userSession(userAgentValue, internalUser).then(session => {
1519
- internalUser.deleteAttributes(
1520
- attributeNames,
1521
- (err, result) => {
1522
- if (err) {
1523
- return reject(err);
1524
- } else {
1525
- return resolve(result);
1526
- }
1527
- },
1528
- userAgentValue
1529
- );
1530
- });
1531
- });
1532
- }
1533
-
1534
- /**
1535
- * Delete the current authenticated user
1536
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1537
- * @return {Promise}
1538
- **/
1539
- // TODO: Check return type void
1540
- public async deleteUser(
1541
- customUserAgentDetails?: CustomUserAgentDetails
1542
- ): Promise<string | void> {
1543
- try {
1544
- await this._storageSync;
1545
- } catch (e) {
1546
- logger.debug('Failed to sync cache info into memory', e);
1547
- throw new Error(e);
1548
- }
1549
-
1550
- const isSignedInHostedUI =
1551
- this._oAuthHandler &&
1552
- this._storage.getItem('amplify-signin-with-hostedUI') === 'true';
1553
-
1554
- return new Promise(async (res, rej) => {
1555
- if (this.userPool) {
1556
- const internalUser =
1557
- this.userPool.getCurrentUser() as InternalCognitoUser;
1558
-
1559
- if (!internalUser) {
1560
- logger.debug('Failed to get user from user pool');
1561
- return rej(new Error('No current user.'));
1562
- } else {
1563
- const userAgentValue = getAuthUserAgentValue(
1564
- AuthAction.DeleteUser,
1565
- customUserAgentDetails
1566
- );
1567
- internalUser.getSession(async (err, session) => {
1568
- if (err) {
1569
- logger.debug('Failed to get the user session', err);
1570
- if (this.isSessionInvalid(err)) {
1571
- try {
1572
- await this.cleanUpInvalidSession(
1573
- internalUser,
1574
- userAgentValue
1575
- );
1576
- } catch (cleanUpError) {
1577
- rej(
1578
- new Error(
1579
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1580
- )
1581
- );
1582
- return;
1583
- }
1584
- }
1585
- return rej(err);
1586
- } else {
1587
- internalUser.deleteUser(
1588
- (err, result: string) => {
1589
- if (err) {
1590
- rej(err);
1591
- } else {
1592
- dispatchAuthEvent(
1593
- 'userDeleted',
1594
- result,
1595
- 'The authenticated user has been deleted.'
1596
- );
1597
- internalUser.signOut(undefined, userAgentValue);
1598
- this.user = null;
1599
- try {
1600
- this.cleanCachedItems(); // clean aws credentials
1601
- } catch (e) {
1602
- // TODO: change to rejects in refactor
1603
- logger.debug('failed to clear cached items');
1604
- }
1605
-
1606
- if (isSignedInHostedUI) {
1607
- this.oAuthSignOutRedirect(res, rej);
1608
- } else {
1609
- dispatchAuthEvent(
1610
- 'signOut',
1611
- this.user,
1612
- `A user has been signed out`
1613
- );
1614
- res(result);
1615
- }
1616
- }
1617
- },
1618
- undefined,
1619
- userAgentValue
1620
- );
1621
- }
1622
- });
1623
- }
1624
- } else {
1625
- logger.debug('no Congito User pool');
1626
- rej(new Error('Cognito User pool does not exist'));
1627
- }
1628
- });
1629
- }
1630
-
1631
- /**
1632
- * Update an authenticated users' attributes
1633
- * @param {CognitoUser} user - The currently logged in user object
1634
- * @param {object} attributes - attributes to update
1635
- * @param {ClientMetaData} clientMetadata - optional client metadata, defaults to config
1636
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1637
- * @return {Promise}
1638
- **/
1639
- public updateUserAttributes(
1640
- user: CognitoUser | any,
1641
- attributes: object,
1642
- clientMetadata: ClientMetaData = this._config.clientMetadata,
1643
- customUserAgentDetails?: CustomUserAgentDetails
1644
- ): Promise<string> {
1645
- const internalUser: InternalCognitoUser | any = user;
1646
- const attributeList: ICognitoUserAttributeData[] = [];
1647
- const that = this;
1648
- const userAgentValue = getAuthUserAgentValue(
1649
- AuthAction.UpdateUserAttributes,
1650
- customUserAgentDetails
1651
- );
1652
- return new Promise((resolve, reject) => {
1653
- that._userSession(userAgentValue, internalUser).then(session => {
1654
- for (const key in attributes) {
1655
- if (key !== 'sub' && key.indexOf('_verified') < 0) {
1656
- const attr: ICognitoUserAttributeData = {
1657
- Name: key,
1658
- Value: attributes[key],
1659
- };
1660
- attributeList.push(attr);
1661
- }
1662
- }
1663
- internalUser.updateAttributes(
1664
- attributeList,
1665
- (err, result, details) => {
1666
- if (err) {
1667
- dispatchAuthEvent(
1668
- 'updateUserAttributes_failure',
1669
- err,
1670
- 'Failed to update attributes'
1671
- );
1672
- return reject(err);
1673
- } else {
1674
- const attrs = this.createUpdateAttributesResultList(
1675
- attributes as Record<string, string>,
1676
- details?.CodeDeliveryDetailsList
1677
- );
1678
- dispatchAuthEvent(
1679
- 'updateUserAttributes',
1680
- attrs,
1681
- 'Attributes successfully updated'
1682
- );
1683
- return resolve(result);
1684
- }
1685
- },
1686
- clientMetadata,
1687
- userAgentValue
1688
- );
1689
- });
1690
- });
1691
- }
1692
-
1693
- private createUpdateAttributesResultList(
1694
- attributes: Record<string, string>,
1695
- codeDeliveryDetailsList?: CodeDeliveryDetails[]
1696
- ): Record<string, string> {
1697
- const attrs = {};
1698
- Object.keys(attributes).forEach(key => {
1699
- attrs[key] = {
1700
- isUpdated: true,
1701
- };
1702
- const codeDeliveryDetails = codeDeliveryDetailsList?.find(
1703
- value => value.AttributeName === key
1704
- );
1705
- if (codeDeliveryDetails) {
1706
- attrs[key].isUpdated = false;
1707
- attrs[key].codeDeliveryDetails = codeDeliveryDetails;
1708
- }
1709
- });
1710
- return attrs;
1711
- }
1712
-
1713
- /**
1714
- * Return user attributes
1715
- * @param {Object} user - The CognitoUser object
1716
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1717
- * @return - A promise resolves to user attributes if success
1718
- */
1719
- public userAttributes(
1720
- user: CognitoUser | any,
1721
- customUserAgentDetails?: CustomUserAgentDetails
1722
- ): Promise<CognitoUserAttribute[]> {
1723
- return this._userAttributes(user, customUserAgentDetails);
1724
- }
1725
-
1726
- private _userAttributes(
1727
- user: CognitoUser | any,
1728
- customUserAgentDetails?: CustomUserAgentDetails
1729
- ): Promise<CognitoUserAttribute[]> {
1730
- const internalUser: InternalCognitoUser | any = user;
1731
- const userAgentValue = getAuthUserAgentValue(
1732
- AuthAction.UserAttributes,
1733
- customUserAgentDetails
1734
- );
1735
- return new Promise((resolve, reject) => {
1736
- this._userSession(userAgentValue, internalUser).then(session => {
1737
- internalUser.getUserAttributes((err, attributes) => {
1738
- if (err) {
1739
- reject(err);
1740
- } else {
1741
- resolve(attributes);
1742
- }
1743
- }, userAgentValue);
1744
- });
1745
- });
1746
- }
1747
-
1748
- public verifiedContact(
1749
- user: CognitoUser | any,
1750
- customUserAgentDetails?: CustomUserAgentDetails
1751
- ) {
1752
- const that = this;
1753
- return this._userAttributes(
1754
- user,
1755
- getAuthUserAgentDetails(
1756
- AuthAction.VerifiedContact,
1757
- customUserAgentDetails
1758
- )
1759
- ).then(attributes => {
1760
- const attrs = that.attributesToObject(attributes);
1761
- const unverified = {};
1762
- const verified = {};
1763
- if (attrs['email']) {
1764
- if (attrs['email_verified']) {
1765
- verified['email'] = attrs['email'];
1766
- } else {
1767
- unverified['email'] = attrs['email'];
1768
- }
1769
- }
1770
- if (attrs['phone_number']) {
1771
- if (attrs['phone_number_verified']) {
1772
- verified['phone_number'] = attrs['phone_number'];
1773
- } else {
1774
- unverified['phone_number'] = attrs['phone_number'];
1775
- }
1776
- }
1777
- return {
1778
- verified,
1779
- unverified,
1780
- };
1781
- });
1782
- }
1783
-
1784
- private isErrorWithMessage(err: any): err is { message: string } {
1785
- return (
1786
- typeof err === 'object' &&
1787
- Object.prototype.hasOwnProperty.call(err, 'message')
1788
- );
1789
- }
1790
-
1791
- // Session revoked by another app
1792
- private isTokenRevokedError(
1793
- err: any
1794
- ): err is { message: 'Access Token has been revoked' } {
1795
- return (
1796
- this.isErrorWithMessage(err) &&
1797
- err.message === 'Access Token has been revoked'
1798
- );
1799
- }
1800
-
1801
- private isRefreshTokenRevokedError(
1802
- err: any
1803
- ): err is { message: 'Refresh Token has been revoked' } {
1804
- return (
1805
- this.isErrorWithMessage(err) &&
1806
- err.message === 'Refresh Token has been revoked'
1807
- );
1808
- }
1809
-
1810
- private isUserDisabledError(
1811
- err: any
1812
- ): err is { message: 'User is disabled.' } {
1813
- return this.isErrorWithMessage(err) && err.message === 'User is disabled.';
1814
- }
1815
-
1816
- private isUserDoesNotExistError(
1817
- err: any
1818
- ): err is { message: 'User does not exist.' } {
1819
- return (
1820
- this.isErrorWithMessage(err) && err.message === 'User does not exist.'
1821
- );
1822
- }
1823
-
1824
- private isRefreshTokenExpiredError(
1825
- err: any
1826
- ): err is { message: 'Refresh Token has expired' } {
1827
- return (
1828
- this.isErrorWithMessage(err) &&
1829
- err.message === 'Refresh Token has expired'
1830
- );
1831
- }
1832
-
1833
- private isPasswordResetRequiredError(
1834
- err: any
1835
- ): err is { message: 'Password reset required for the user' } {
1836
- return (
1837
- this.isErrorWithMessage(err) &&
1838
- err.message === 'Password reset required for the user'
1839
- );
1840
- }
1841
-
1842
- private isSignedInHostedUI() {
1843
- return (
1844
- this._oAuthHandler &&
1845
- this._storage.getItem('amplify-signin-with-hostedUI') === 'true'
1846
- );
1847
- }
1848
-
1849
- private isSessionInvalid(err: any) {
1850
- return (
1851
- this.isUserDisabledError(err) ||
1852
- this.isUserDoesNotExistError(err) ||
1853
- this.isTokenRevokedError(err) ||
1854
- this.isRefreshTokenRevokedError(err) ||
1855
- this.isRefreshTokenExpiredError(err) ||
1856
- this.isPasswordResetRequiredError(err)
1857
- );
1858
- }
1859
-
1860
- private async cleanUpInvalidSession(
1861
- internalUser: InternalCognitoUser,
1862
- userAgentValue: string
1863
- ) {
1864
- internalUser.signOut(undefined, userAgentValue);
1865
- this.user = null;
1866
- try {
1867
- await this.cleanCachedItems(); // clean aws credentials
1868
- } catch (e) {
1869
- logger.debug('failed to clear cached items');
1870
- }
1871
- if (this.isSignedInHostedUI()) {
1872
- return new Promise((res, rej) => {
1873
- this.oAuthSignOutRedirect(res, rej);
1874
- });
1875
- } else {
1876
- dispatchAuthEvent('signOut', this.user, `A user has been signed out`);
1877
- }
1878
- }
1879
-
1880
- /**
1881
- * Get current authenticated user
1882
- * @param {CurrentUserOpts} params - options for getting the current user
1883
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
1884
- * @return - A promise resolves to current authenticated CognitoUser if success
1885
- */
1886
- public currentUserPoolUser(
1887
- params?: CurrentUserOpts,
1888
- customUserAgentDetails?: CustomUserAgentDetails
1889
- ): Promise<CognitoUser | any> {
1890
- return this._currentUserPoolUser(params, customUserAgentDetails);
1891
- }
1892
-
1893
- private _currentUserPoolUser(
1894
- params?: CurrentUserOpts,
1895
- customUserAgentDetails?: CustomUserAgentDetails
1896
- ): Promise<CognitoUser | any> {
1897
- if (!this.userPool) {
1898
- return this.rejectNoUserPool();
1899
- }
1900
-
1901
- return new Promise((res, rej) => {
1902
- this._storageSync
1903
- .then(async () => {
1904
- if (this.isOAuthInProgress()) {
1905
- logger.debug('OAuth signIn in progress, waiting for resolution...');
1906
-
1907
- await new Promise(res => {
1908
- const timeoutId = setTimeout(() => {
1909
- logger.debug('OAuth signIn in progress timeout');
1910
-
1911
- Hub.remove('auth', hostedUISignCallback);
1912
-
1913
- res();
1914
- }, OAUTH_FLOW_MS_TIMEOUT);
1915
-
1916
- Hub.listen('auth', hostedUISignCallback);
1917
-
1918
- function hostedUISignCallback({ payload }) {
1919
- const { event } = payload;
1920
-
1921
- if (
1922
- event === 'cognitoHostedUI' ||
1923
- event === 'cognitoHostedUI_failure'
1924
- ) {
1925
- logger.debug(`OAuth signIn resolved: ${event}`);
1926
- clearTimeout(timeoutId);
1927
-
1928
- Hub.remove('auth', hostedUISignCallback);
1929
-
1930
- res();
1931
- }
1932
- }
1933
- });
1934
- }
1935
-
1936
- const internalUser =
1937
- this.userPool.getCurrentUser() as InternalCognitoUser;
1938
-
1939
- if (!internalUser) {
1940
- logger.debug('Failed to get user from user pool');
1941
- rej('No current user');
1942
- return;
1943
- }
1944
-
1945
- // refresh the session if the session expired.
1946
- try {
1947
- const userAgentValue = getAuthUserAgentValue(
1948
- AuthAction.CurrentUserPoolUser,
1949
- customUserAgentDetails
1950
- );
1951
- const session = await this._userSession(
1952
- userAgentValue,
1953
- internalUser
1954
- );
1955
-
1956
- // get user data from Cognito
1957
- const bypassCache = params ? params.bypassCache : false;
1958
-
1959
- if (bypassCache) {
1960
- await this.Credentials.clear();
1961
- }
1962
-
1963
- const clientMetadata = this._config.clientMetadata;
1964
-
1965
- // validate the token's scope first before calling this function
1966
- const { scope = '' } = session.getAccessToken().decodePayload();
1967
- if (scope.split(' ').includes(USER_ADMIN_SCOPE)) {
1968
- internalUser.getUserData(
1969
- async (err, data) => {
1970
- if (err) {
1971
- logger.debug('getting user data failed', err);
1972
- if (this.isSessionInvalid(err)) {
1973
- try {
1974
- await this.cleanUpInvalidSession(
1975
- internalUser,
1976
- userAgentValue
1977
- );
1978
- } catch (cleanUpError) {
1979
- rej(
1980
- new Error(
1981
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
1982
- )
1983
- );
1984
- return;
1985
- }
1986
- rej(err);
1987
- } else {
1988
- res(internalUser);
1989
- }
1990
- return;
1991
- }
1992
- const preferredMFA = data.PreferredMfaSetting || 'NOMFA';
1993
- const attributeList: CognitoUserAttribute[] = [];
1994
-
1995
- for (let i = 0; i < data.UserAttributes.length; i++) {
1996
- const attribute = {
1997
- Name: data.UserAttributes[i].Name,
1998
- Value: data.UserAttributes[i].Value,
1999
- };
2000
- const userAttribute = new CognitoUserAttribute(attribute);
2001
- attributeList.push(userAttribute);
2002
- }
2003
-
2004
- const attributes = this.attributesToObject(attributeList);
2005
- Object.assign(internalUser, { attributes, preferredMFA });
2006
- return res(internalUser);
2007
- },
2008
- { bypassCache, clientMetadata },
2009
- userAgentValue
2010
- );
2011
- } else {
2012
- logger.debug(
2013
- `Unable to get the user data because the ${USER_ADMIN_SCOPE} ` +
2014
- `is not in the scopes of the access token`
2015
- );
2016
- return res(internalUser);
2017
- }
2018
- } catch (err) {
2019
- rej(err);
2020
- }
2021
- })
2022
- .catch(e => {
2023
- logger.debug('Failed to sync cache info into memory', e);
2024
- return rej(e);
2025
- });
2026
- });
2027
- }
2028
-
2029
- private isOAuthInProgress(): boolean {
2030
- return this.oAuthFlowInProgress;
2031
- }
2032
-
2033
- /**
2034
- * Get current authenticated user
2035
- * @param {CurrentUserOpts} - options for getting the current user
2036
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2037
- * @return - A promise resolves to current authenticated CognitoUser if success
2038
- */
2039
- public currentAuthenticatedUser(
2040
- params?: CurrentUserOpts,
2041
- customUserAgentDetails?: CustomUserAgentDetails
2042
- ): Promise<CognitoUser | any> {
2043
- return this._currentAuthenticatedUser(params, customUserAgentDetails);
2044
- }
2045
-
2046
- private async _currentAuthenticatedUser(
2047
- params?: CurrentUserOpts,
2048
- customUserAgentDetails?: CustomUserAgentDetails
2049
- ): Promise<CognitoUser | any> {
2050
- logger.debug('getting current authenticated user');
2051
- let federatedUser = null;
2052
- try {
2053
- await this._storageSync;
2054
- } catch (e) {
2055
- logger.debug('Failed to sync cache info into memory', e);
2056
- throw e;
2057
- }
2058
-
2059
- try {
2060
- const federatedInfo = JSON.parse(
2061
- this._storage.getItem('aws-amplify-federatedInfo')
2062
- );
2063
- if (federatedInfo) {
2064
- federatedUser = {
2065
- ...federatedInfo.user,
2066
- token: federatedInfo.token,
2067
- };
2068
- }
2069
- } catch (e) {
2070
- logger.debug('cannot load federated user from auth storage');
2071
- }
2072
-
2073
- if (federatedUser) {
2074
- this.user = federatedUser;
2075
- logger.debug('get current authenticated federated user', this.user);
2076
- return this.user;
2077
- } else {
2078
- logger.debug('get current authenticated userpool user');
2079
- let user = null;
2080
- try {
2081
- user = await this._currentUserPoolUser(
2082
- params,
2083
- getAuthUserAgentDetails(
2084
- AuthAction.CurrentAuthenticatedUser,
2085
- customUserAgentDetails
2086
- )
2087
- );
2088
- } catch (e) {
2089
- if (e === 'No userPool') {
2090
- logger.error(
2091
- 'Cannot get the current user because the user pool is missing. ' +
2092
- 'Please make sure the Auth module is configured with a valid Cognito User Pool ID'
2093
- );
2094
- }
2095
- logger.debug('The user is not authenticated by the error', e);
2096
- return Promise.reject('The user is not authenticated');
2097
- }
2098
- this.user = user;
2099
- return this.user;
2100
- }
2101
- }
2102
-
2103
- /**
2104
- * Get current user's session
2105
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2106
- * @return - A promise resolves to session object if success
2107
- */
2108
- public currentSession(
2109
- customUserAgentDetails?: CustomUserAgentDetails
2110
- ): Promise<CognitoUserSession> {
2111
- return this._currentSession(customUserAgentDetails);
2112
- }
2113
-
2114
- private _currentSession(
2115
- customUserAgentDetails?: CustomUserAgentDetails
2116
- ): Promise<CognitoUserSession> {
2117
- const that = this;
2118
- const userAgentDetails = getAuthUserAgentDetails(
2119
- AuthAction.CurrentSession,
2120
- customUserAgentDetails
2121
- );
2122
- logger.debug('Getting current session');
2123
- // Purposely not calling the reject method here because we don't need a console error
2124
- if (!this.userPool) {
2125
- return Promise.reject(new Error('No User Pool in the configuration.'));
2126
- }
2127
-
2128
- return new Promise((res, rej) => {
2129
- that
2130
- ._currentUserPoolUser(undefined, userAgentDetails)
2131
- .then(user => {
2132
- that
2133
- ._userSession(getAmplifyUserAgent(userAgentDetails), user)
2134
- .then(session => {
2135
- res(session);
2136
- return;
2137
- })
2138
- .catch(e => {
2139
- logger.debug('Failed to get the current session', e);
2140
- rej(e);
2141
- return;
2142
- });
2143
- })
2144
- .catch(e => {
2145
- logger.debug('Failed to get the current user', e);
2146
- rej(e);
2147
- return;
2148
- });
2149
- });
2150
- }
2151
-
2152
- private async _userSession(
2153
- userAgentValue: string,
2154
- internalUser?: InternalCognitoUser
2155
- ): Promise<CognitoUserSession> {
2156
- if (!internalUser) {
2157
- logger.debug('the user is null');
2158
- return this.rejectAuthError(AuthErrorTypes.NoUserSession);
2159
- }
2160
- const clientMetadata = this._config.clientMetadata;
2161
- // Debouncing the concurrent userSession calls by caching the promise.
2162
- // This solution assumes users will always call this function with the same CognitoUser instance.
2163
- if (this.inflightSessionPromiseCounter === 0) {
2164
- this.inflightSessionPromise = new Promise<CognitoUserSession>(
2165
- (res, rej) => {
2166
- internalUser.getSession(
2167
- async (err, session) => {
2168
- if (err) {
2169
- logger.debug(
2170
- 'Failed to get the session from user',
2171
- internalUser
2172
- );
2173
- if (this.isSessionInvalid(err)) {
2174
- try {
2175
- await this.cleanUpInvalidSession(
2176
- internalUser,
2177
- userAgentValue
2178
- );
2179
- } catch (cleanUpError) {
2180
- rej(
2181
- new Error(
2182
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
2183
- )
2184
- );
2185
- return;
2186
- }
2187
- }
2188
- rej(err);
2189
- return;
2190
- } else {
2191
- logger.debug('Succeed to get the user session', session);
2192
- res(session);
2193
- return;
2194
- }
2195
- },
2196
- { clientMetadata },
2197
- userAgentValue
2198
- );
2199
- }
2200
- );
2201
- }
2202
- this.inflightSessionPromiseCounter++;
2203
-
2204
- try {
2205
- const userSession = await this.inflightSessionPromise;
2206
- // Set private member. Avoid user.setSignInUserSession() to prevent excessive localstorage refresh.
2207
- // @ts-ignore
2208
- internalUser.signInUserSession = userSession;
2209
- return userSession!;
2210
- } finally {
2211
- this.inflightSessionPromiseCounter--;
2212
- }
2213
- }
2214
-
2215
- /**
2216
- * Get the corresponding user session
2217
- * @param {Object} user - The CognitoUser object
2218
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2219
- * @return - A promise resolves to the session
2220
- */
2221
- public userSession(
2222
- user,
2223
- customUserAgentDetails?: CustomUserAgentDetails
2224
- ): Promise<CognitoUserSession> {
2225
- return this._userSession(
2226
- getAuthUserAgentValue(AuthAction.UserSession, customUserAgentDetails),
2227
- user
2228
- );
2229
- }
2230
-
2231
- /**
2232
- * Get authenticated credentials of current user.
2233
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2234
- * @return - A promise resolves to be current user's credentials
2235
- */
2236
- public async currentUserCredentials(
2237
- customUserAgentDetails?: CustomUserAgentDetails
2238
- ): Promise<ICredentials> {
2239
- logger.debug('Getting current user credentials');
2240
-
2241
- try {
2242
- await this._storageSync;
2243
- } catch (e) {
2244
- logger.debug('Failed to sync cache info into memory', e);
2245
- throw e;
2246
- }
2247
-
2248
- // first to check whether there is federation info in the auth storage
2249
- let federatedInfo = null;
2250
- try {
2251
- federatedInfo = JSON.parse(
2252
- this._storage.getItem('aws-amplify-federatedInfo')
2253
- );
2254
- } catch (e) {
2255
- logger.debug('failed to get or parse item aws-amplify-federatedInfo', e);
2256
- }
2257
-
2258
- if (federatedInfo) {
2259
- // refresh the jwt token here if necessary
2260
- return this.Credentials.refreshFederatedToken(federatedInfo);
2261
- } else {
2262
- return this._currentSession(
2263
- getAuthUserAgentDetails(
2264
- AuthAction.CurrentUserCredentials,
2265
- customUserAgentDetails
2266
- )
2267
- )
2268
- .then(session => {
2269
- logger.debug('getting session success', session);
2270
- return this.Credentials.set(session, 'session');
2271
- })
2272
- .catch(() => {
2273
- logger.debug('getting guest credentials');
2274
- return this.Credentials.set(null, 'guest');
2275
- });
2276
- }
2277
- }
2278
-
2279
- public currentCredentials(
2280
- customUserAgentDetails?: CustomUserAgentDetails
2281
- ): Promise<ICredentials> {
2282
- logger.debug('getting current credentials');
2283
- return this.Credentials.get();
2284
- }
2285
-
2286
- /**
2287
- * Initiate an attribute confirmation request
2288
- * @param {Object} user - The CognitoUser
2289
- * @param {Object} attr - The attributes to be verified
2290
- * @param {ClientMetaData} clientMetadata - optional client metadata, defaults to config
2291
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2292
- * @return - A promise resolves to callback data if success
2293
- */
2294
- public verifyUserAttribute(
2295
- user: CognitoUser | any,
2296
- attr: string,
2297
- clientMetadata: ClientMetaData = this._config.clientMetadata,
2298
- customUserAgentDetails?: CustomUserAgentDetails
2299
- ): Promise<void> {
2300
- return this._verifyUserAttribute(
2301
- user,
2302
- attr,
2303
- clientMetadata,
2304
- customUserAgentDetails
2305
- );
2306
- }
2307
-
2308
- private _verifyUserAttribute(
2309
- user: CognitoUser | any,
2310
- attr: string,
2311
- clientMetadata: ClientMetaData = this._config.clientMetadata,
2312
- customUserAgentDetails?: CustomUserAgentDetails
2313
- ): Promise<void> {
2314
- const internalUser: InternalCognitoUser | any = user;
2315
-
2316
- return new Promise((resolve, reject) => {
2317
- internalUser.getAttributeVerificationCode(
2318
- attr,
2319
- {
2320
- onSuccess(success) {
2321
- return resolve(success);
2322
- },
2323
- onFailure(err) {
2324
- return reject(err);
2325
- },
2326
- },
2327
- clientMetadata,
2328
- getAuthUserAgentValue(
2329
- AuthAction.VerifyUserAttribute,
2330
- customUserAgentDetails
2331
- )
2332
- );
2333
- });
2334
- }
2335
-
2336
- /**
2337
- * Confirm an attribute using a confirmation code
2338
- * @param {Object} user - The CognitoUser
2339
- * @param {Object} attr - The attribute to be verified
2340
- * @param {String} code - The confirmation code
2341
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2342
- * @return - A promise resolves to callback data if success
2343
- */
2344
- public verifyUserAttributeSubmit(
2345
- user: CognitoUser | any,
2346
- attr: string,
2347
- code: string,
2348
- customUserAgentDetails?: CustomUserAgentDetails
2349
- ): Promise<string> {
2350
- return this._verifyUserAttributeSubmit(
2351
- user,
2352
- attr,
2353
- code,
2354
- customUserAgentDetails
2355
- );
2356
- }
2357
-
2358
- private _verifyUserAttributeSubmit(
2359
- user: CognitoUser | any,
2360
- attr: string,
2361
- code: string,
2362
- customUserAgentDetails?: CustomUserAgentDetails
2363
- ): Promise<string> {
2364
- if (!code) {
2365
- return this.rejectAuthError(AuthErrorTypes.EmptyCode);
2366
- }
2367
- const internalUser: InternalCognitoUser | any = user;
2368
-
2369
- return new Promise((resolve, reject) => {
2370
- internalUser.verifyAttribute(
2371
- attr,
2372
- code,
2373
- {
2374
- onSuccess(data) {
2375
- resolve(data);
2376
- return;
2377
- },
2378
- onFailure(err) {
2379
- reject(err);
2380
- return;
2381
- },
2382
- },
2383
- getAuthUserAgentValue(
2384
- AuthAction.VerifyUserAttributeSubmit,
2385
- customUserAgentDetails
2386
- )
2387
- );
2388
- });
2389
- }
2390
-
2391
- public verifyCurrentUserAttribute(
2392
- attr: string,
2393
- customUserAgentDetails?: CustomUserAgentDetails
2394
- ): Promise<void> {
2395
- const userAgentDetails = getAuthUserAgentDetails(
2396
- AuthAction.VerifyCurrentUserAttribute,
2397
- customUserAgentDetails
2398
- );
2399
- const that = this;
2400
- return that
2401
- ._currentUserPoolUser(undefined, userAgentDetails)
2402
- .then(user =>
2403
- that._verifyUserAttribute(user, attr, undefined, userAgentDetails)
2404
- );
2405
- }
2406
-
2407
- /**
2408
- * Confirm current user's attribute using a confirmation code
2409
- * @param {Object} attr - The attribute to be verified
2410
- * @param {String} code - The confirmation code
2411
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2412
- * @return - A promise resolves to callback data if success
2413
- */
2414
- verifyCurrentUserAttributeSubmit(
2415
- attr: string,
2416
- code: string,
2417
- customUserAgentDetails?: CustomUserAgentDetails
2418
- ): Promise<string> {
2419
- const userAgentDetails = getAuthUserAgentDetails(
2420
- AuthAction.VerifyCurrentUserAttributeSubmit,
2421
- customUserAgentDetails
2422
- );
2423
- const that = this;
2424
- return that
2425
- ._currentUserPoolUser(undefined, userAgentDetails)
2426
- .then(user =>
2427
- that._verifyUserAttributeSubmit(user, attr, code, userAgentDetails)
2428
- );
2429
- }
2430
-
2431
- private async cognitoIdentitySignOut(
2432
- opts: SignOutOpts,
2433
- internalUser: InternalCognitoUser | any,
2434
- userAgentValue: string
2435
- ) {
2436
- try {
2437
- await this._storageSync;
2438
- } catch (e) {
2439
- logger.debug('Failed to sync cache info into memory', e);
2440
- throw e;
2441
- }
2442
-
2443
- const isSignedInHostedUI =
2444
- this._oAuthHandler &&
2445
- this._storage.getItem('amplify-signin-with-hostedUI') === 'true';
2446
-
2447
- return new Promise((res, rej) => {
2448
- if (opts && opts.global) {
2449
- logger.debug('user global sign out', internalUser);
2450
- // in order to use global signout
2451
- // we must validate the user as an authenticated user by using getSession
2452
- const clientMetadata = this._config.clientMetadata; // TODO: verify behavior if this is override during signIn
2453
-
2454
- internalUser.getSession(
2455
- async (err, result) => {
2456
- if (err) {
2457
- logger.debug('failed to get the user session', err);
2458
- if (this.isSessionInvalid(err)) {
2459
- try {
2460
- await this.cleanUpInvalidSession(
2461
- internalUser,
2462
- userAgentValue
2463
- );
2464
- } catch (cleanUpError) {
2465
- rej(
2466
- new Error(
2467
- `Session is invalid due to: ${err.message} and failed to clean up invalid session: ${cleanUpError.message}`
2468
- )
2469
- );
2470
- return;
2471
- }
2472
- }
2473
- return rej(err);
2474
- }
2475
- internalUser.globalSignOut(
2476
- {
2477
- onSuccess: data => {
2478
- logger.debug('global sign out success');
2479
- if (isSignedInHostedUI) {
2480
- this.oAuthSignOutRedirect(res, rej);
2481
- } else {
2482
- return res();
2483
- }
2484
- },
2485
- onFailure: err => {
2486
- logger.debug('global sign out failed', err);
2487
- return rej(err);
2488
- },
2489
- },
2490
- userAgentValue
2491
- );
2492
- },
2493
- { clientMetadata },
2494
- userAgentValue
2495
- );
2496
- } else {
2497
- logger.debug('user sign out', internalUser);
2498
- internalUser.signOut(() => {
2499
- if (isSignedInHostedUI) {
2500
- this.oAuthSignOutRedirect(res, rej);
2501
- } else {
2502
- return res();
2503
- }
2504
- }, userAgentValue);
2505
- }
2506
- });
2507
- }
2508
-
2509
- private oAuthSignOutRedirect(
2510
- resolve: () => void,
2511
- reject: (reason?: any) => void
2512
- ) {
2513
- const { isBrowser } = browserOrNode();
2514
-
2515
- if (isBrowser) {
2516
- this.oAuthSignOutRedirectOrReject(reject);
2517
- } else {
2518
- this.oAuthSignOutAndResolve(resolve);
2519
- }
2520
- }
2521
-
2522
- private oAuthSignOutAndResolve(resolve: () => void) {
2523
- this._oAuthHandler.signOut();
2524
- resolve();
2525
- }
2526
-
2527
- private oAuthSignOutRedirectOrReject(reject: (reason?: any) => void) {
2528
- this._oAuthHandler.signOut(); // this method redirects url
2529
-
2530
- // App should be redirected to another url otherwise it will reject
2531
- setTimeout(() => reject(Error('Signout timeout fail')), 3000);
2532
- }
2533
-
2534
- /**
2535
- * Sign out method
2536
- * @param {SignOutOpts} opts - options for sign out
2537
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2538
- * @return - A promise resolved if success
2539
- */
2540
- public async signOut(
2541
- opts?: SignOutOpts,
2542
- customUserAgentDetails?: CustomUserAgentDetails
2543
- ): Promise<any> {
2544
- try {
2545
- await this.cleanCachedItems();
2546
- } catch (e) {
2547
- logger.debug('failed to clear cached items');
2548
- }
2549
-
2550
- if (this.userPool) {
2551
- const internalUser =
2552
- this.userPool.getCurrentUser() as InternalCognitoUser;
2553
- if (internalUser) {
2554
- await this.cognitoIdentitySignOut(
2555
- opts,
2556
- internalUser,
2557
- getAuthUserAgentValue(AuthAction.SignOut, customUserAgentDetails)
2558
- );
2559
- } else {
2560
- logger.debug('no current Cognito user');
2561
- }
2562
- } else {
2563
- logger.debug('no Cognito User pool');
2564
- }
2565
-
2566
- /**
2567
- * Note for future refactor - no reliable way to get username with
2568
- * Cognito User Pools vs Identity when federating with Social Providers
2569
- * This is why we need a well structured session object that can be inspected
2570
- * and information passed back in the message below for Hub dispatch
2571
- */
2572
- dispatchAuthEvent('signOut', this.user, `A user has been signed out`);
2573
- this.user = null;
2574
- }
2575
-
2576
- private async cleanCachedItems() {
2577
- // clear cognito cached item
2578
- await this.Credentials.clear();
2579
- }
2580
-
2581
- /**
2582
- * Change a password for an authenticated user
2583
- * @param {Object} user - The CognitoUser object
2584
- * @param {String} oldPassword - the current password
2585
- * @param {String} newPassword - the requested new password
2586
- * @param {ClientMetaData} clientMetadata - optional client metadata, defaults to config
2587
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2588
- * @return - A promise resolves if success
2589
- */
2590
- public changePassword(
2591
- user: CognitoUser | any,
2592
- oldPassword: string,
2593
- newPassword: string,
2594
- clientMetadata: ClientMetaData = this._config.clientMetadata,
2595
- customUserAgentDetails?: CustomUserAgentDetails
2596
- ): Promise<'SUCCESS'> {
2597
- const internalUser: InternalCognitoUser | any = user;
2598
- const userAgentValue = getAuthUserAgentValue(
2599
- AuthAction.ChangePassword,
2600
- customUserAgentDetails
2601
- );
2602
-
2603
- return new Promise((resolve, reject) => {
2604
- this._userSession(userAgentValue, internalUser).then(session => {
2605
- internalUser.changePassword(
2606
- oldPassword,
2607
- newPassword,
2608
- (err, data) => {
2609
- if (err) {
2610
- logger.debug('change password failure', err);
2611
- return reject(err);
2612
- } else {
2613
- return resolve(data);
2614
- }
2615
- },
2616
- clientMetadata,
2617
- userAgentValue
2618
- );
2619
- });
2620
- });
2621
- }
2622
-
2623
- /**
2624
- * Initiate a forgot password request
2625
- * @param {String} username - the username to change password
2626
- * @param {ClientMetaData} clientMetadata - optional client metadata, defaults to config
2627
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2628
- * @return - A promise resolves if success
2629
- */
2630
- public forgotPassword(
2631
- username: string,
2632
- clientMetadata: ClientMetaData = this._config.clientMetadata,
2633
- customUserAgentDetails?: CustomUserAgentDetails
2634
- ): Promise<any> {
2635
- if (!this.userPool) {
2636
- return this.rejectNoUserPool();
2637
- }
2638
- if (!username) {
2639
- return this.rejectAuthError(AuthErrorTypes.EmptyUsername);
2640
- }
2641
-
2642
- const internalUser = this.createCognitoUser(username);
2643
- return new Promise((resolve, reject) => {
2644
- internalUser.forgotPassword(
2645
- {
2646
- onSuccess: () => {
2647
- resolve();
2648
- return;
2649
- },
2650
- onFailure: err => {
2651
- logger.debug('forgot password failure', err);
2652
- dispatchAuthEvent(
2653
- 'forgotPassword_failure',
2654
- err,
2655
- `${username} forgotPassword failed`
2656
- );
2657
- reject(err);
2658
- return;
2659
- },
2660
- inputVerificationCode: data => {
2661
- dispatchAuthEvent(
2662
- 'forgotPassword',
2663
- internalUser,
2664
- `${username} has initiated forgot password flow`
2665
- );
2666
- resolve(data);
2667
- return;
2668
- },
2669
- },
2670
- clientMetadata,
2671
- getAuthUserAgentValue(AuthAction.ForgotPassword, customUserAgentDetails)
2672
- );
2673
- });
2674
- }
2675
-
2676
- /**
2677
- * Confirm a new password using a confirmation Code
2678
- * @param {String} username - The username
2679
- * @param {String} code - The confirmation code
2680
- * @param {String} password - The new password
2681
- * @param {ClientMetaData} clientMetadata - optional client metadata, defaults to config
2682
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2683
- * @return - A promise that resolves if success
2684
- */
2685
- public forgotPasswordSubmit(
2686
- username: string,
2687
- code: string,
2688
- password: string,
2689
- clientMetadata: ClientMetaData = this._config.clientMetadata,
2690
- customUserAgentDetails?: CustomUserAgentDetails
2691
- ): Promise<string> {
2692
- if (!this.userPool) {
2693
- return this.rejectNoUserPool();
2694
- }
2695
- if (!username) {
2696
- return this.rejectAuthError(AuthErrorTypes.EmptyUsername);
2697
- }
2698
- if (!code) {
2699
- return this.rejectAuthError(AuthErrorTypes.EmptyCode);
2700
- }
2701
- if (!password) {
2702
- return this.rejectAuthError(AuthErrorTypes.EmptyPassword);
2703
- }
2704
-
2705
- const internalUser = this.createCognitoUser(username);
2706
- return new Promise((resolve, reject) => {
2707
- internalUser.confirmPassword(
2708
- code,
2709
- password,
2710
- {
2711
- onSuccess: success => {
2712
- dispatchAuthEvent(
2713
- 'forgotPasswordSubmit',
2714
- internalUser,
2715
- `${username} forgotPasswordSubmit successful`
2716
- );
2717
- resolve(success);
2718
- return;
2719
- },
2720
- onFailure: err => {
2721
- dispatchAuthEvent(
2722
- 'forgotPasswordSubmit_failure',
2723
- err,
2724
- `${username} forgotPasswordSubmit failed`
2725
- );
2726
- reject(err);
2727
- return;
2728
- },
2729
- },
2730
- clientMetadata,
2731
- getAuthUserAgentValue(
2732
- AuthAction.ForgotPasswordSubmit,
2733
- customUserAgentDetails
2734
- )
2735
- );
2736
- });
2737
- }
2738
-
2739
- /**
2740
- * Get user information
2741
- * @async
2742
- * @param {CustomUserAgentDetails} customUserAgentDetails - Optional parameter to send user agent details
2743
- * @return {Object }- current User's information
2744
- */
2745
- public async currentUserInfo(
2746
- customUserAgentDetails?: CustomUserAgentDetails
2747
- ) {
2748
- const source = this.Credentials.getCredSource();
2749
- const userAgentDetails = getAuthUserAgentDetails(
2750
- AuthAction.CurrentUserInfo,
2751
- customUserAgentDetails
2752
- );
2753
-
2754
- if (!source || source === 'aws' || source === 'userPool') {
2755
- const internalUser: InternalCognitoUser = await this._currentUserPoolUser(
2756
- undefined,
2757
- userAgentDetails
2758
- ).catch(err => logger.error(err));
2759
- if (!internalUser) {
2760
- return null;
2761
- }
2762
-
2763
- try {
2764
- const attributes = await this._userAttributes(
2765
- internalUser,
2766
- userAgentDetails
2767
- );
2768
- const userAttrs: object = this.attributesToObject(attributes);
2769
- let credentials = null;
2770
- try {
2771
- credentials = await this.currentCredentials();
2772
- } catch (e) {
2773
- logger.debug(
2774
- 'Failed to retrieve credentials while getting current user info',
2775
- e
2776
- );
2777
- }
2778
-
2779
- const info = {
2780
- id: credentials ? credentials.identityId : undefined,
2781
- username: internalUser.getUsername(),
2782
- attributes: userAttrs,
2783
- };
2784
- return info;
2785
- } catch (err) {
2786
- logger.error('currentUserInfo error', err);
2787
- return {};
2788
- }
2789
- }
2790
-
2791
- if (source === 'federated') {
2792
- const user = this.user;
2793
- return user ? user : {};
2794
- }
2795
- }
2796
-
2797
- public async federatedSignIn(
2798
- providerOrOptions:
2799
- | LegacyProvider
2800
- | FederatedSignInOptions
2801
- | FederatedSignInOptionsCustom,
2802
- response?: FederatedResponse,
2803
- user?: FederatedUser,
2804
- customUserAgentDetails?: CustomUserAgentDetails
2805
- ): Promise<ICredentials> {
2806
- if (!this._config.identityPoolId && !this._config.userPoolId) {
2807
- throw new Error(
2808
- `Federation requires either a User Pool or Identity Pool in config`
2809
- );
2810
- }
2811
-
2812
- // Ensure backwards compatability
2813
- if (typeof providerOrOptions === 'undefined') {
2814
- if (this._config.identityPoolId && !this._config.userPoolId) {
2815
- throw new Error(
2816
- `Federation with Identity Pools requires tokens passed as arguments`
2817
- );
2818
- }
2819
- }
2820
-
2821
- if (
2822
- isFederatedSignInOptions(providerOrOptions) ||
2823
- isFederatedSignInOptionsCustom(providerOrOptions) ||
2824
- hasCustomState(providerOrOptions) ||
2825
- typeof providerOrOptions === 'undefined'
2826
- ) {
2827
- const options = providerOrOptions || {
2828
- provider: CognitoHostedUIIdentityProvider.Cognito,
2829
- };
2830
- const provider = isFederatedSignInOptions(options)
2831
- ? options.provider
2832
- : (options as FederatedSignInOptionsCustom).customProvider;
2833
-
2834
- const customState = isFederatedSignInOptions(options)
2835
- ? options.customState
2836
- : (options as FederatedSignInOptionsCustom).customState;
2837
-
2838
- if (this._config.userPoolId) {
2839
- const client_id = isCognitoHostedOpts(this._config.oauth)
2840
- ? this._config.userPoolWebClientId
2841
- : this._config.oauth.clientID;
2842
- /*Note: Invenstigate automatically adding trailing slash */
2843
- const redirect_uri = isCognitoHostedOpts(this._config.oauth)
2844
- ? this._config.oauth.redirectSignIn
2845
- : this._config.oauth.redirectUri;
2846
-
2847
- this._storage.setItem(
2848
- 'aws-amplify-federatedUserAgent',
2849
- getAuthUserAgentValue(
2850
- AuthAction.FederatedSignIn,
2851
- customUserAgentDetails
2852
- )
2853
- );
2854
-
2855
- this._oAuthHandler.oauthSignIn(
2856
- this._config.oauth.responseType,
2857
- this._config.oauth.domain,
2858
- redirect_uri,
2859
- client_id,
2860
- provider,
2861
- customState
2862
- );
2863
- }
2864
- } else {
2865
- const provider = providerOrOptions;
2866
- // To check if the user is already logged in
2867
- try {
2868
- const loggedInUser = JSON.stringify(
2869
- JSON.parse(this._storage.getItem('aws-amplify-federatedInfo')).user
2870
- );
2871
- if (loggedInUser) {
2872
- logger.warn(`There is already a signed in user: ${loggedInUser} in your app.
2873
- You should not call Auth.federatedSignIn method again as it may cause unexpected behavior.`);
2874
- }
2875
- } catch (e) {}
2876
-
2877
- const { token, identity_id, expires_at } = response;
2878
- // Because this.Credentials.set would update the user info with identity id
2879
- // So we need to retrieve the user again.
2880
- const credentials = await this.Credentials.set(
2881
- { provider, token, identity_id, user, expires_at },
2882
- 'federation'
2883
- );
2884
- const currentUser = await this._currentAuthenticatedUser();
2885
- dispatchAuthEvent(
2886
- 'signIn',
2887
- currentUser,
2888
- `A user ${currentUser.username} has been signed in`
2889
- );
2890
- logger.debug('federated sign in credentials', credentials);
2891
- return credentials;
2892
- }
2893
- }
2894
-
2895
- /**
2896
- * Used to complete the OAuth flow with or without the Cognito Hosted UI
2897
- * @param {String} URL - optional parameter for customers to pass in the response URL
2898
- */
2899
- private async _handleAuthResponse(URL?: string) {
2900
- if (this.oAuthFlowInProgress) {
2901
- logger.debug(`Skipping URL ${URL} current flow in progress`);
2902
- return;
2903
- }
2904
-
2905
- try {
2906
- this.oAuthFlowInProgress = true;
2907
- if (!this._config.userPoolId) {
2908
- throw new Error(
2909
- `OAuth responses require a User Pool defined in config`
2910
- );
2911
- }
2912
-
2913
- dispatchAuthEvent(
2914
- 'parsingCallbackUrl',
2915
- { url: URL },
2916
- `The callback url is being parsed`
2917
- );
2918
-
2919
- const currentUrl =
2920
- URL || (browserOrNode().isBrowser ? window.location.href : '');
2921
-
2922
- const hasCodeOrError = !!(parse(currentUrl).query || '')
2923
- .split('&')
2924
- .map(entry => entry.split('='))
2925
- .find(([k]) => k === 'code' || k === 'error');
2926
-
2927
- const hasTokenOrError = !!(parse(currentUrl).hash || '#')
2928
- .substr(1)
2929
- .split('&')
2930
- .map(entry => entry.split('='))
2931
- .find(([k]) => k === 'access_token' || k === 'error');
2932
-
2933
- if (hasCodeOrError || hasTokenOrError) {
2934
- this._storage.setItem('amplify-redirected-from-hosted-ui', 'true');
2935
- const userAgentValue =
2936
- this._storage.getItem('aws-amplify-federatedUserAgent') || undefined;
2937
- this._storage.removeItem('aws-amplify-federatedUserAgent');
2938
- try {
2939
- const { accessToken, idToken, refreshToken, state } =
2940
- await this._oAuthHandler.handleAuthResponse(
2941
- currentUrl,
2942
- userAgentValue
2943
- );
2944
- const session = new CognitoUserSession({
2945
- IdToken: new CognitoIdToken({ IdToken: idToken }),
2946
- RefreshToken: new CognitoRefreshToken({
2947
- RefreshToken: refreshToken,
2948
- }),
2949
- AccessToken: new CognitoAccessToken({
2950
- AccessToken: accessToken,
2951
- }),
2952
- });
2953
-
2954
- let credentials;
2955
- // Get AWS Credentials & store if Identity Pool is defined
2956
- if (this._config.identityPoolId) {
2957
- credentials = await this.Credentials.set(session, 'session');
2958
- logger.debug('AWS credentials', credentials);
2959
- }
2960
-
2961
- /*
2962
- Prior to the request we do sign the custom state along with the state we set. This check will verify
2963
- if there is a dash indicated when setting custom state from the request. If a dash is contained
2964
- then there is custom state present on the state string.
2965
- */
2966
- const isCustomStateIncluded = /-/.test(state);
2967
-
2968
- /*
2969
- The following is to create a user for the Cognito Identity SDK to store the tokens
2970
- When we remove this SDK later that logic will have to be centralized in our new version
2971
- */
2972
- //#region
2973
- const currentUser = this.createCognitoUser(
2974
- session.getIdToken().decodePayload()['cognito:username']
2975
- );
2976
-
2977
- // This calls cacheTokens() in Cognito SDK
2978
- currentUser.setSignInUserSession(session);
2979
-
2980
- if (window && typeof window.history !== 'undefined') {
2981
- window.history.replaceState(
2982
- {},
2983
- null,
2984
- (this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn
2985
- );
2986
- }
2987
-
2988
- dispatchAuthEvent(
2989
- 'signIn',
2990
- currentUser,
2991
- `A user ${currentUser.getUsername()} has been signed in`
2992
- );
2993
- dispatchAuthEvent(
2994
- 'cognitoHostedUI',
2995
- currentUser,
2996
- `A user ${currentUser.getUsername()} has been signed in via Cognito Hosted UI`
2997
- );
2998
-
2999
- if (isCustomStateIncluded) {
3000
- const customState = state.split('-').splice(1).join('-');
3001
-
3002
- dispatchAuthEvent(
3003
- 'customOAuthState',
3004
- urlSafeDecode(customState),
3005
- `State for user ${currentUser.getUsername()}`
3006
- );
3007
- }
3008
- //#endregion
3009
-
3010
- return credentials;
3011
- } catch (err) {
3012
- logger.debug('Error in cognito hosted auth response', err);
3013
-
3014
- // Just like a successful handling of `?code`, replace the window history to "dispose" of the `code`.
3015
- // Otherwise, reloading the page will throw errors as the `code` has already been spent.
3016
- if (window && typeof window.history !== 'undefined') {
3017
- window.history.replaceState(
3018
- {},
3019
- null,
3020
- (this._config.oauth as AwsCognitoOAuthOpts).redirectSignIn
3021
- );
3022
- }
3023
-
3024
- dispatchAuthEvent(
3025
- 'signIn_failure',
3026
- err,
3027
- `The OAuth response flow failed`
3028
- );
3029
- dispatchAuthEvent(
3030
- 'cognitoHostedUI_failure',
3031
- err,
3032
- `A failure occurred when returning to the Cognito Hosted UI`
3033
- );
3034
- dispatchAuthEvent(
3035
- 'customState_failure',
3036
- err,
3037
- `A failure occurred when returning state`
3038
- );
3039
- }
3040
- }
3041
- } finally {
3042
- this.oAuthFlowInProgress = false;
3043
- }
3044
- }
3045
-
3046
- /**
3047
- * Compact version of credentials
3048
- * @param {Object} credentials
3049
- * @return {Object} - Credentials
3050
- */
3051
- public essentialCredentials(credentials): ICredentials {
3052
- return {
3053
- accessKeyId: credentials.accessKeyId,
3054
- sessionToken: credentials.sessionToken,
3055
- secretAccessKey: credentials.secretAccessKey,
3056
- identityId: credentials.identityId,
3057
- authenticated: credentials.authenticated,
3058
- };
3059
- }
3060
-
3061
- private attributesToObject(attributes) {
3062
- const obj = {};
3063
- if (attributes) {
3064
- attributes.map(attribute => {
3065
- if (
3066
- attribute.Name === 'email_verified' ||
3067
- attribute.Name === 'phone_number_verified'
3068
- ) {
3069
- obj[attribute.Name] =
3070
- this.isTruthyString(attribute.Value) || attribute.Value === true;
3071
- } else {
3072
- obj[attribute.Name] = attribute.Value;
3073
- }
3074
- });
3075
- }
3076
- return obj;
3077
- }
3078
-
3079
- private isTruthyString(value: any): boolean {
3080
- return (
3081
- typeof value.toLowerCase === 'function' && value.toLowerCase() === 'true'
3082
- );
3083
- }
3084
-
3085
- private createCognitoUser(username: string): InternalCognitoUser {
3086
- const userData: ICognitoUserData = {
3087
- Username: username,
3088
- Pool: this.userPool,
3089
- };
3090
- userData.Storage = this._storage;
3091
-
3092
- const { authenticationFlowType } = this._config;
3093
-
3094
- const internalUser = new InternalCognitoUser(userData);
3095
- if (authenticationFlowType) {
3096
- internalUser.setAuthenticationFlowType(authenticationFlowType);
3097
- }
3098
- return internalUser;
3099
- }
3100
-
3101
- private _isValidAuthStorage(obj) {
3102
- // We need to check if the obj has the functions of Storage
3103
- return (
3104
- !!obj &&
3105
- typeof obj.getItem === 'function' &&
3106
- typeof obj.setItem === 'function' &&
3107
- typeof obj.removeItem === 'function' &&
3108
- typeof obj.clear === 'function'
3109
- );
3110
- }
3111
-
3112
- private noUserPoolErrorHandler(config: AuthOptions): AuthErrorTypes {
3113
- if (config) {
3114
- if (!config.userPoolId || !config.identityPoolId) {
3115
- return AuthErrorTypes.MissingAuthConfig;
3116
- }
3117
- }
3118
- return AuthErrorTypes.NoConfig;
3119
- }
3120
-
3121
- private rejectAuthError(type: AuthErrorTypes): Promise<never> {
3122
- return Promise.reject(new AuthError(type));
3123
- }
3124
-
3125
- private rejectNoUserPool(): Promise<never> {
3126
- const type = this.noUserPoolErrorHandler(this._config);
3127
- return Promise.reject(new NoUserPoolError(type));
3128
- }
3129
-
3130
- public async rememberDevice(
3131
- customUserAgentDetails?: CustomUserAgentDetails
3132
- ): Promise<string | AuthError> {
3133
- let internalUser: InternalCognitoUser | any;
3134
- const userAgentDetails = getAuthUserAgentDetails(
3135
- AuthAction.RememberDevice,
3136
- customUserAgentDetails
3137
- );
3138
-
3139
- try {
3140
- internalUser = await this._currentUserPoolUser(
3141
- undefined,
3142
- userAgentDetails
3143
- );
3144
- } catch (error) {
3145
- logger.debug('The user is not authenticated by the error', error);
3146
- return Promise.reject('The user is not authenticated');
3147
- }
3148
-
3149
- internalUser.getCachedDeviceKeyAndPassword();
3150
- return new Promise((res, rej) => {
3151
- internalUser.setDeviceStatusRemembered(
3152
- {
3153
- onSuccess: data => {
3154
- res(data);
3155
- },
3156
- onFailure: err => {
3157
- if (err.code === 'InvalidParameterException') {
3158
- rej(new AuthError(AuthErrorTypes.DeviceConfig));
3159
- } else if (err.code === 'NetworkError') {
3160
- rej(new AuthError(AuthErrorTypes.NetworkError));
3161
- } else {
3162
- rej(err);
3163
- }
3164
- },
3165
- },
3166
- getAmplifyUserAgent(userAgentDetails)
3167
- );
3168
- });
3169
- }
3170
-
3171
- public async forgetDevice(
3172
- customUserAgentDetails?: CustomUserAgentDetails
3173
- ): Promise<void> {
3174
- let internalUser: InternalCognitoUser | any;
3175
- const userAgentDetails = getAuthUserAgentDetails(
3176
- AuthAction.ForgetDevice,
3177
- customUserAgentDetails
3178
- );
3179
-
3180
- try {
3181
- internalUser = await this._currentUserPoolUser(
3182
- undefined,
3183
- userAgentDetails
3184
- );
3185
- } catch (error) {
3186
- logger.debug('The user is not authenticated by the error', error);
3187
- return Promise.reject('The user is not authenticated');
3188
- }
3189
-
3190
- internalUser.getCachedDeviceKeyAndPassword();
3191
- return new Promise((res, rej) => {
3192
- internalUser.forgetDevice(
3193
- {
3194
- onSuccess: data => {
3195
- res(data);
3196
- },
3197
- onFailure: err => {
3198
- if (err.code === 'InvalidParameterException') {
3199
- rej(new AuthError(AuthErrorTypes.DeviceConfig));
3200
- } else if (err.code === 'NetworkError') {
3201
- rej(new AuthError(AuthErrorTypes.NetworkError));
3202
- } else {
3203
- rej(err);
3204
- }
3205
- },
3206
- },
3207
- getAmplifyUserAgent(userAgentDetails)
3208
- );
3209
- });
3210
- }
3211
-
3212
- public async fetchDevices(
3213
- customUserAgentDetails?: CustomUserAgentDetails
3214
- ): Promise<IAuthDevice[]> {
3215
- let internalUser: InternalCognitoUser | any;
3216
- const userAgentDetails = getAuthUserAgentDetails(
3217
- AuthAction.FetchDevices,
3218
- customUserAgentDetails
3219
- );
3220
-
3221
- try {
3222
- internalUser = await this._currentUserPoolUser(
3223
- undefined,
3224
- userAgentDetails
3225
- );
3226
- } catch (error) {
3227
- logger.debug('The user is not authenticated by the error', error);
3228
- throw new Error('The user is not authenticated');
3229
- }
3230
-
3231
- internalUser.getCachedDeviceKeyAndPassword();
3232
- return new Promise((res, rej) => {
3233
- const cb = {
3234
- onSuccess(data) {
3235
- const deviceList: IAuthDevice[] = data.Devices.map(device => {
3236
- const deviceName =
3237
- device.DeviceAttributes.find(
3238
- ({ Name }) => Name === 'device_name'
3239
- ) || {};
3240
-
3241
- const deviceInfo: IAuthDevice = {
3242
- id: device.DeviceKey,
3243
- name: deviceName.Value,
3244
- };
3245
- return deviceInfo;
3246
- });
3247
- res(deviceList);
3248
- },
3249
- onFailure: err => {
3250
- if (err.code === 'InvalidParameterException') {
3251
- rej(new AuthError(AuthErrorTypes.DeviceConfig));
3252
- } else if (err.code === 'NetworkError') {
3253
- rej(new AuthError(AuthErrorTypes.NetworkError));
3254
- } else {
3255
- rej(err);
3256
- }
3257
- },
3258
- };
3259
- internalUser.listDevices(
3260
- MAX_DEVICES,
3261
- null,
3262
- cb,
3263
- getAmplifyUserAgent(userAgentDetails)
3264
- );
3265
- });
3266
- }
3267
- }
3268
-
3269
- export const InternalAuth = new InternalAuthClass(null);
3270
- Amplify.register(InternalAuth);