@auth0/auth0-spa-js 2.7.0 → 2.8.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 +4 -3
- package/dist/auth0-spa-js.development.js +91 -25
- 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/auth0-spa-js.worker.development.js.map +1 -1
- package/dist/auth0-spa-js.worker.production.js.map +1 -1
- package/dist/lib/auth0-spa-js.cjs.js +97 -25
- package/dist/lib/auth0-spa-js.cjs.js.map +1 -1
- package/dist/typings/Auth0Client.d.ts +2 -1
- package/dist/typings/Auth0Client.utils.d.ts +9 -3
- package/dist/typings/cache/cache-manager.d.ts +1 -0
- package/dist/typings/constants.d.ts +1 -0
- package/dist/typings/global.d.ts +9 -1
- package/dist/typings/scope.d.ts +25 -0
- package/dist/typings/utils.d.ts +6 -0
- package/dist/typings/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/Auth0Client.ts +72 -33
- package/src/Auth0Client.utils.ts +14 -5
- package/src/api.ts +5 -6
- package/src/cache/cache-manager.ts +14 -0
- package/src/constants.ts +2 -0
- package/src/global.ts +11 -1
- package/src/scope.ts +57 -0
- package/src/utils.ts +36 -0
- package/src/version.ts +1 -1
|
@@ -22,6 +22,7 @@ export declare class Auth0Client {
|
|
|
22
22
|
private readonly userCache;
|
|
23
23
|
private readonly myAccountApi;
|
|
24
24
|
private worker?;
|
|
25
|
+
private readonly activeLockKeys;
|
|
25
26
|
private readonly defaultOptions;
|
|
26
27
|
constructor(options: Auth0ClientOptions);
|
|
27
28
|
private _url;
|
|
@@ -207,7 +208,7 @@ export declare class Auth0Client {
|
|
|
207
208
|
private _getIdTokenFromCache;
|
|
208
209
|
private _getEntryFromCache;
|
|
209
210
|
/**
|
|
210
|
-
* Releases any
|
|
211
|
+
* Releases any locks acquired by the current page that are not released yet
|
|
211
212
|
*
|
|
212
213
|
* Get's called on the `pagehide` event.
|
|
213
214
|
* https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import { ICache } from './cache';
|
|
2
|
-
import { Auth0ClientOptions, AuthorizationParams, AuthorizeOptions, LogoutOptions } from './global';
|
|
2
|
+
import { Auth0ClientOptions, AuthorizationParams, AuthorizeOptions, ClientAuthorizationParams, LogoutOptions } from './global';
|
|
3
3
|
/**
|
|
4
4
|
* @ignore
|
|
5
5
|
*/
|
|
6
6
|
export declare const GET_TOKEN_SILENTLY_LOCK_KEY = "auth0.lock.getTokenSilently";
|
|
7
|
+
/**
|
|
8
|
+
* @ignore
|
|
9
|
+
*/
|
|
10
|
+
export declare const buildGetTokenSilentlyLockKey: (clientId: string, audience: string) => string;
|
|
7
11
|
/**
|
|
8
12
|
* @ignore
|
|
9
13
|
*/
|
|
@@ -24,8 +28,10 @@ export declare const cacheFactory: (location: string) => () => ICache;
|
|
|
24
28
|
* @ignore
|
|
25
29
|
*/
|
|
26
30
|
export declare const getAuthorizeParams: (clientOptions: Auth0ClientOptions & {
|
|
27
|
-
authorizationParams:
|
|
28
|
-
}, scope: string, authorizationParams: AuthorizationParams
|
|
31
|
+
authorizationParams: ClientAuthorizationParams;
|
|
32
|
+
}, scope: Record<string, string>, authorizationParams: AuthorizationParams & {
|
|
33
|
+
scope?: string | undefined;
|
|
34
|
+
}, state: string, nonce: string, code_challenge: string, redirect_uri: string | undefined, response_mode: string | undefined, thumbprint: string | undefined) => AuthorizeOptions;
|
|
29
35
|
/**
|
|
30
36
|
* @ignore
|
|
31
37
|
*
|
|
@@ -10,6 +10,7 @@ export declare class CacheManager {
|
|
|
10
10
|
get(cacheKey: CacheKey, expiryAdjustmentSeconds?: number, useMrrt?: boolean, cacheMode?: string): Promise<Partial<CacheEntry> | undefined>;
|
|
11
11
|
private modifiedCachedEntry;
|
|
12
12
|
set(entry: CacheEntry): Promise<void>;
|
|
13
|
+
remove(client_id: string, audience?: string, scope?: string): Promise<void>;
|
|
13
14
|
clear(clientId?: string): Promise<void>;
|
|
14
15
|
private wrapCacheEntry;
|
|
15
16
|
private getCacheKeys;
|
package/dist/typings/global.d.ts
CHANGED
|
@@ -97,6 +97,9 @@ export interface AuthorizationParams {
|
|
|
97
97
|
*/
|
|
98
98
|
[key: string]: any;
|
|
99
99
|
}
|
|
100
|
+
export interface ClientAuthorizationParams extends Omit<AuthorizationParams, 'scope'> {
|
|
101
|
+
scope?: string | Record<string, string>;
|
|
102
|
+
}
|
|
100
103
|
interface BaseLoginOptions {
|
|
101
104
|
/**
|
|
102
105
|
* URL parameters that will be sent back to the Authorization Server. This can be known parameters
|
|
@@ -104,7 +107,7 @@ interface BaseLoginOptions {
|
|
|
104
107
|
*/
|
|
105
108
|
authorizationParams?: AuthorizationParams;
|
|
106
109
|
}
|
|
107
|
-
export interface Auth0ClientOptions
|
|
110
|
+
export interface Auth0ClientOptions {
|
|
108
111
|
/**
|
|
109
112
|
* Your Auth0 account domain such as `'example.auth0.com'`,
|
|
110
113
|
* `'example.eu.auth0.com'` or , `'example.mycompany.com'`
|
|
@@ -256,6 +259,11 @@ export interface Auth0ClientOptions extends BaseLoginOptions {
|
|
|
256
259
|
* The default setting is `false`.
|
|
257
260
|
*/
|
|
258
261
|
useDpop?: boolean;
|
|
262
|
+
/**
|
|
263
|
+
* URL parameters that will be sent back to the Authorization Server. This can be known parameters
|
|
264
|
+
* defined by Auth0 or custom parameters that you define.
|
|
265
|
+
*/
|
|
266
|
+
authorizationParams?: ClientAuthorizationParams;
|
|
259
267
|
}
|
|
260
268
|
/**
|
|
261
269
|
* The possible locations where tokens can be stored
|
package/dist/typings/scope.d.ts
CHANGED
|
@@ -8,3 +8,28 @@
|
|
|
8
8
|
* @returns {string} A string containing unique scopes separated by a single space.
|
|
9
9
|
*/
|
|
10
10
|
export declare const getUniqueScopes: (...scopes: (string | undefined)[]) => string;
|
|
11
|
+
/**
|
|
12
|
+
* @ignore
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* We will check if the developer has created the client with a string or object of audience:scopes. We will inject
|
|
16
|
+
* the base scopes to each audience, and store the base ones inside default key. As well, if the developer created the Auth0Client
|
|
17
|
+
* with a string of scopes, we will store the requested ones with the base scopes inside the default key as well.
|
|
18
|
+
* @param authScopes The scopes requested by the user when creating the Auth0Client
|
|
19
|
+
* @param openIdScope openId scope
|
|
20
|
+
* @param extraScopes Other scopes to accumulate such as offline_access
|
|
21
|
+
* @returns {Record<string, string>} An object with all scopes that are going to be accumulated.
|
|
22
|
+
*/
|
|
23
|
+
export declare const injectDefaultScopes: (authScopes: string | Record<string, string> | undefined, openIdScope: string, ...extraScopes: string[]) => Record<string, string>;
|
|
24
|
+
/**
|
|
25
|
+
* @ignore
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Will return a string of scopes. If a specific audience was requested and it exist inside the scopes object, we will return those
|
|
29
|
+
* related to that audience that we want to accumulate. If not, we will return the ones stored inside the default key.
|
|
30
|
+
* @param authScopes Object of audience:scopes that are going to be accumulated
|
|
31
|
+
* @param methodScopes The scopes requested for the developer in a specific request
|
|
32
|
+
* @param audience The audience the developer requested for an specific request or the one they configured in the Auth0Client
|
|
33
|
+
* @returns {string} A combination of Auth0Client scopes and the ones requested by the developer for a specific request
|
|
34
|
+
*/
|
|
35
|
+
export declare const scopesToRequest: (authScopes: Record<string, string>, methodScopes: string | undefined, audience: string | undefined) => string;
|
package/dist/typings/utils.d.ts
CHANGED
|
@@ -7,6 +7,12 @@ export declare const getCrypto: () => Crypto;
|
|
|
7
7
|
export declare const createRandomString: () => string;
|
|
8
8
|
export declare const encode: (value: string) => string;
|
|
9
9
|
export declare const decode: (value: string) => string;
|
|
10
|
+
/**
|
|
11
|
+
* Strips any property that is not present in ALLOWED_AUTH0CLIENT_PROPERTIES
|
|
12
|
+
* @param auth0Client - The full auth0Client object
|
|
13
|
+
* @returns The stripped auth0Client object
|
|
14
|
+
*/
|
|
15
|
+
export declare const stripAuth0Client: (auth0Client: any) => any;
|
|
10
16
|
export declare const createQueryParams: ({ clientId: client_id, ...params }: any) => string;
|
|
11
17
|
export declare const sha256: (s: string) => Promise<any>;
|
|
12
18
|
export declare const urlDecodeB64: (input: string) => string;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
declare const _default: "2.
|
|
1
|
+
declare const _default: "2.8.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": "2.
|
|
6
|
+
"version": "2.8.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",
|
package/src/Auth0Client.ts
CHANGED
|
@@ -18,7 +18,7 @@ import {
|
|
|
18
18
|
|
|
19
19
|
import { oauthToken } from './api';
|
|
20
20
|
|
|
21
|
-
import {
|
|
21
|
+
import { injectDefaultScopes, scopesToRequest } from './scope';
|
|
22
22
|
|
|
23
23
|
import {
|
|
24
24
|
InMemoryCache,
|
|
@@ -59,7 +59,8 @@ import {
|
|
|
59
59
|
DEFAULT_AUTH0_CLIENT,
|
|
60
60
|
INVALID_REFRESH_TOKEN_ERROR_MESSAGE,
|
|
61
61
|
DEFAULT_NOW_PROVIDER,
|
|
62
|
-
DEFAULT_FETCH_TIMEOUT_MS
|
|
62
|
+
DEFAULT_FETCH_TIMEOUT_MS,
|
|
63
|
+
DEFAULT_AUDIENCE
|
|
63
64
|
} from './constants';
|
|
64
65
|
|
|
65
66
|
import {
|
|
@@ -82,7 +83,8 @@ import {
|
|
|
82
83
|
AuthenticationResult,
|
|
83
84
|
ConnectAccountRedirectResult,
|
|
84
85
|
RedirectConnectAccountOptions,
|
|
85
|
-
ResponseType
|
|
86
|
+
ResponseType,
|
|
87
|
+
ClientAuthorizationParams,
|
|
86
88
|
} from './global';
|
|
87
89
|
|
|
88
90
|
// @ts-ignore
|
|
@@ -94,7 +96,7 @@ import {
|
|
|
94
96
|
buildOrganizationHintCookieName,
|
|
95
97
|
cacheFactory,
|
|
96
98
|
getAuthorizeParams,
|
|
97
|
-
|
|
99
|
+
buildGetTokenSilentlyLockKey,
|
|
98
100
|
OLD_IS_AUTHENTICATED_COOKIE_NAME,
|
|
99
101
|
patchOpenUrlWithOnRedirect,
|
|
100
102
|
getScopeToRequest,
|
|
@@ -134,7 +136,7 @@ export class Auth0Client {
|
|
|
134
136
|
private readonly cacheManager: CacheManager;
|
|
135
137
|
private readonly domainUrl: string;
|
|
136
138
|
private readonly tokenIssuer: string;
|
|
137
|
-
private readonly scope: string
|
|
139
|
+
private readonly scope: Record<string, string>;
|
|
138
140
|
private readonly cookieStorage: ClientStorage;
|
|
139
141
|
private readonly dpop: Dpop | undefined;
|
|
140
142
|
private readonly sessionCheckExpiryDays: number;
|
|
@@ -143,12 +145,14 @@ export class Auth0Client {
|
|
|
143
145
|
private readonly nowProvider: () => number | Promise<number>;
|
|
144
146
|
private readonly httpTimeoutMs: number;
|
|
145
147
|
private readonly options: Auth0ClientOptions & {
|
|
146
|
-
authorizationParams:
|
|
148
|
+
authorizationParams: ClientAuthorizationParams,
|
|
147
149
|
};
|
|
148
150
|
private readonly userCache: ICache = new InMemoryCache().enclosedCache;
|
|
149
151
|
private readonly myAccountApi: MyAccountApiClient;
|
|
150
152
|
|
|
151
153
|
private worker?: Worker;
|
|
154
|
+
private readonly activeLockKeys: Set<string> = new Set();
|
|
155
|
+
|
|
152
156
|
private readonly defaultOptions: Partial<Auth0ClientOptions> = {
|
|
153
157
|
authorizationParams: {
|
|
154
158
|
scope: DEFAULT_SCOPE
|
|
@@ -218,9 +222,9 @@ export class Auth0Client {
|
|
|
218
222
|
// 1. Always include `openid`
|
|
219
223
|
// 2. Include the scopes provided in `authorizationParams. This defaults to `profile email`
|
|
220
224
|
// 3. Add `offline_access` if `useRefreshTokens` is enabled
|
|
221
|
-
this.scope =
|
|
222
|
-
'openid',
|
|
225
|
+
this.scope = injectDefaultScopes(
|
|
223
226
|
this.options.authorizationParams.scope,
|
|
227
|
+
'openid',
|
|
224
228
|
this.options.useRefreshTokens ? 'offline_access' : ''
|
|
225
229
|
);
|
|
226
230
|
|
|
@@ -362,7 +366,7 @@ export class Auth0Client {
|
|
|
362
366
|
nonce,
|
|
363
367
|
code_verifier,
|
|
364
368
|
scope: params.scope,
|
|
365
|
-
audience: params.audience ||
|
|
369
|
+
audience: params.audience || DEFAULT_AUDIENCE,
|
|
366
370
|
redirect_uri: params.redirect_uri,
|
|
367
371
|
state,
|
|
368
372
|
url
|
|
@@ -782,7 +786,11 @@ export class Auth0Client {
|
|
|
782
786
|
authorizationParams: {
|
|
783
787
|
...this.options.authorizationParams,
|
|
784
788
|
...options.authorizationParams,
|
|
785
|
-
scope:
|
|
789
|
+
scope: scopesToRequest(
|
|
790
|
+
this.scope,
|
|
791
|
+
options.authorizationParams?.scope,
|
|
792
|
+
options.authorizationParams?.audience || this.options.authorizationParams.audience,
|
|
793
|
+
)
|
|
786
794
|
}
|
|
787
795
|
};
|
|
788
796
|
|
|
@@ -806,7 +814,7 @@ export class Auth0Client {
|
|
|
806
814
|
if (cacheMode !== 'off') {
|
|
807
815
|
const entry = await this._getEntryFromCache({
|
|
808
816
|
scope: getTokenOptions.authorizationParams.scope,
|
|
809
|
-
audience: getTokenOptions.authorizationParams.audience ||
|
|
817
|
+
audience: getTokenOptions.authorizationParams.audience || DEFAULT_AUDIENCE,
|
|
810
818
|
clientId: this.options.clientId,
|
|
811
819
|
cacheMode,
|
|
812
820
|
});
|
|
@@ -820,21 +828,26 @@ export class Auth0Client {
|
|
|
820
828
|
return;
|
|
821
829
|
}
|
|
822
830
|
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
) {
|
|
829
|
-
try {
|
|
830
|
-
window.addEventListener('pagehide', this._releaseLockOnPageHide);
|
|
831
|
+
// Generate lock key based on client ID and audience for better isolation
|
|
832
|
+
const lockKey = buildGetTokenSilentlyLockKey(
|
|
833
|
+
this.options.clientId,
|
|
834
|
+
getTokenOptions.authorizationParams.audience || 'default'
|
|
835
|
+
);
|
|
831
836
|
|
|
837
|
+
if (await retryPromise(() => lock.acquireLock(lockKey, 5000), 10)) {
|
|
838
|
+
this.activeLockKeys.add(lockKey);
|
|
839
|
+
|
|
840
|
+
// Add event listener only if this is the first active lock
|
|
841
|
+
if (this.activeLockKeys.size === 1) {
|
|
842
|
+
window.addEventListener('pagehide', this._releaseLockOnPageHide);
|
|
843
|
+
}
|
|
844
|
+
try {
|
|
832
845
|
// Check the cache a second time, because it may have been populated
|
|
833
846
|
// by a previous call while this call was waiting to acquire the lock.
|
|
834
847
|
if (cacheMode !== 'off') {
|
|
835
848
|
const entry = await this._getEntryFromCache({
|
|
836
849
|
scope: getTokenOptions.authorizationParams.scope,
|
|
837
|
-
audience: getTokenOptions.authorizationParams.audience ||
|
|
850
|
+
audience: getTokenOptions.authorizationParams.audience || DEFAULT_AUDIENCE,
|
|
838
851
|
clientId: this.options.clientId
|
|
839
852
|
});
|
|
840
853
|
|
|
@@ -863,8 +876,12 @@ export class Auth0Client {
|
|
|
863
876
|
expires_in
|
|
864
877
|
};
|
|
865
878
|
} finally {
|
|
866
|
-
await lock.releaseLock(
|
|
867
|
-
|
|
879
|
+
await lock.releaseLock(lockKey);
|
|
880
|
+
this.activeLockKeys.delete(lockKey);
|
|
881
|
+
// If we have no more locks, we can remove the event listener to clean up
|
|
882
|
+
if (this.activeLockKeys.size === 0) {
|
|
883
|
+
window.removeEventListener('pagehide', this._releaseLockOnPageHide);
|
|
884
|
+
}
|
|
868
885
|
}
|
|
869
886
|
} else {
|
|
870
887
|
throw new TimeoutError();
|
|
@@ -892,7 +909,11 @@ export class Auth0Client {
|
|
|
892
909
|
authorizationParams: {
|
|
893
910
|
...this.options.authorizationParams,
|
|
894
911
|
...options.authorizationParams,
|
|
895
|
-
scope:
|
|
912
|
+
scope: scopesToRequest(
|
|
913
|
+
this.scope,
|
|
914
|
+
options.authorizationParams?.scope,
|
|
915
|
+
options.authorizationParams?.audience || this.options.authorizationParams.audience
|
|
916
|
+
)
|
|
896
917
|
}
|
|
897
918
|
};
|
|
898
919
|
|
|
@@ -906,7 +927,7 @@ export class Auth0Client {
|
|
|
906
927
|
const cache = await this.cacheManager.get(
|
|
907
928
|
new CacheKey({
|
|
908
929
|
scope: localOptions.authorizationParams.scope,
|
|
909
|
-
audience: localOptions.authorizationParams.audience ||
|
|
930
|
+
audience: localOptions.authorizationParams.audience || DEFAULT_AUDIENCE,
|
|
910
931
|
clientId: this.options.clientId
|
|
911
932
|
}),
|
|
912
933
|
undefined,
|
|
@@ -1095,7 +1116,7 @@ export class Auth0Client {
|
|
|
1095
1116
|
const cache = await this.cacheManager.get(
|
|
1096
1117
|
new CacheKey({
|
|
1097
1118
|
scope: options.authorizationParams.scope,
|
|
1098
|
-
audience: options.authorizationParams.audience ||
|
|
1119
|
+
audience: options.authorizationParams.audience || DEFAULT_AUDIENCE,
|
|
1099
1120
|
clientId: this.options.clientId
|
|
1100
1121
|
}),
|
|
1101
1122
|
undefined,
|
|
@@ -1112,7 +1133,7 @@ export class Auth0Client {
|
|
|
1112
1133
|
}
|
|
1113
1134
|
|
|
1114
1135
|
throw new MissingRefreshTokenError(
|
|
1115
|
-
options.authorizationParams.audience ||
|
|
1136
|
+
options.authorizationParams.audience || DEFAULT_AUDIENCE,
|
|
1116
1137
|
options.authorizationParams.scope
|
|
1117
1138
|
);
|
|
1118
1139
|
}
|
|
@@ -1179,6 +1200,14 @@ export class Auth0Client {
|
|
|
1179
1200
|
return await this._getTokenFromIFrame(options);
|
|
1180
1201
|
}
|
|
1181
1202
|
|
|
1203
|
+
// Before throwing MissingScopesError, we have to remove the previously created entry
|
|
1204
|
+
// to avoid storing wrong data
|
|
1205
|
+
await this.cacheManager.remove(
|
|
1206
|
+
this.options.clientId,
|
|
1207
|
+
options.authorizationParams.audience,
|
|
1208
|
+
options.authorizationParams.scope,
|
|
1209
|
+
);
|
|
1210
|
+
|
|
1182
1211
|
const missingScopes = getMissingScopes(
|
|
1183
1212
|
scopesToRequest,
|
|
1184
1213
|
tokenResult.scope,
|
|
@@ -1196,7 +1225,7 @@ export class Auth0Client {
|
|
|
1196
1225
|
...tokenResult,
|
|
1197
1226
|
scope: options.authorizationParams.scope,
|
|
1198
1227
|
oauthTokenScope: tokenResult.scope,
|
|
1199
|
-
audience: options.authorizationParams.audience ||
|
|
1228
|
+
audience: options.authorizationParams.audience || DEFAULT_AUDIENCE
|
|
1200
1229
|
};
|
|
1201
1230
|
} catch (e) {
|
|
1202
1231
|
if (
|
|
@@ -1236,13 +1265,14 @@ export class Auth0Client {
|
|
|
1236
1265
|
}
|
|
1237
1266
|
|
|
1238
1267
|
private async _getIdTokenFromCache() {
|
|
1239
|
-
const audience = this.options.authorizationParams.audience ||
|
|
1268
|
+
const audience = this.options.authorizationParams.audience || DEFAULT_AUDIENCE;
|
|
1269
|
+
const scope = this.scope[audience];
|
|
1240
1270
|
|
|
1241
1271
|
const cache = await this.cacheManager.getIdToken(
|
|
1242
1272
|
new CacheKey({
|
|
1243
1273
|
clientId: this.options.clientId,
|
|
1244
1274
|
audience,
|
|
1245
|
-
scope
|
|
1275
|
+
scope,
|
|
1246
1276
|
})
|
|
1247
1277
|
);
|
|
1248
1278
|
|
|
@@ -1299,13 +1329,18 @@ export class Auth0Client {
|
|
|
1299
1329
|
}
|
|
1300
1330
|
|
|
1301
1331
|
/**
|
|
1302
|
-
* Releases any
|
|
1332
|
+
* Releases any locks acquired by the current page that are not released yet
|
|
1303
1333
|
*
|
|
1304
1334
|
* Get's called on the `pagehide` event.
|
|
1305
1335
|
* https://developer.mozilla.org/en-US/docs/Web/API/Window/pagehide_event
|
|
1306
1336
|
*/
|
|
1307
1337
|
private _releaseLockOnPageHide = async () => {
|
|
1308
|
-
|
|
1338
|
+
// Release all active locks
|
|
1339
|
+
const lockKeysToRelease = Array.from(this.activeLockKeys);
|
|
1340
|
+
for (const lockKey of lockKeysToRelease) {
|
|
1341
|
+
await lock.releaseLock(lockKey);
|
|
1342
|
+
}
|
|
1343
|
+
this.activeLockKeys.clear();
|
|
1309
1344
|
|
|
1310
1345
|
window.removeEventListener('pagehide', this._releaseLockOnPageHide);
|
|
1311
1346
|
};
|
|
@@ -1343,7 +1378,7 @@ export class Auth0Client {
|
|
|
1343
1378
|
...authResult,
|
|
1344
1379
|
decodedToken,
|
|
1345
1380
|
scope: options.scope,
|
|
1346
|
-
audience: options.audience ||
|
|
1381
|
+
audience: options.audience || DEFAULT_AUDIENCE,
|
|
1347
1382
|
...(authResult.scope ? { oauthTokenScope: authResult.scope } : null),
|
|
1348
1383
|
client_id: this.options.clientId
|
|
1349
1384
|
});
|
|
@@ -1415,7 +1450,11 @@ export class Auth0Client {
|
|
|
1415
1450
|
grant_type: 'urn:ietf:params:oauth:grant-type:token-exchange',
|
|
1416
1451
|
subject_token: options.subject_token,
|
|
1417
1452
|
subject_token_type: options.subject_token_type,
|
|
1418
|
-
scope:
|
|
1453
|
+
scope: scopesToRequest(
|
|
1454
|
+
this.scope,
|
|
1455
|
+
options.scope,
|
|
1456
|
+
options.audience || this.options.authorizationParams.audience
|
|
1457
|
+
),
|
|
1419
1458
|
audience: options.audience || this.options.authorizationParams.audience
|
|
1420
1459
|
});
|
|
1421
1460
|
}
|
package/src/Auth0Client.utils.ts
CHANGED
|
@@ -3,15 +3,24 @@ import {
|
|
|
3
3
|
Auth0ClientOptions,
|
|
4
4
|
AuthorizationParams,
|
|
5
5
|
AuthorizeOptions,
|
|
6
|
+
ClientAuthorizationParams,
|
|
6
7
|
LogoutOptions
|
|
7
8
|
} from './global';
|
|
8
|
-
import {
|
|
9
|
+
import { scopesToRequest } from './scope';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* @ignore
|
|
12
13
|
*/
|
|
13
14
|
export const GET_TOKEN_SILENTLY_LOCK_KEY = 'auth0.lock.getTokenSilently';
|
|
14
15
|
|
|
16
|
+
/**
|
|
17
|
+
* @ignore
|
|
18
|
+
*/
|
|
19
|
+
export const buildGetTokenSilentlyLockKey = (
|
|
20
|
+
clientId: string,
|
|
21
|
+
audience: string
|
|
22
|
+
) => `${GET_TOKEN_SILENTLY_LOCK_KEY}.${clientId}.${audience}`;
|
|
23
|
+
|
|
15
24
|
/**
|
|
16
25
|
* @ignore
|
|
17
26
|
*/
|
|
@@ -49,10 +58,10 @@ export const cacheFactory = (location: string) => {
|
|
|
49
58
|
*/
|
|
50
59
|
export const getAuthorizeParams = (
|
|
51
60
|
clientOptions: Auth0ClientOptions & {
|
|
52
|
-
authorizationParams:
|
|
61
|
+
authorizationParams: ClientAuthorizationParams;
|
|
53
62
|
},
|
|
54
|
-
scope: string,
|
|
55
|
-
authorizationParams: AuthorizationParams,
|
|
63
|
+
scope: Record<string, string>,
|
|
64
|
+
authorizationParams: AuthorizationParams & { scope?: string },
|
|
56
65
|
state: string,
|
|
57
66
|
nonce: string,
|
|
58
67
|
code_challenge: string,
|
|
@@ -64,7 +73,7 @@ export const getAuthorizeParams = (
|
|
|
64
73
|
client_id: clientOptions.clientId,
|
|
65
74
|
...clientOptions.authorizationParams,
|
|
66
75
|
...authorizationParams,
|
|
67
|
-
scope:
|
|
76
|
+
scope: scopesToRequest(scope, authorizationParams.scope, authorizationParams.audience),
|
|
68
77
|
response_type: 'code',
|
|
69
78
|
response_mode: response_mode || 'query',
|
|
70
79
|
state,
|
package/src/api.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { TokenEndpointOptions, TokenEndpointResponse } from './global';
|
|
2
|
-
import { DEFAULT_AUTH0_CLIENT } from './constants';
|
|
2
|
+
import { DEFAULT_AUTH0_CLIENT, DEFAULT_AUDIENCE } from './constants';
|
|
3
3
|
import * as dpopUtils from './dpop/utils';
|
|
4
4
|
import { getJSON } from './http';
|
|
5
|
-
import { createQueryParams } from './utils';
|
|
5
|
+
import { createQueryParams, stripAuth0Client } from './utils';
|
|
6
6
|
|
|
7
7
|
export async function oauthToken(
|
|
8
8
|
{
|
|
@@ -21,8 +21,7 @@ export async function oauthToken(
|
|
|
21
21
|
const isTokenExchange =
|
|
22
22
|
options.grant_type === 'urn:ietf:params:oauth:grant-type:token-exchange';
|
|
23
23
|
|
|
24
|
-
const refreshWithMrrt =
|
|
25
|
-
options.grant_type === 'refresh_token' && useMrrt;
|
|
24
|
+
const refreshWithMrrt = options.grant_type === 'refresh_token' && useMrrt;
|
|
26
25
|
|
|
27
26
|
const allParams = {
|
|
28
27
|
...options,
|
|
@@ -40,7 +39,7 @@ export async function oauthToken(
|
|
|
40
39
|
return await getJSON<TokenEndpointResponse>(
|
|
41
40
|
`${baseUrl}/oauth/token`,
|
|
42
41
|
timeout,
|
|
43
|
-
audience ||
|
|
42
|
+
audience || DEFAULT_AUDIENCE,
|
|
44
43
|
scope,
|
|
45
44
|
{
|
|
46
45
|
method: 'POST',
|
|
@@ -50,7 +49,7 @@ export async function oauthToken(
|
|
|
50
49
|
? 'application/x-www-form-urlencoded'
|
|
51
50
|
: 'application/json',
|
|
52
51
|
'Auth0-Client': btoa(
|
|
53
|
-
JSON.stringify(auth0Client || DEFAULT_AUTH0_CLIENT)
|
|
52
|
+
JSON.stringify(stripAuth0Client(auth0Client || DEFAULT_AUTH0_CLIENT))
|
|
54
53
|
)
|
|
55
54
|
}
|
|
56
55
|
},
|
|
@@ -149,6 +149,20 @@ export class CacheManager {
|
|
|
149
149
|
await this.keyManifest?.add(cacheKey.toKey());
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
+
async remove(
|
|
153
|
+
client_id: string,
|
|
154
|
+
audience?: string,
|
|
155
|
+
scope?: string,
|
|
156
|
+
): Promise<void> {
|
|
157
|
+
const cacheKey = new CacheKey({
|
|
158
|
+
clientId: client_id,
|
|
159
|
+
scope: scope,
|
|
160
|
+
audience: audience
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
await this.cache.remove(cacheKey.toKey());
|
|
164
|
+
}
|
|
165
|
+
|
|
152
166
|
async clear(clientId?: string): Promise<void> {
|
|
153
167
|
const keys = await this.getCacheKeys();
|
|
154
168
|
|
package/src/constants.ts
CHANGED
package/src/global.ts
CHANGED
|
@@ -113,6 +113,10 @@ export interface AuthorizationParams {
|
|
|
113
113
|
[key: string]: any;
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
export interface ClientAuthorizationParams extends Omit<AuthorizationParams, 'scope'> {
|
|
117
|
+
scope?: string | Record<string, string>
|
|
118
|
+
};
|
|
119
|
+
|
|
116
120
|
interface BaseLoginOptions {
|
|
117
121
|
/**
|
|
118
122
|
* URL parameters that will be sent back to the Authorization Server. This can be known parameters
|
|
@@ -121,7 +125,7 @@ interface BaseLoginOptions {
|
|
|
121
125
|
authorizationParams?: AuthorizationParams;
|
|
122
126
|
}
|
|
123
127
|
|
|
124
|
-
export interface Auth0ClientOptions
|
|
128
|
+
export interface Auth0ClientOptions {
|
|
125
129
|
/**
|
|
126
130
|
* Your Auth0 account domain such as `'example.auth0.com'`,
|
|
127
131
|
* `'example.eu.auth0.com'` or , `'example.mycompany.com'`
|
|
@@ -288,6 +292,12 @@ export interface Auth0ClientOptions extends BaseLoginOptions {
|
|
|
288
292
|
* The default setting is `false`.
|
|
289
293
|
*/
|
|
290
294
|
useDpop?: boolean;
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* URL parameters that will be sent back to the Authorization Server. This can be known parameters
|
|
298
|
+
* defined by Auth0 or custom parameters that you define.
|
|
299
|
+
*/
|
|
300
|
+
authorizationParams?: ClientAuthorizationParams;
|
|
291
301
|
}
|
|
292
302
|
|
|
293
303
|
/**
|
package/src/scope.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { DEFAULT_AUDIENCE } from "./constants";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* @ignore
|
|
3
5
|
*/
|
|
@@ -15,3 +17,58 @@ const dedupe = (arr: string[]) => Array.from(new Set(arr));
|
|
|
15
17
|
export const getUniqueScopes = (...scopes: (string | undefined)[]) => {
|
|
16
18
|
return dedupe(scopes.filter(Boolean).join(' ').trim().split(/\s+/)).join(' ');
|
|
17
19
|
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @ignore
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* We will check if the developer has created the client with a string or object of audience:scopes. We will inject
|
|
26
|
+
* the base scopes to each audience, and store the base ones inside default key. As well, if the developer created the Auth0Client
|
|
27
|
+
* with a string of scopes, we will store the requested ones with the base scopes inside the default key as well.
|
|
28
|
+
* @param authScopes The scopes requested by the user when creating the Auth0Client
|
|
29
|
+
* @param openIdScope openId scope
|
|
30
|
+
* @param extraScopes Other scopes to accumulate such as offline_access
|
|
31
|
+
* @returns {Record<string, string>} An object with all scopes that are going to be accumulated.
|
|
32
|
+
*/
|
|
33
|
+
export const injectDefaultScopes = (authScopes: string | Record<string, string> | undefined, openIdScope: string, ...extraScopes: string[]): Record<string, string> => {
|
|
34
|
+
if (typeof authScopes !== 'object') {
|
|
35
|
+
return { [DEFAULT_AUDIENCE]: getUniqueScopes(openIdScope, authScopes, ...extraScopes) };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
let requestedScopes: Record<string, string> = {
|
|
39
|
+
[DEFAULT_AUDIENCE]: getUniqueScopes(openIdScope, ...extraScopes),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Object.keys(authScopes).forEach((key) => {
|
|
43
|
+
const audienceScopes = authScopes[key];
|
|
44
|
+
|
|
45
|
+
requestedScopes[key] = getUniqueScopes(openIdScope, audienceScopes, ...extraScopes);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return requestedScopes;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @ignore
|
|
53
|
+
*/
|
|
54
|
+
/**
|
|
55
|
+
* Will return a string of scopes. If a specific audience was requested and it exist inside the scopes object, we will return those
|
|
56
|
+
* related to that audience that we want to accumulate. If not, we will return the ones stored inside the default key.
|
|
57
|
+
* @param authScopes Object of audience:scopes that are going to be accumulated
|
|
58
|
+
* @param methodScopes The scopes requested for the developer in a specific request
|
|
59
|
+
* @param audience The audience the developer requested for an specific request or the one they configured in the Auth0Client
|
|
60
|
+
* @returns {string} A combination of Auth0Client scopes and the ones requested by the developer for a specific request
|
|
61
|
+
*/
|
|
62
|
+
export const scopesToRequest = (authScopes: Record<string, string>, methodScopes: string | undefined, audience: string | undefined): string => {
|
|
63
|
+
let scope: string | undefined;
|
|
64
|
+
|
|
65
|
+
if (audience) {
|
|
66
|
+
scope = authScopes[audience];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (!scope) {
|
|
70
|
+
scope = authScopes[DEFAULT_AUDIENCE];
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return getUniqueScopes(scope, methodScopes);
|
|
74
|
+
}
|