@auth0/auth0-spa-js 1.21.1 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/auth0-spa-js.development.js +132 -80
- package/dist/auth0-spa-js.development.js.map +1 -1
- package/dist/auth0-spa-js.production.esm.js +1 -1
- package/dist/auth0-spa-js.production.esm.js.map +1 -1
- package/dist/auth0-spa-js.production.js +1 -1
- package/dist/auth0-spa-js.production.js.map +1 -1
- package/dist/lib/auth0-spa-js.cjs.js +132 -80
- package/dist/lib/auth0-spa-js.cjs.js.map +1 -1
- package/dist/typings/Auth0Client.d.ts +1 -0
- package/dist/typings/constants.d.ts +1 -1
- package/dist/typings/errors.d.ts +5 -0
- package/dist/typings/global.d.ts +20 -0
- package/dist/typings/utils.d.ts +7 -0
- package/dist/typings/version.d.ts +1 -1
- package/package.json +2 -2
- package/src/Auth0Client.ts +24 -7
- package/src/constants.ts +1 -2
- package/src/errors.ts +15 -0
- package/src/global.ts +21 -0
- package/src/utils.ts +10 -0
- package/src/version.ts +1 -1
- package/src/worker/token.worker.ts +2 -2
|
@@ -17,6 +17,7 @@ export default class Auth0Client {
|
|
|
17
17
|
private readonly isAuthenticatedCookieName;
|
|
18
18
|
private readonly nowProvider;
|
|
19
19
|
private readonly httpTimeoutMs;
|
|
20
|
+
private readonly useRefreshTokensFallback;
|
|
20
21
|
cacheLocation: CacheLocation;
|
|
21
22
|
private worker;
|
|
22
23
|
constructor(options: Auth0ClientOptions);
|
|
@@ -24,7 +24,7 @@ export declare const CACHE_LOCATION_LOCAL_STORAGE = "localstorage";
|
|
|
24
24
|
/**
|
|
25
25
|
* @ignore
|
|
26
26
|
*/
|
|
27
|
-
export declare const MISSING_REFRESH_TOKEN_ERROR_MESSAGE = "
|
|
27
|
+
export declare const MISSING_REFRESH_TOKEN_ERROR_MESSAGE = "Missing Refresh Token";
|
|
28
28
|
/**
|
|
29
29
|
* @ignore
|
|
30
30
|
*/
|
package/dist/typings/errors.d.ts
CHANGED
|
@@ -48,3 +48,8 @@ export declare class MfaRequiredError extends GenericError {
|
|
|
48
48
|
mfa_token: string;
|
|
49
49
|
constructor(error: string, error_description: string, mfa_token: string);
|
|
50
50
|
}
|
|
51
|
+
export declare class MissingRefreshTokenError extends GenericError {
|
|
52
|
+
audience: string;
|
|
53
|
+
scope: string;
|
|
54
|
+
constructor(audience: string, scope: string);
|
|
55
|
+
}
|
package/dist/typings/global.d.ts
CHANGED
|
@@ -138,6 +138,26 @@ export interface Auth0ClientOptions extends BaseLoginOptions {
|
|
|
138
138
|
* **Note**: Use of refresh tokens must be enabled by an administrator on your Auth0 client application.
|
|
139
139
|
*/
|
|
140
140
|
useRefreshTokens?: boolean;
|
|
141
|
+
/**
|
|
142
|
+
* If true, fallback to the technique of using a hidden iframe and the `authorization_code` grant with `prompt=none` when unable to use refresh tokens.
|
|
143
|
+
* The default setting is `true`.
|
|
144
|
+
*
|
|
145
|
+
* **Note**: There might be situations where doing silent auth with a Web Message response from an iframe is not possible,
|
|
146
|
+
* like when you're serving your application from the file system or a custom protocol (like in a Desktop or Native app).
|
|
147
|
+
* In situations like this you can disable the iframe fallback and handle the failed Refresh Grant and prompt the user to login interactively with `loginWithRedirect` or `loginWithPopup`."
|
|
148
|
+
*
|
|
149
|
+
* E.g. Using the `file:` protocol in an Electron application does not support that legacy technique.
|
|
150
|
+
*
|
|
151
|
+
* let token: string;
|
|
152
|
+
* try {
|
|
153
|
+
* token = await auth0.getTokenSilently();
|
|
154
|
+
* } catch (e) {
|
|
155
|
+
* if (e.error === 'missing_refresh_token' || e.error === 'invalid_grant') {
|
|
156
|
+
* auth0.loginWithRedirect();
|
|
157
|
+
* }
|
|
158
|
+
* }
|
|
159
|
+
*/
|
|
160
|
+
useRefreshTokensFallback?: boolean;
|
|
141
161
|
/**
|
|
142
162
|
* A maximum number of seconds to wait before declaring background calls to /authorize as failed for timeout
|
|
143
163
|
* Defaults to 60s.
|
package/dist/typings/utils.d.ts
CHANGED
|
@@ -13,3 +13,10 @@ export declare const sha256: (s: string) => Promise<any>;
|
|
|
13
13
|
export declare const urlDecodeB64: (input: string) => string;
|
|
14
14
|
export declare const bufferToBase64UrlEncoded: (input: number[] | Uint8Array) => string;
|
|
15
15
|
export declare const validateCrypto: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Returns an empty string when value is falsy, or when it's value is included in the exclude argument.
|
|
18
|
+
* @param value The value to check
|
|
19
|
+
* @param exclude An array of values that should result in an empty string.
|
|
20
|
+
* @returns The value, or an empty string when falsy or included in the exclude argument.
|
|
21
|
+
*/
|
|
22
|
+
export declare function valueOrEmptyString(value: string, exclude?: string[]): string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "1.
|
|
1
|
+
declare const _default: "1.22.0";
|
|
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.
|
|
6
|
+
"version": "1.22.0",
|
|
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",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"dependencies": {
|
|
82
82
|
"abortcontroller-polyfill": "^1.7.3",
|
|
83
83
|
"browser-tabs-lock": "^1.2.15",
|
|
84
|
-
"core-js": "^3.22.
|
|
84
|
+
"core-js": "^3.22.4",
|
|
85
85
|
"es-cookie": "^1.3.2",
|
|
86
86
|
"fast-text-encoding": "^1.0.3",
|
|
87
87
|
"promise-polyfill": "^8.2.3",
|
package/src/Auth0Client.ts
CHANGED
|
@@ -27,7 +27,12 @@ import {
|
|
|
27
27
|
|
|
28
28
|
import TransactionManager from './transaction-manager';
|
|
29
29
|
import { verify as verifyIdToken } from './jwt';
|
|
30
|
-
import {
|
|
30
|
+
import {
|
|
31
|
+
AuthenticationError,
|
|
32
|
+
GenericError,
|
|
33
|
+
MissingRefreshTokenError,
|
|
34
|
+
TimeoutError
|
|
35
|
+
} from './errors';
|
|
31
36
|
|
|
32
37
|
import {
|
|
33
38
|
ClientStorage,
|
|
@@ -202,6 +207,7 @@ export default class Auth0Client {
|
|
|
202
207
|
private readonly isAuthenticatedCookieName: string;
|
|
203
208
|
private readonly nowProvider: () => number | Promise<number>;
|
|
204
209
|
private readonly httpTimeoutMs: number;
|
|
210
|
+
private readonly useRefreshTokensFallback: boolean;
|
|
205
211
|
|
|
206
212
|
cacheLocation: CacheLocation;
|
|
207
213
|
private worker: Worker;
|
|
@@ -299,6 +305,9 @@ export default class Auth0Client {
|
|
|
299
305
|
}
|
|
300
306
|
|
|
301
307
|
this.customOptions = getCustomInitialOptions(options);
|
|
308
|
+
|
|
309
|
+
this.useRefreshTokensFallback =
|
|
310
|
+
this.options.useRefreshTokensFallback !== false;
|
|
302
311
|
}
|
|
303
312
|
|
|
304
313
|
private _url(path: string) {
|
|
@@ -1183,7 +1192,14 @@ export default class Auth0Client {
|
|
|
1183
1192
|
// and you don't have a refresh token in web worker memory
|
|
1184
1193
|
// fallback to an iframe.
|
|
1185
1194
|
if ((!cache || !cache.refresh_token) && !this.worker) {
|
|
1186
|
-
|
|
1195
|
+
if (this.useRefreshTokensFallback) {
|
|
1196
|
+
return await this._getTokenFromIFrame(options);
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
throw new MissingRefreshTokenError(
|
|
1200
|
+
options.audience || 'default',
|
|
1201
|
+
options.scope
|
|
1202
|
+
);
|
|
1187
1203
|
}
|
|
1188
1204
|
|
|
1189
1205
|
const redirect_uri =
|
|
@@ -1230,11 +1246,12 @@ export default class Auth0Client {
|
|
|
1230
1246
|
if (
|
|
1231
1247
|
// The web worker didn't have a refresh token in memory so
|
|
1232
1248
|
// fallback to an iframe.
|
|
1233
|
-
e.message
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1249
|
+
(e.message.indexOf(MISSING_REFRESH_TOKEN_ERROR_MESSAGE) > -1 ||
|
|
1250
|
+
// A refresh token was found, but is it no longer valid.
|
|
1251
|
+
// Fallback to an iframe.
|
|
1252
|
+
(e.message &&
|
|
1253
|
+
e.message.indexOf(INVALID_REFRESH_TOKEN_ERROR_MESSAGE) > -1)) &&
|
|
1254
|
+
this.useRefreshTokensFallback
|
|
1238
1255
|
) {
|
|
1239
1256
|
return await this._getTokenFromIFrame(options);
|
|
1240
1257
|
}
|
package/src/constants.ts
CHANGED
|
@@ -34,8 +34,7 @@ export const CACHE_LOCATION_LOCAL_STORAGE = 'localstorage';
|
|
|
34
34
|
/**
|
|
35
35
|
* @ignore
|
|
36
36
|
*/
|
|
37
|
-
export const MISSING_REFRESH_TOKEN_ERROR_MESSAGE =
|
|
38
|
-
'The web worker is missing the refresh token';
|
|
37
|
+
export const MISSING_REFRESH_TOKEN_ERROR_MESSAGE = 'Missing Refresh Token';
|
|
39
38
|
|
|
40
39
|
/**
|
|
41
40
|
* @ignore
|
package/src/errors.ts
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* https://github.com/gotwarlost/istanbul/issues/690
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { valueOrEmptyString } from './utils';
|
|
7
|
+
|
|
6
8
|
/**
|
|
7
9
|
* Thrown when network requests to the Auth server fail.
|
|
8
10
|
*/
|
|
@@ -91,3 +93,16 @@ export class MfaRequiredError extends GenericError {
|
|
|
91
93
|
Object.setPrototypeOf(this, MfaRequiredError.prototype);
|
|
92
94
|
}
|
|
93
95
|
}
|
|
96
|
+
|
|
97
|
+
export class MissingRefreshTokenError extends GenericError {
|
|
98
|
+
/* istanbul ignore next */
|
|
99
|
+
constructor(public audience: string, public scope: string) {
|
|
100
|
+
super(
|
|
101
|
+
'missing_refresh_token',
|
|
102
|
+
`Missing Refresh Token (audience: '${valueOrEmptyString(audience, [
|
|
103
|
+
'default'
|
|
104
|
+
])}', scope: '${valueOrEmptyString(scope)}')`
|
|
105
|
+
);
|
|
106
|
+
Object.setPrototypeOf(this, MissingRefreshTokenError.prototype);
|
|
107
|
+
}
|
|
108
|
+
}
|
package/src/global.ts
CHANGED
|
@@ -158,6 +158,27 @@ export interface Auth0ClientOptions extends BaseLoginOptions {
|
|
|
158
158
|
*/
|
|
159
159
|
useRefreshTokens?: boolean;
|
|
160
160
|
|
|
161
|
+
/**
|
|
162
|
+
* If true, fallback to the technique of using a hidden iframe and the `authorization_code` grant with `prompt=none` when unable to use refresh tokens.
|
|
163
|
+
* The default setting is `true`.
|
|
164
|
+
*
|
|
165
|
+
* **Note**: There might be situations where doing silent auth with a Web Message response from an iframe is not possible,
|
|
166
|
+
* like when you're serving your application from the file system or a custom protocol (like in a Desktop or Native app).
|
|
167
|
+
* In situations like this you can disable the iframe fallback and handle the failed Refresh Grant and prompt the user to login interactively with `loginWithRedirect` or `loginWithPopup`."
|
|
168
|
+
*
|
|
169
|
+
* E.g. Using the `file:` protocol in an Electron application does not support that legacy technique.
|
|
170
|
+
*
|
|
171
|
+
* let token: string;
|
|
172
|
+
* try {
|
|
173
|
+
* token = await auth0.getTokenSilently();
|
|
174
|
+
* } catch (e) {
|
|
175
|
+
* if (e.error === 'missing_refresh_token' || e.error === 'invalid_grant') {
|
|
176
|
+
* auth0.loginWithRedirect();
|
|
177
|
+
* }
|
|
178
|
+
* }
|
|
179
|
+
*/
|
|
180
|
+
useRefreshTokensFallback?: boolean;
|
|
181
|
+
|
|
161
182
|
/**
|
|
162
183
|
* A maximum number of seconds to wait before declaring background calls to /authorize as failed for timeout
|
|
163
184
|
* Defaults to 60s.
|
package/src/utils.ts
CHANGED
|
@@ -241,3 +241,13 @@ export const validateCrypto = () => {
|
|
|
241
241
|
`);
|
|
242
242
|
}
|
|
243
243
|
};
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Returns an empty string when value is falsy, or when it's value is included in the exclude argument.
|
|
247
|
+
* @param value The value to check
|
|
248
|
+
* @param exclude An array of values that should result in an empty string.
|
|
249
|
+
* @returns The value, or an empty string when falsy or included in the exclude argument.
|
|
250
|
+
*/
|
|
251
|
+
export function valueOrEmptyString(value: string, exclude: string[] = []) {
|
|
252
|
+
return value && !exclude.includes(value) ? value : '';
|
|
253
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '1.
|
|
1
|
+
export default '1.22.0';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MissingRefreshTokenError } from '../errors';
|
|
2
2
|
import { WorkerRefreshTokenMessage } from './worker.types';
|
|
3
3
|
|
|
4
4
|
let refreshTokens: Record<string, string> = {};
|
|
@@ -50,7 +50,7 @@ const messageHandler = async ({
|
|
|
50
50
|
const refreshToken = getRefreshToken(audience, scope);
|
|
51
51
|
|
|
52
52
|
if (!refreshToken) {
|
|
53
|
-
throw new
|
|
53
|
+
throw new MissingRefreshTokenError(audience, scope);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
fetchOptions.body = useFormData
|