@auth0/auth0-spa-js 1.19.2 → 1.19.3

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.
@@ -90,7 +90,7 @@ export default class Auth0Client {
90
90
  *
91
91
  * @param options
92
92
  */
93
- getIdTokenClaims(options?: GetIdTokenClaimsOptions): Promise<IdToken>;
93
+ getIdTokenClaims(options?: GetIdTokenClaimsOptions): Promise<IdToken | undefined>;
94
94
  /**
95
95
  * ```js
96
96
  * await auth0.loginWithRedirect(options);
@@ -102,14 +102,14 @@ export default class Auth0Client {
102
102
  *
103
103
  * @param options
104
104
  */
105
- loginWithRedirect(options?: RedirectLoginOptions): Promise<void>;
105
+ loginWithRedirect<TAppState = any>(options?: RedirectLoginOptions<TAppState>): Promise<void>;
106
106
  /**
107
107
  * After the browser redirects back to the callback page,
108
108
  * call `handleRedirectCallback` to handle success and error
109
109
  * responses from Auth0. If the response is successful, results
110
110
  * will be valid according to their expiration times.
111
111
  */
112
- handleRedirectCallback(url?: string): Promise<RedirectLoginResult>;
112
+ handleRedirectCallback<TAppState = any>(url?: string): Promise<RedirectLoginResult<TAppState>>;
113
113
  /**
114
114
  * ```js
115
115
  * await auth0.checkSession();
@@ -127,6 +127,12 @@ export default class Auth0Client {
127
127
  * `Auth0Client` constructor. You should not need this if you are using the
128
128
  * `createAuth0Client` factory.
129
129
  *
130
+ * **Note:** the cookie **may not** be present if running an app using a private tab, as some
131
+ * browsers clear JS cookie data and local storage when the tab or page is closed, or on page reload. This effectively
132
+ * means that `checkSession` could silently return without authenticating the user on page refresh when
133
+ * using a private tab, despite having previously logged in. As a workaround, use `getTokenSilently` instead
134
+ * and handle the possible `login_required` error [as shown in the readme](https://github.com/auth0/auth0-spa-js#creating-the-client).
135
+ *
130
136
  * @param options
131
137
  */
132
138
  checkSession(options?: GetTokenSilentlyOptions): Promise<void>;
@@ -213,7 +213,7 @@ export interface AuthorizeOptions extends BaseLoginOptions {
213
213
  code_challenge: string;
214
214
  code_challenge_method: string;
215
215
  }
216
- export interface RedirectLoginOptions extends BaseLoginOptions {
216
+ export interface RedirectLoginOptions<TAppState = any> extends BaseLoginOptions {
217
217
  /**
218
218
  * The URL where Auth0 will redirect your browser to with
219
219
  * the authentication result. It must be whitelisted in
@@ -224,7 +224,7 @@ export interface RedirectLoginOptions extends BaseLoginOptions {
224
224
  /**
225
225
  * Used to store state before doing the redirect
226
226
  */
227
- appState?: any;
227
+ appState?: TAppState;
228
228
  /**
229
229
  * Used to add to the URL fragment before redirecting
230
230
  */
@@ -234,11 +234,11 @@ export interface RedirectLoginOptions extends BaseLoginOptions {
234
234
  */
235
235
  redirectMethod?: 'replace' | 'assign';
236
236
  }
237
- export interface RedirectLoginResult {
237
+ export interface RedirectLoginResult<TAppState = any> {
238
238
  /**
239
239
  * State stored when the redirect request was made
240
240
  */
241
- appState?: any;
241
+ appState?: TAppState;
242
242
  }
243
243
  export interface PopupLoginOptions extends BaseLoginOptions {
244
244
  }
@@ -12,6 +12,15 @@ import Auth0Client from './Auth0Client';
12
12
  import { Auth0ClientOptions } from './global';
13
13
  import './global';
14
14
  export * from './global';
15
+ /**
16
+ * Asynchronously creates the Auth0Client instance and calls `checkSession`.
17
+ *
18
+ * **Note:** There are caveats to using this in a private browser tab, which may not silently authenticae
19
+ * a user on page refresh. Please see [the checkSession docs](https://auth0.github.io/auth0-spa-js/classes/auth0client.html#checksession) for more info.
20
+ *
21
+ * @param options The client options
22
+ * @returns An instance of Auth0Client
23
+ */
15
24
  export default function createAuth0Client(options: Auth0ClientOptions): Promise<Auth0Client>;
16
25
  export { Auth0Client };
17
26
  export { GenericError, AuthenticationError, TimeoutError, PopupTimeoutError, PopupCancelledError, MfaRequiredError } from './errors';
@@ -5,7 +5,7 @@ interface ClientStorageOptions {
5
5
  * Defines a type that handles storage to/from a storage location
6
6
  */
7
7
  export declare type ClientStorage = {
8
- get<T extends Object>(key: string): T;
8
+ get<T extends Object>(key: string): T | undefined;
9
9
  save(key: string, value: any, options?: ClientStorageOptions): void;
10
10
  remove(key: string): void;
11
11
  };
@@ -7,6 +7,7 @@ interface Transaction {
7
7
  code_verifier: string;
8
8
  redirect_uri: string;
9
9
  organizationId?: string;
10
+ state?: string;
10
11
  }
11
12
  export default class TransactionManager {
12
13
  private storage;
@@ -15,7 +16,7 @@ export default class TransactionManager {
15
16
  private storageKey;
16
17
  constructor(storage: ClientStorage, clientId: string);
17
18
  create(transaction: Transaction): void;
18
- get(): Transaction;
19
+ get(): Transaction | undefined;
19
20
  remove(): void;
20
21
  }
21
22
  export {};
@@ -1,2 +1,2 @@
1
- declare const _default: "1.19.2";
1
+ declare const _default: "1.19.3";
2
2
  export default _default;
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "name": "@auth0/auth0-spa-js",
4
4
  "description": "Auth0 SDK for Single Page Applications using Authorization Code Grant Flow with PKCE",
5
5
  "license": "MIT",
6
- "version": "1.19.2",
6
+ "version": "1.19.3",
7
7
  "main": "dist/lib/auth0-spa-js.cjs.js",
8
8
  "types": "dist/typings/index.d.ts",
9
9
  "module": "dist/auth0-spa-js.production.esm.js",
@@ -21,7 +21,7 @@
21
21
  "test:watch:integration": "concurrently --raw npm:dev 'npm:test:open:integration'",
22
22
  "test:es-check": "npm run test:es-check:es5 && npm run test:es-check:es2015:module",
23
23
  "test:es-check:es5": "es-check es5 'dist/auth0-spa-js.production.js'",
24
- "test:es-check:es2015:module": "es-check es2015 --module 'dist/auth0-spa-js.production.esm.js'",
24
+ "test:es-check:es2015:module": "es-check es2015 'dist/auth0-spa-js.production.esm.js' --module ",
25
25
  "test:integration:server": "npm run dev",
26
26
  "test:integration:tests": "wait-on http://localhost:3000/ && cypress run",
27
27
  "test:integration": "concurrently --raw --kill-others --success first npm:test:integration:server npm:test:integration:tests",
@@ -38,27 +38,27 @@
38
38
  "@types/jest": "^27.0.2",
39
39
  "@typescript-eslint/eslint-plugin-tslint": "^4.33.0",
40
40
  "@typescript-eslint/parser": "^4.33.0",
41
- "browserstack-cypress-cli": "^1.10.1",
41
+ "browserstack-cypress-cli": "1.8.1",
42
42
  "cli-table": "^0.3.6",
43
43
  "codecov": "^3.8.3",
44
- "concurrently": "^6.3.0",
44
+ "concurrently": "^6.4.0",
45
45
  "cypress": "7.2.0",
46
- "es-check": "^6.0.0",
46
+ "es-check": "^6.1.1",
47
47
  "eslint": "^7.32.0",
48
48
  "gzip-size": "^6.0.0",
49
- "husky": "^7.0.2",
50
- "idtoken-verifier": "^2.2.1",
51
- "jest": "^27.2.4",
49
+ "husky": "^7.0.4",
50
+ "idtoken-verifier": "^2.2.2",
51
+ "jest": "^27.3.1",
52
52
  "jest-junit": "^13.0.0",
53
53
  "jest-localstorage-mock": "^2.4.18",
54
54
  "jsonwebtoken": "^8.5.1",
55
- "oidc-provider": "^7.8.0",
55
+ "oidc-provider": "^7.10.1",
56
56
  "pem": "^1.14.4",
57
57
  "prettier": "^2.4.1",
58
- "pretty-quick": "^3.1.1",
58
+ "pretty-quick": "^3.1.2",
59
59
  "qss": "^2.0.3",
60
60
  "rimraf": "^3.0.2",
61
- "rollup": "^2.58.0",
61
+ "rollup": "^2.60.0",
62
62
  "rollup-plugin-analyzer": "^4.0.0",
63
63
  "rollup-plugin-commonjs": "^10.1.0",
64
64
  "rollup-plugin-dev": "^1.1.3",
@@ -70,21 +70,21 @@
70
70
  "rollup-plugin-visualizer": "^5.5.2",
71
71
  "rollup-plugin-web-worker-loader": "^1.6.1",
72
72
  "serve": "^12.0.1",
73
- "ts-jest": "^27.0.5",
73
+ "ts-jest": "^27.0.7",
74
74
  "tslib": "^2.3.1",
75
75
  "tslint": "^6.1.3",
76
76
  "tslint-config-security": "^1.16.0",
77
77
  "typedoc": "0.18.0",
78
- "typescript": "^4.4.3",
78
+ "typescript": "^4.4.4",
79
79
  "wait-on": "^6.0.0"
80
80
  },
81
81
  "dependencies": {
82
82
  "abortcontroller-polyfill": "^1.7.3",
83
83
  "browser-tabs-lock": "^1.2.15",
84
- "core-js": "^3.18.2",
84
+ "core-js": "^3.19.0",
85
85
  "es-cookie": "^1.3.2",
86
86
  "fast-text-encoding": "^1.0.3",
87
- "promise-polyfill": "^8.2.0",
87
+ "promise-polyfill": "^8.2.1",
88
88
  "unfetch": "^4.2.0"
89
89
  },
90
90
  "files": [
@@ -309,20 +309,28 @@ export default class Auth0Client {
309
309
  code_challenge: string,
310
310
  redirect_uri: string
311
311
  ): AuthorizeOptions {
312
+ // These options should be excluded from the authorize URL,
313
+ // as they're options for the client and not for the IdP.
314
+ // ** IMPORTANT ** If adding a new client option, include it in this destructure list.
312
315
  const {
313
- domain,
314
- leeway,
315
316
  useRefreshTokens,
316
317
  useCookiesForTransactions,
317
318
  useFormData,
318
319
  auth0Client,
319
320
  cacheLocation,
320
321
  advancedOptions,
321
- ...withoutClientOptions
322
+ detailedResponse,
323
+ nowProvider,
324
+ authorizeTimeoutInSeconds,
325
+ legacySameSiteCookie,
326
+ sessionCheckExpiryDays,
327
+ domain,
328
+ leeway,
329
+ ...loginOptions
322
330
  } = this.options;
323
331
 
324
332
  return {
325
- ...withoutClientOptions,
333
+ ...loginOptions,
326
334
  ...authorizeOptions,
327
335
  scope: getUniqueScopes(
328
336
  this.defaultScope,
@@ -338,6 +346,7 @@ export default class Auth0Client {
338
346
  code_challenge_method: 'S256'
339
347
  };
340
348
  }
349
+
341
350
  private _authorizeUrl(authorizeOptions: AuthorizeOptions) {
342
351
  return this._url(`/authorize?${createQueryParams(authorizeOptions)}`);
343
352
  }
@@ -417,6 +426,7 @@ export default class Auth0Client {
417
426
  scope: params.scope,
418
427
  audience: params.audience || 'default',
419
428
  redirect_uri: params.redirect_uri,
429
+ state: stateIn,
420
430
  ...(organizationId && { organizationId })
421
431
  });
422
432
 
@@ -579,7 +589,7 @@ export default class Auth0Client {
579
589
  */
580
590
  public async getIdTokenClaims(
581
591
  options: GetIdTokenClaimsOptions = {}
582
- ): Promise<IdToken> {
592
+ ): Promise<IdToken | undefined> {
583
593
  const audience = options.audience || this.options.audience || 'default';
584
594
  const scope = getUniqueScopes(this.defaultScope, this.scope, options.scope);
585
595
 
@@ -605,7 +615,9 @@ export default class Auth0Client {
605
615
  *
606
616
  * @param options
607
617
  */
608
- public async loginWithRedirect(options: RedirectLoginOptions = {}) {
618
+ public async loginWithRedirect<TAppState = any>(
619
+ options: RedirectLoginOptions<TAppState> = {}
620
+ ) {
609
621
  const { redirectMethod, ...urlOptions } = options;
610
622
  const url = await this.buildAuthorizeUrl(urlOptions);
611
623
  window.location[redirectMethod || 'assign'](url);
@@ -617,9 +629,9 @@ export default class Auth0Client {
617
629
  * responses from Auth0. If the response is successful, results
618
630
  * will be valid according to their expiration times.
619
631
  */
620
- public async handleRedirectCallback(
632
+ public async handleRedirectCallback<TAppState = any>(
621
633
  url: string = window.location.href
622
- ): Promise<RedirectLoginResult> {
634
+ ): Promise<RedirectLoginResult<TAppState>> {
623
635
  const queryStringFragments = url.split('?').slice(1);
624
636
 
625
637
  if (queryStringFragments.length === 0) {
@@ -632,8 +644,7 @@ export default class Auth0Client {
632
644
 
633
645
  const transaction = this.transactionManager.get();
634
646
 
635
- // Transaction should have a `code_verifier` to do PKCE for CSRF protection
636
- if (!transaction || !transaction.code_verifier) {
647
+ if (!transaction) {
637
648
  throw new Error('Invalid state');
638
649
  }
639
650
 
@@ -648,6 +659,14 @@ export default class Auth0Client {
648
659
  );
649
660
  }
650
661
 
662
+ // Transaction should have a `code_verifier` to do PKCE for CSRF protection
663
+ if (
664
+ !transaction.code_verifier ||
665
+ (transaction.state && transaction.state !== state)
666
+ ) {
667
+ throw new Error('Invalid state');
668
+ }
669
+
651
670
  const tokenOptions = {
652
671
  audience: transaction.audience,
653
672
  scope: transaction.scope,
@@ -678,6 +697,7 @@ export default class Auth0Client {
678
697
  decodedToken,
679
698
  audience: transaction.audience,
680
699
  scope: transaction.scope,
700
+ ...(authResult.scope ? { oauthTokenScope: authResult.scope } : null),
681
701
  client_id: this.options.client_id
682
702
  });
683
703
 
@@ -709,6 +729,12 @@ export default class Auth0Client {
709
729
  * `Auth0Client` constructor. You should not need this if you are using the
710
730
  * `createAuth0Client` factory.
711
731
  *
732
+ * **Note:** the cookie **may not** be present if running an app using a private tab, as some
733
+ * browsers clear JS cookie data and local storage when the tab or page is closed, or on page reload. This effectively
734
+ * means that `checkSession` could silently return without authenticating the user on page refresh when
735
+ * using a private tab, despite having previously logged in. As a workaround, use `getTokenSilently` instead
736
+ * and handle the possible `login_required` error [as shown in the readme](https://github.com/auth0/auth0-spa-js#creating-the-client).
737
+ *
712
738
  * @param options
713
739
  */
714
740
  public async checkSession(options?: GetTokenSilentlyOptions) {
@@ -856,12 +882,8 @@ export default class Auth0Client {
856
882
  });
857
883
 
858
884
  if (options.detailedResponse) {
859
- const {
860
- id_token,
861
- access_token,
862
- oauthTokenScope,
863
- expires_in
864
- } = authResult;
885
+ const { id_token, access_token, oauthTokenScope, expires_in } =
886
+ authResult;
865
887
 
866
888
  return {
867
889
  id_token,
@@ -1015,8 +1037,10 @@ export default class Auth0Client {
1015
1037
  const code_challengeBuffer = await sha256(code_verifier);
1016
1038
  const code_challenge = bufferToBase64UrlEncoded(code_challengeBuffer);
1017
1039
 
1040
+ const { detailedResponse, ...withoutClientOptions } = options;
1041
+
1018
1042
  const params = this._getParams(
1019
- options,
1043
+ withoutClientOptions,
1020
1044
  stateIn,
1021
1045
  nonceIn,
1022
1046
  code_challenge,
@@ -1063,6 +1087,7 @@ export default class Auth0Client {
1063
1087
  redirect_uri,
1064
1088
  ignoreCache,
1065
1089
  timeoutInSeconds,
1090
+ detailedResponse,
1066
1091
  ...customOptions
1067
1092
  } = options;
1068
1093
 
@@ -1144,6 +1169,7 @@ export default class Auth0Client {
1144
1169
  audience,
1145
1170
  ignoreCache,
1146
1171
  timeoutInSeconds,
1172
+ detailedResponse,
1147
1173
  ...customOptions
1148
1174
  } = options;
1149
1175
 
package/src/global.ts CHANGED
@@ -240,7 +240,8 @@ export interface AuthorizeOptions extends BaseLoginOptions {
240
240
  code_challenge_method: string;
241
241
  }
242
242
 
243
- export interface RedirectLoginOptions extends BaseLoginOptions {
243
+ export interface RedirectLoginOptions<TAppState = any>
244
+ extends BaseLoginOptions {
244
245
  /**
245
246
  * The URL where Auth0 will redirect your browser to with
246
247
  * the authentication result. It must be whitelisted in
@@ -251,7 +252,7 @@ export interface RedirectLoginOptions extends BaseLoginOptions {
251
252
  /**
252
253
  * Used to store state before doing the redirect
253
254
  */
254
- appState?: any;
255
+ appState?: TAppState;
255
256
  /**
256
257
  * Used to add to the URL fragment before redirecting
257
258
  */
@@ -262,11 +263,11 @@ export interface RedirectLoginOptions extends BaseLoginOptions {
262
263
  redirectMethod?: 'replace' | 'assign';
263
264
  }
264
265
 
265
- export interface RedirectLoginResult {
266
+ export interface RedirectLoginResult<TAppState = any> {
266
267
  /**
267
268
  * State stored when the redirect request was made
268
269
  */
269
- appState?: any;
270
+ appState?: TAppState;
270
271
  }
271
272
 
272
273
  export interface PopupLoginOptions extends BaseLoginOptions {}
package/src/index.ts CHANGED
@@ -16,6 +16,15 @@ import './global';
16
16
 
17
17
  export * from './global';
18
18
 
19
+ /**
20
+ * Asynchronously creates the Auth0Client instance and calls `checkSession`.
21
+ *
22
+ * **Note:** There are caveats to using this in a private browser tab, which may not silently authenticae
23
+ * a user on page refresh. Please see [the checkSession docs](https://auth0.github.io/auth0-spa-js/classes/auth0client.html#checksession) for more info.
24
+ *
25
+ * @param options The client options
26
+ * @returns An instance of Auth0Client
27
+ */
19
28
  export default async function createAuth0Client(options: Auth0ClientOptions) {
20
29
  const auth0 = new Auth0Client(options);
21
30
  await auth0.checkSession();
package/src/storage.ts CHANGED
@@ -8,7 +8,7 @@ interface ClientStorageOptions {
8
8
  * Defines a type that handles storage to/from a storage location
9
9
  */
10
10
  export type ClientStorage = {
11
- get<T extends Object>(key: string): T;
11
+ get<T extends Object>(key: string): T | undefined;
12
12
  save(key: string, value: any, options?: ClientStorageOptions): void;
13
13
  remove(key: string): void;
14
14
  };
@@ -10,14 +10,15 @@ interface Transaction {
10
10
  code_verifier: string;
11
11
  redirect_uri: string;
12
12
  organizationId?: string;
13
+ state?: string;
13
14
  }
14
15
 
15
16
  export default class TransactionManager {
16
- private transaction: Transaction;
17
+ private transaction: Transaction | undefined;
17
18
  private storageKey: string;
18
19
 
19
20
  constructor(private storage: ClientStorage, private clientId: string) {
20
- this.storageKey = `${TRANSACTION_STORAGE_KEY_PREFIX}.${clientId}`;
21
+ this.storageKey = `${TRANSACTION_STORAGE_KEY_PREFIX}.${this.clientId}`;
21
22
  this.transaction = this.storage.get(this.storageKey);
22
23
  }
23
24
 
@@ -29,7 +30,7 @@ export default class TransactionManager {
29
30
  });
30
31
  }
31
32
 
32
- public get(): Transaction {
33
+ public get(): Transaction | undefined {
33
34
  return this.transaction;
34
35
  }
35
36
 
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export default '1.19.2';
1
+ export default '1.19.3';