@logto/client 2.2.2 → 2.2.4
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 +0 -2
- package/lib/index.cjs +42 -36
- package/lib/index.d.ts +24 -21
- package/lib/index.js +42 -36
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -5,8 +5,6 @@
|
|
|
5
5
|
|
|
6
6
|
The Logto JavaScript Client SDK written in TypeScript. Check out our [docs](https://docs.logto.io/sdk/JavaScript/client/) for more information.
|
|
7
7
|
|
|
8
|
-
We also provide [文档](https://docs.logto.io/zh-cn/sdk/JavaScript/sdk/client/) in Simplified Chinese.
|
|
9
|
-
|
|
10
8
|
## Installation
|
|
11
9
|
|
|
12
10
|
### Using npm
|
package/lib/index.cjs
CHANGED
|
@@ -24,6 +24,21 @@ var requester = require('./utils/requester.cjs');
|
|
|
24
24
|
class LogtoClient {
|
|
25
25
|
constructor(logtoConfig, adapter) {
|
|
26
26
|
this.getOidcConfig = memoize.memoize(this.#getOidcConfig);
|
|
27
|
+
/**
|
|
28
|
+
* Get the access token from the storage.
|
|
29
|
+
*
|
|
30
|
+
* - If the access token has expired, it will try to fetch a new one using the Refresh Token.
|
|
31
|
+
* - If there's an ongoing Promise to fetch the access token, it will return the Promise.
|
|
32
|
+
*
|
|
33
|
+
* If you want to get the access token claims, use {@link getAccessTokenClaims} instead.
|
|
34
|
+
*
|
|
35
|
+
* @param resource The resource that the access token is granted for. If not
|
|
36
|
+
* specified, the access token will be used for OpenID Connect or the default
|
|
37
|
+
* resource, as specified in the Logto Console.
|
|
38
|
+
* @returns The access token string.
|
|
39
|
+
* @throws LogtoClientError if the user is not authenticated.
|
|
40
|
+
*/
|
|
41
|
+
this.getAccessToken = memoize.memoize(this.#getAccessToken);
|
|
27
42
|
this.getJwtVerifyGetKey = once.once(this.#getJwtVerifyGetKey);
|
|
28
43
|
this.accessTokenMap = new Map();
|
|
29
44
|
this.logtoConfig = {
|
|
@@ -53,36 +68,6 @@ class LogtoClient {
|
|
|
53
68
|
async getIdToken() {
|
|
54
69
|
return this.adapter.storage.getItem('idToken');
|
|
55
70
|
}
|
|
56
|
-
/**
|
|
57
|
-
* Get the Access Token from the storage. If the Access Token has expired, it
|
|
58
|
-
* will try to fetch a new one using the Refresh Token.
|
|
59
|
-
*
|
|
60
|
-
* If you want to get the Access Token claims, use {@link getAccessTokenClaims} instead.
|
|
61
|
-
*
|
|
62
|
-
* @param resource The resource that the Access Token is granted for. If not
|
|
63
|
-
* specified, the Access Token will be used for OpenID Connect or the default
|
|
64
|
-
* resource, as specified in the Logto Console.
|
|
65
|
-
* @returns The Access Token string.
|
|
66
|
-
* @throws LogtoClientError if the user is not authenticated.
|
|
67
|
-
*/
|
|
68
|
-
async getAccessToken(resource) {
|
|
69
|
-
if (!(await this.getIdToken())) {
|
|
70
|
-
throw new errors.LogtoClientError('not_authenticated');
|
|
71
|
-
}
|
|
72
|
-
const accessTokenKey = index$2.buildAccessTokenKey(resource);
|
|
73
|
-
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
74
|
-
if (accessToken && accessToken.expiresAt > Date.now() / 1000) {
|
|
75
|
-
return accessToken.token;
|
|
76
|
-
}
|
|
77
|
-
// Since the access token has expired, delete it from the map.
|
|
78
|
-
if (accessToken) {
|
|
79
|
-
this.accessTokenMap.delete(accessTokenKey);
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Need to fetch a new access token using refresh token.
|
|
83
|
-
*/
|
|
84
|
-
return this.getAccessTokenByRefreshToken(resource);
|
|
85
|
-
}
|
|
86
71
|
/**
|
|
87
72
|
* Get the ID Token claims.
|
|
88
73
|
*/
|
|
@@ -94,10 +79,10 @@ class LogtoClient {
|
|
|
94
79
|
return js.decodeIdToken(idToken);
|
|
95
80
|
}
|
|
96
81
|
/**
|
|
97
|
-
* Get the
|
|
82
|
+
* Get the access token claims for the specified resource.
|
|
98
83
|
*
|
|
99
|
-
* @param resource The resource that the
|
|
100
|
-
* specified, the
|
|
84
|
+
* @param resource The resource that the access token is granted for. If not
|
|
85
|
+
* specified, the access token will be used for OpenID Connect or the default
|
|
101
86
|
* resource, as specified in the Logto Console.
|
|
102
87
|
*/
|
|
103
88
|
async getAccessTokenClaims(resource) {
|
|
@@ -183,8 +168,9 @@ class LogtoClient {
|
|
|
183
168
|
* Handle the sign-in callback by parsing the authorization code from the
|
|
184
169
|
* callback URI and exchanging it for the tokens.
|
|
185
170
|
*
|
|
186
|
-
* @param callbackUri The callback URI that the user is redirected to after the sign-in flow is completed.
|
|
187
|
-
*
|
|
171
|
+
* @param callbackUri The callback URI, including the search params, that the user is redirected to after the sign-in flow is completed.
|
|
172
|
+
* The origin and pathname of this URI must match the origin and pathname of the redirect URI specified in {@link signIn}.
|
|
173
|
+
* In many cases you'll probably end up passing `window.location.href` as the argument to this function.
|
|
188
174
|
* @throws LogtoClientError if the sign-in session is not found.
|
|
189
175
|
*/
|
|
190
176
|
async handleSignInCallback(callbackUri) {
|
|
@@ -302,7 +288,9 @@ class LogtoClient {
|
|
|
302
288
|
expiresAt: requestedAt + expiresIn,
|
|
303
289
|
});
|
|
304
290
|
await this.saveAccessTokenMap();
|
|
305
|
-
|
|
291
|
+
if (refreshToken) {
|
|
292
|
+
await this.setRefreshToken(refreshToken);
|
|
293
|
+
}
|
|
306
294
|
if (idToken) {
|
|
307
295
|
await this.verifyIdToken(idToken);
|
|
308
296
|
await this.setIdToken(idToken);
|
|
@@ -355,6 +343,24 @@ class LogtoClient {
|
|
|
355
343
|
const cachedJwkSet = new remoteJwkSet.CachedRemoteJwkSet(new URL(jwksUri), this.adapter);
|
|
356
344
|
return async (...args) => cachedJwkSet.getKey(...args);
|
|
357
345
|
}
|
|
346
|
+
async #getAccessToken(resource) {
|
|
347
|
+
if (!(await this.getIdToken())) {
|
|
348
|
+
throw new errors.LogtoClientError('not_authenticated');
|
|
349
|
+
}
|
|
350
|
+
const accessTokenKey = index$2.buildAccessTokenKey(resource);
|
|
351
|
+
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
352
|
+
if (accessToken && accessToken.expiresAt > Date.now() / 1000) {
|
|
353
|
+
return accessToken.token;
|
|
354
|
+
}
|
|
355
|
+
// Since the access token has expired, delete it from the map.
|
|
356
|
+
if (accessToken) {
|
|
357
|
+
this.accessTokenMap.delete(accessTokenKey);
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Need to fetch a new access token using refresh token.
|
|
361
|
+
*/
|
|
362
|
+
return this.getAccessTokenByRefreshToken(resource);
|
|
363
|
+
}
|
|
358
364
|
}
|
|
359
365
|
|
|
360
366
|
Object.defineProperty(exports, 'LogtoError', {
|
package/lib/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { type JWTVerifyGetKey } from 'jose';
|
|
|
4
4
|
import { ClientAdapterInstance, type ClientAdapter } from './adapter/index.js';
|
|
5
5
|
import type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types/index.js';
|
|
6
6
|
export type { IdTokenClaims, LogtoErrorCode, UserInfoResponse, InteractionMode } from '@logto/js';
|
|
7
|
-
export { LogtoError, OidcError, Prompt,
|
|
7
|
+
export { LogtoError, LogtoRequestError, OidcError, Prompt, ReservedScope, UserScope, } from '@logto/js';
|
|
8
8
|
export * from './errors.js';
|
|
9
9
|
export type { Storage, StorageKey, ClientAdapter } from './adapter/index.js';
|
|
10
10
|
export { PersistKey, CacheKey } from './adapter/index.js';
|
|
@@ -19,8 +19,8 @@ export * from './types/index.js';
|
|
|
19
19
|
*/
|
|
20
20
|
export default class LogtoClient {
|
|
21
21
|
#private;
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
readonly logtoConfig: LogtoConfig;
|
|
23
|
+
readonly getOidcConfig: (this: unknown) => Promise<import("@silverhand/essentials").KeysToCamelCase<{
|
|
24
24
|
authorization_endpoint: string;
|
|
25
25
|
token_endpoint: string;
|
|
26
26
|
userinfo_endpoint: string;
|
|
@@ -29,6 +29,21 @@ export default class LogtoClient {
|
|
|
29
29
|
jwks_uri: string;
|
|
30
30
|
issuer: string;
|
|
31
31
|
}>>;
|
|
32
|
+
/**
|
|
33
|
+
* Get the access token from the storage.
|
|
34
|
+
*
|
|
35
|
+
* - If the access token has expired, it will try to fetch a new one using the Refresh Token.
|
|
36
|
+
* - If there's an ongoing Promise to fetch the access token, it will return the Promise.
|
|
37
|
+
*
|
|
38
|
+
* If you want to get the access token claims, use {@link getAccessTokenClaims} instead.
|
|
39
|
+
*
|
|
40
|
+
* @param resource The resource that the access token is granted for. If not
|
|
41
|
+
* specified, the access token will be used for OpenID Connect or the default
|
|
42
|
+
* resource, as specified in the Logto Console.
|
|
43
|
+
* @returns The access token string.
|
|
44
|
+
* @throws LogtoClientError if the user is not authenticated.
|
|
45
|
+
*/
|
|
46
|
+
readonly getAccessToken: (this: unknown, resource?: string | undefined) => Promise<string>;
|
|
32
47
|
protected readonly getJwtVerifyGetKey: (...args: unknown[]) => Promise<JWTVerifyGetKey>;
|
|
33
48
|
protected readonly adapter: ClientAdapterInstance;
|
|
34
49
|
protected readonly accessTokenMap: Map<string, AccessToken>;
|
|
@@ -46,28 +61,15 @@ export default class LogtoClient {
|
|
|
46
61
|
* use {@link getIdTokenClaims} instead.
|
|
47
62
|
*/
|
|
48
63
|
getIdToken(): Promise<Nullable<string>>;
|
|
49
|
-
/**
|
|
50
|
-
* Get the Access Token from the storage. If the Access Token has expired, it
|
|
51
|
-
* will try to fetch a new one using the Refresh Token.
|
|
52
|
-
*
|
|
53
|
-
* If you want to get the Access Token claims, use {@link getAccessTokenClaims} instead.
|
|
54
|
-
*
|
|
55
|
-
* @param resource The resource that the Access Token is granted for. If not
|
|
56
|
-
* specified, the Access Token will be used for OpenID Connect or the default
|
|
57
|
-
* resource, as specified in the Logto Console.
|
|
58
|
-
* @returns The Access Token string.
|
|
59
|
-
* @throws LogtoClientError if the user is not authenticated.
|
|
60
|
-
*/
|
|
61
|
-
getAccessToken(resource?: string): Promise<string>;
|
|
62
64
|
/**
|
|
63
65
|
* Get the ID Token claims.
|
|
64
66
|
*/
|
|
65
67
|
getIdTokenClaims(): Promise<IdTokenClaims>;
|
|
66
68
|
/**
|
|
67
|
-
* Get the
|
|
69
|
+
* Get the access token claims for the specified resource.
|
|
68
70
|
*
|
|
69
|
-
* @param resource The resource that the
|
|
70
|
-
* specified, the
|
|
71
|
+
* @param resource The resource that the access token is granted for. If not
|
|
72
|
+
* specified, the access token will be used for OpenID Connect or the default
|
|
71
73
|
* resource, as specified in the Logto Console.
|
|
72
74
|
*/
|
|
73
75
|
getAccessTokenClaims(resource?: string): Promise<AccessTokenClaims>;
|
|
@@ -112,8 +114,9 @@ export default class LogtoClient {
|
|
|
112
114
|
* Handle the sign-in callback by parsing the authorization code from the
|
|
113
115
|
* callback URI and exchanging it for the tokens.
|
|
114
116
|
*
|
|
115
|
-
* @param callbackUri The callback URI that the user is redirected to after the sign-in flow is completed.
|
|
116
|
-
*
|
|
117
|
+
* @param callbackUri The callback URI, including the search params, that the user is redirected to after the sign-in flow is completed.
|
|
118
|
+
* The origin and pathname of this URI must match the origin and pathname of the redirect URI specified in {@link signIn}.
|
|
119
|
+
* In many cases you'll probably end up passing `window.location.href` as the argument to this function.
|
|
117
120
|
* @throws LogtoClientError if the sign-in session is not found.
|
|
118
121
|
*/
|
|
119
122
|
handleSignInCallback(callbackUri: string): Promise<void>;
|
package/lib/index.js
CHANGED
|
@@ -21,6 +21,21 @@ export { createRequester } from './utils/requester.js';
|
|
|
21
21
|
class LogtoClient {
|
|
22
22
|
constructor(logtoConfig, adapter) {
|
|
23
23
|
this.getOidcConfig = memoize(this.#getOidcConfig);
|
|
24
|
+
/**
|
|
25
|
+
* Get the access token from the storage.
|
|
26
|
+
*
|
|
27
|
+
* - If the access token has expired, it will try to fetch a new one using the Refresh Token.
|
|
28
|
+
* - If there's an ongoing Promise to fetch the access token, it will return the Promise.
|
|
29
|
+
*
|
|
30
|
+
* If you want to get the access token claims, use {@link getAccessTokenClaims} instead.
|
|
31
|
+
*
|
|
32
|
+
* @param resource The resource that the access token is granted for. If not
|
|
33
|
+
* specified, the access token will be used for OpenID Connect or the default
|
|
34
|
+
* resource, as specified in the Logto Console.
|
|
35
|
+
* @returns The access token string.
|
|
36
|
+
* @throws LogtoClientError if the user is not authenticated.
|
|
37
|
+
*/
|
|
38
|
+
this.getAccessToken = memoize(this.#getAccessToken);
|
|
24
39
|
this.getJwtVerifyGetKey = once(this.#getJwtVerifyGetKey);
|
|
25
40
|
this.accessTokenMap = new Map();
|
|
26
41
|
this.logtoConfig = {
|
|
@@ -50,36 +65,6 @@ class LogtoClient {
|
|
|
50
65
|
async getIdToken() {
|
|
51
66
|
return this.adapter.storage.getItem('idToken');
|
|
52
67
|
}
|
|
53
|
-
/**
|
|
54
|
-
* Get the Access Token from the storage. If the Access Token has expired, it
|
|
55
|
-
* will try to fetch a new one using the Refresh Token.
|
|
56
|
-
*
|
|
57
|
-
* If you want to get the Access Token claims, use {@link getAccessTokenClaims} instead.
|
|
58
|
-
*
|
|
59
|
-
* @param resource The resource that the Access Token is granted for. If not
|
|
60
|
-
* specified, the Access Token will be used for OpenID Connect or the default
|
|
61
|
-
* resource, as specified in the Logto Console.
|
|
62
|
-
* @returns The Access Token string.
|
|
63
|
-
* @throws LogtoClientError if the user is not authenticated.
|
|
64
|
-
*/
|
|
65
|
-
async getAccessToken(resource) {
|
|
66
|
-
if (!(await this.getIdToken())) {
|
|
67
|
-
throw new LogtoClientError('not_authenticated');
|
|
68
|
-
}
|
|
69
|
-
const accessTokenKey = buildAccessTokenKey(resource);
|
|
70
|
-
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
71
|
-
if (accessToken && accessToken.expiresAt > Date.now() / 1000) {
|
|
72
|
-
return accessToken.token;
|
|
73
|
-
}
|
|
74
|
-
// Since the access token has expired, delete it from the map.
|
|
75
|
-
if (accessToken) {
|
|
76
|
-
this.accessTokenMap.delete(accessTokenKey);
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Need to fetch a new access token using refresh token.
|
|
80
|
-
*/
|
|
81
|
-
return this.getAccessTokenByRefreshToken(resource);
|
|
82
|
-
}
|
|
83
68
|
/**
|
|
84
69
|
* Get the ID Token claims.
|
|
85
70
|
*/
|
|
@@ -91,10 +76,10 @@ class LogtoClient {
|
|
|
91
76
|
return decodeIdToken(idToken);
|
|
92
77
|
}
|
|
93
78
|
/**
|
|
94
|
-
* Get the
|
|
79
|
+
* Get the access token claims for the specified resource.
|
|
95
80
|
*
|
|
96
|
-
* @param resource The resource that the
|
|
97
|
-
* specified, the
|
|
81
|
+
* @param resource The resource that the access token is granted for. If not
|
|
82
|
+
* specified, the access token will be used for OpenID Connect or the default
|
|
98
83
|
* resource, as specified in the Logto Console.
|
|
99
84
|
*/
|
|
100
85
|
async getAccessTokenClaims(resource) {
|
|
@@ -180,8 +165,9 @@ class LogtoClient {
|
|
|
180
165
|
* Handle the sign-in callback by parsing the authorization code from the
|
|
181
166
|
* callback URI and exchanging it for the tokens.
|
|
182
167
|
*
|
|
183
|
-
* @param callbackUri The callback URI that the user is redirected to after the sign-in flow is completed.
|
|
184
|
-
*
|
|
168
|
+
* @param callbackUri The callback URI, including the search params, that the user is redirected to after the sign-in flow is completed.
|
|
169
|
+
* The origin and pathname of this URI must match the origin and pathname of the redirect URI specified in {@link signIn}.
|
|
170
|
+
* In many cases you'll probably end up passing `window.location.href` as the argument to this function.
|
|
185
171
|
* @throws LogtoClientError if the sign-in session is not found.
|
|
186
172
|
*/
|
|
187
173
|
async handleSignInCallback(callbackUri) {
|
|
@@ -299,7 +285,9 @@ class LogtoClient {
|
|
|
299
285
|
expiresAt: requestedAt + expiresIn,
|
|
300
286
|
});
|
|
301
287
|
await this.saveAccessTokenMap();
|
|
302
|
-
|
|
288
|
+
if (refreshToken) {
|
|
289
|
+
await this.setRefreshToken(refreshToken);
|
|
290
|
+
}
|
|
303
291
|
if (idToken) {
|
|
304
292
|
await this.verifyIdToken(idToken);
|
|
305
293
|
await this.setIdToken(idToken);
|
|
@@ -352,6 +340,24 @@ class LogtoClient {
|
|
|
352
340
|
const cachedJwkSet = new CachedRemoteJwkSet(new URL(jwksUri), this.adapter);
|
|
353
341
|
return async (...args) => cachedJwkSet.getKey(...args);
|
|
354
342
|
}
|
|
343
|
+
async #getAccessToken(resource) {
|
|
344
|
+
if (!(await this.getIdToken())) {
|
|
345
|
+
throw new LogtoClientError('not_authenticated');
|
|
346
|
+
}
|
|
347
|
+
const accessTokenKey = buildAccessTokenKey(resource);
|
|
348
|
+
const accessToken = this.accessTokenMap.get(accessTokenKey);
|
|
349
|
+
if (accessToken && accessToken.expiresAt > Date.now() / 1000) {
|
|
350
|
+
return accessToken.token;
|
|
351
|
+
}
|
|
352
|
+
// Since the access token has expired, delete it from the map.
|
|
353
|
+
if (accessToken) {
|
|
354
|
+
this.accessTokenMap.delete(accessTokenKey);
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Need to fetch a new access token using refresh token.
|
|
358
|
+
*/
|
|
359
|
+
return this.getAccessTokenByRefreshToken(resource);
|
|
360
|
+
}
|
|
355
361
|
}
|
|
356
362
|
|
|
357
363
|
export { CacheKey, LogtoClientError, PersistKey, LogtoClient as default, isLogtoAccessTokenMap, isLogtoSignInSessionItem };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/client",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.cjs",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"directory": "packages/client"
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
|
-
"@logto/js": "^2.1.
|
|
24
|
+
"@logto/js": "^2.1.3",
|
|
25
25
|
"@silverhand/essentials": "^2.6.2",
|
|
26
26
|
"camelcase-keys": "^7.0.1",
|
|
27
27
|
"jose": "^4.13.2"
|
|
@@ -36,11 +36,11 @@
|
|
|
36
36
|
"eslint": "^8.44.0",
|
|
37
37
|
"jest": "^29.5.0",
|
|
38
38
|
"jest-matcher-specific-error": "^1.0.0",
|
|
39
|
-
"lint-staged": "^
|
|
39
|
+
"lint-staged": "^15.0.0",
|
|
40
40
|
"nock": "^13.3.0",
|
|
41
41
|
"prettier": "^3.0.0",
|
|
42
42
|
"text-encoder": "^0.0.4",
|
|
43
|
-
"type-fest": "^
|
|
43
|
+
"type-fest": "^4.0.0",
|
|
44
44
|
"typescript": "^5.0.0"
|
|
45
45
|
},
|
|
46
46
|
"eslintConfig": {
|