@logto/client 2.4.0 → 2.5.1
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/lib/adapter/types.d.ts +5 -4
- package/lib/client.cjs +20 -20
- package/lib/client.d.ts +29 -7
- package/lib/client.js +20 -20
- package/lib/mock.d.ts +2 -0
- package/lib/types/index.d.ts +1 -0
- package/package.json +2 -2
package/lib/adapter/types.d.ts
CHANGED
|
@@ -39,16 +39,17 @@ export type InferStorageKey<S> = S extends Storage<infer Key> ? Key : never;
|
|
|
39
39
|
* @param url The URL to navigate to.
|
|
40
40
|
* @param parameters The parameters for the navigation.
|
|
41
41
|
* @param parameters.redirectUri The redirect URI that the user will be redirected to after the
|
|
42
|
-
* flow is completed. That is, the "redirect URI" for sign-in and "post-logout redirect URI" for
|
|
43
|
-
* sign-out.
|
|
44
|
-
* @param parameters.for The purpose of the navigation. It can be either "sign-in"
|
|
42
|
+
* flow is completed. That is, the "redirect URI" for "sign-in" and "post-logout redirect URI" for
|
|
43
|
+
* "sign-out". For the "post-sign-in" navigation, it should be ignored.
|
|
44
|
+
* @param parameters.for The purpose of the navigation. It can be either "sign-in", "sign-out", or
|
|
45
|
+
* "post-sign-in".
|
|
45
46
|
* @remarks Usually, the `redirectUri` parameter can be ignored unless the client needs to pass the
|
|
46
47
|
* redirect scheme or other parameters to the native app, such as `ASWebAuthenticationSession` in
|
|
47
48
|
* iOS.
|
|
48
49
|
*/
|
|
49
50
|
export type Navigate = (url: string, parameters: {
|
|
50
51
|
redirectUri?: string;
|
|
51
|
-
for: 'sign-in' | 'sign-out';
|
|
52
|
+
for: 'sign-in' | 'sign-out' | 'post-sign-in';
|
|
52
53
|
}) => void | Promise<void>;
|
|
53
54
|
export type JwtVerifier = {
|
|
54
55
|
verifyIdToken(idToken: string): Promise<void>;
|
package/lib/client.cjs
CHANGED
|
@@ -9,6 +9,7 @@ var memoize = require('./utils/memoize.cjs');
|
|
|
9
9
|
var once = require('./utils/once.cjs');
|
|
10
10
|
var types = require('./adapter/types.cjs');
|
|
11
11
|
|
|
12
|
+
/* eslint-disable max-lines */
|
|
12
13
|
/**
|
|
13
14
|
* The Logto base client class that provides the essential methods for
|
|
14
15
|
* interacting with the Logto server.
|
|
@@ -139,23 +140,17 @@ class StandardLogtoClient {
|
|
|
139
140
|
}
|
|
140
141
|
return js.fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
* a part of the OIDC standard, but a Logto-specific extension. Defaults to `signIn`.
|
|
154
|
-
*
|
|
155
|
-
* @see {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#sign-in | Sign in} for more information.
|
|
156
|
-
* @see {@link InteractionMode}
|
|
157
|
-
*/
|
|
158
|
-
async signIn(redirectUri, interactionMode) {
|
|
143
|
+
async signIn(options, mode, hint) {
|
|
144
|
+
const { redirectUri: redirectUriUrl, postRedirectUri: postRedirectUriUrl, interactionMode, loginHint, } = typeof options === 'string' || options instanceof URL
|
|
145
|
+
? {
|
|
146
|
+
redirectUri: options,
|
|
147
|
+
postRedirectUri: undefined,
|
|
148
|
+
interactionMode: mode,
|
|
149
|
+
loginHint: hint,
|
|
150
|
+
}
|
|
151
|
+
: options;
|
|
152
|
+
const redirectUri = redirectUriUrl.toString();
|
|
153
|
+
const postRedirectUri = postRedirectUriUrl?.toString();
|
|
159
154
|
const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;
|
|
160
155
|
const { authorizationEndpoint } = await this.getOidcConfig();
|
|
161
156
|
const [codeVerifier, state] = await Promise.all([
|
|
@@ -166,16 +161,17 @@ class StandardLogtoClient {
|
|
|
166
161
|
const signInUri = js.generateSignInUri({
|
|
167
162
|
authorizationEndpoint,
|
|
168
163
|
clientId,
|
|
169
|
-
redirectUri,
|
|
164
|
+
redirectUri: redirectUri.toString(),
|
|
170
165
|
codeChallenge,
|
|
171
166
|
state,
|
|
172
167
|
scopes,
|
|
173
168
|
resources,
|
|
174
169
|
prompt,
|
|
175
170
|
interactionMode,
|
|
171
|
+
loginHint,
|
|
176
172
|
});
|
|
177
173
|
await Promise.all([
|
|
178
|
-
this.setSignInSession({ redirectUri, codeVerifier, state }),
|
|
174
|
+
this.setSignInSession({ redirectUri, postRedirectUri, codeVerifier, state }),
|
|
179
175
|
this.setRefreshToken(null),
|
|
180
176
|
this.setIdToken(null),
|
|
181
177
|
]);
|
|
@@ -349,7 +345,7 @@ class StandardLogtoClient {
|
|
|
349
345
|
if (!signInSession) {
|
|
350
346
|
throw new errors.LogtoClientError('sign_in_session.not_found');
|
|
351
347
|
}
|
|
352
|
-
const { redirectUri, state, codeVerifier } = signInSession;
|
|
348
|
+
const { redirectUri, postRedirectUri, state, codeVerifier } = signInSession;
|
|
353
349
|
const code = js.verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);
|
|
354
350
|
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
355
351
|
const accessTokenKey = index$2.buildAccessTokenKey();
|
|
@@ -377,7 +373,11 @@ class StandardLogtoClient {
|
|
|
377
373
|
});
|
|
378
374
|
await this.saveAccessTokenMap();
|
|
379
375
|
await this.setSignInSession(null);
|
|
376
|
+
if (postRedirectUri) {
|
|
377
|
+
await this.adapter.navigate(postRedirectUri, { for: 'post-sign-in' });
|
|
378
|
+
}
|
|
380
379
|
}
|
|
381
380
|
}
|
|
381
|
+
/* eslint-enable max-lines */
|
|
382
382
|
|
|
383
383
|
exports.StandardLogtoClient = StandardLogtoClient;
|
package/lib/client.d.ts
CHANGED
|
@@ -2,6 +2,31 @@ import { type IdTokenClaims, type UserInfoResponse, type InteractionMode, type A
|
|
|
2
2
|
import { type Nullable } from '@silverhand/essentials';
|
|
3
3
|
import { ClientAdapterInstance, type ClientAdapter, type JwtVerifier } from './adapter/index.js';
|
|
4
4
|
import type { AccessToken, LogtoConfig, LogtoSignInSessionItem } from './types/index.js';
|
|
5
|
+
export type SignInOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* The redirect URI that the user will be redirected to after the sign-in flow is completed.
|
|
8
|
+
*/
|
|
9
|
+
redirectUri: string | URL;
|
|
10
|
+
/**
|
|
11
|
+
* The URI that the user will be redirected to after `redirectUri` successfully handled the
|
|
12
|
+
* sign-in callback. If not specified, the user will stay on the `redirectUri` page.
|
|
13
|
+
*/
|
|
14
|
+
postRedirectUri?: string | URL;
|
|
15
|
+
/**
|
|
16
|
+
* The interaction mode to be used for the authorization request. It determines the first page
|
|
17
|
+
* that the user will see in the sign-in flow.
|
|
18
|
+
*
|
|
19
|
+
* Note it's not a part of the OIDC standard, but a Logto-specific extension.
|
|
20
|
+
*
|
|
21
|
+
* @default InteractionMode.SignIn
|
|
22
|
+
* @see {@link InteractionMode}
|
|
23
|
+
*/
|
|
24
|
+
interactionMode?: InteractionMode;
|
|
25
|
+
/**
|
|
26
|
+
* Login hint indicates the current user (usually an email address).
|
|
27
|
+
*/
|
|
28
|
+
loginHint?: string;
|
|
29
|
+
};
|
|
5
30
|
/**
|
|
6
31
|
* The Logto base client class that provides the essential methods for
|
|
7
32
|
* interacting with the Logto server.
|
|
@@ -106,6 +131,7 @@ export declare class StandardLogtoClient {
|
|
|
106
131
|
* @throws LogtoClientError if the user is not authenticated.
|
|
107
132
|
*/
|
|
108
133
|
fetchUserInfo(): Promise<UserInfoResponse>;
|
|
134
|
+
signIn(options: SignInOptions): Promise<void>;
|
|
109
135
|
/**
|
|
110
136
|
* Start the sign-in flow with the specified redirect URI. The URI must be
|
|
111
137
|
* registered in the Logto Console.
|
|
@@ -115,14 +141,10 @@ export declare class StandardLogtoClient {
|
|
|
115
141
|
* To fetch the tokens from the authorization code, use {@link handleSignInCallback}
|
|
116
142
|
* after the user is redirected in the callback URI.
|
|
117
143
|
*
|
|
118
|
-
* @param redirectUri
|
|
119
|
-
* @param interactionMode
|
|
120
|
-
* a part of the OIDC standard, but a Logto-specific extension. Defaults to `signIn`.
|
|
121
|
-
*
|
|
122
|
-
* @see {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#sign-in | Sign in} for more information.
|
|
123
|
-
* @see {@link InteractionMode}
|
|
144
|
+
* @param redirectUri See {@link SignInOptions.redirectUri}.
|
|
145
|
+
* @param interactionMode See {@link SignInOptions.interactionMode}.
|
|
124
146
|
*/
|
|
125
|
-
signIn(redirectUri:
|
|
147
|
+
signIn(redirectUri: SignInOptions['redirectUri'], interactionMode?: SignInOptions['interactionMode'], loginHint?: SignInOptions['loginHint']): Promise<void>;
|
|
126
148
|
/**
|
|
127
149
|
* Check if the user is redirected from the sign-in page by checking if the
|
|
128
150
|
* current URL matches the redirect URI in the sign-in session.
|
package/lib/client.js
CHANGED
|
@@ -7,6 +7,7 @@ import { memoize } from './utils/memoize.js';
|
|
|
7
7
|
import { once } from './utils/once.js';
|
|
8
8
|
import { PersistKey, CacheKey } from './adapter/types.js';
|
|
9
9
|
|
|
10
|
+
/* eslint-disable max-lines */
|
|
10
11
|
/**
|
|
11
12
|
* The Logto base client class that provides the essential methods for
|
|
12
13
|
* interacting with the Logto server.
|
|
@@ -137,23 +138,17 @@ class StandardLogtoClient {
|
|
|
137
138
|
}
|
|
138
139
|
return fetchUserInfo(userinfoEndpoint, accessToken, this.adapter.requester);
|
|
139
140
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
* a part of the OIDC standard, but a Logto-specific extension. Defaults to `signIn`.
|
|
152
|
-
*
|
|
153
|
-
* @see {@link https://docs.logto.io/docs/recipes/integrate-logto/vanilla-js/#sign-in | Sign in} for more information.
|
|
154
|
-
* @see {@link InteractionMode}
|
|
155
|
-
*/
|
|
156
|
-
async signIn(redirectUri, interactionMode) {
|
|
141
|
+
async signIn(options, mode, hint) {
|
|
142
|
+
const { redirectUri: redirectUriUrl, postRedirectUri: postRedirectUriUrl, interactionMode, loginHint, } = typeof options === 'string' || options instanceof URL
|
|
143
|
+
? {
|
|
144
|
+
redirectUri: options,
|
|
145
|
+
postRedirectUri: undefined,
|
|
146
|
+
interactionMode: mode,
|
|
147
|
+
loginHint: hint,
|
|
148
|
+
}
|
|
149
|
+
: options;
|
|
150
|
+
const redirectUri = redirectUriUrl.toString();
|
|
151
|
+
const postRedirectUri = postRedirectUriUrl?.toString();
|
|
157
152
|
const { appId: clientId, prompt, resources, scopes } = this.logtoConfig;
|
|
158
153
|
const { authorizationEndpoint } = await this.getOidcConfig();
|
|
159
154
|
const [codeVerifier, state] = await Promise.all([
|
|
@@ -164,16 +159,17 @@ class StandardLogtoClient {
|
|
|
164
159
|
const signInUri = generateSignInUri({
|
|
165
160
|
authorizationEndpoint,
|
|
166
161
|
clientId,
|
|
167
|
-
redirectUri,
|
|
162
|
+
redirectUri: redirectUri.toString(),
|
|
168
163
|
codeChallenge,
|
|
169
164
|
state,
|
|
170
165
|
scopes,
|
|
171
166
|
resources,
|
|
172
167
|
prompt,
|
|
173
168
|
interactionMode,
|
|
169
|
+
loginHint,
|
|
174
170
|
});
|
|
175
171
|
await Promise.all([
|
|
176
|
-
this.setSignInSession({ redirectUri, codeVerifier, state }),
|
|
172
|
+
this.setSignInSession({ redirectUri, postRedirectUri, codeVerifier, state }),
|
|
177
173
|
this.setRefreshToken(null),
|
|
178
174
|
this.setIdToken(null),
|
|
179
175
|
]);
|
|
@@ -347,7 +343,7 @@ class StandardLogtoClient {
|
|
|
347
343
|
if (!signInSession) {
|
|
348
344
|
throw new LogtoClientError('sign_in_session.not_found');
|
|
349
345
|
}
|
|
350
|
-
const { redirectUri, state, codeVerifier } = signInSession;
|
|
346
|
+
const { redirectUri, postRedirectUri, state, codeVerifier } = signInSession;
|
|
351
347
|
const code = verifyAndParseCodeFromCallbackUri(callbackUri, redirectUri, state);
|
|
352
348
|
// NOTE: Will add scope to accessTokenKey when needed. (Linear issue LOG-1589)
|
|
353
349
|
const accessTokenKey = buildAccessTokenKey();
|
|
@@ -375,7 +371,11 @@ class StandardLogtoClient {
|
|
|
375
371
|
});
|
|
376
372
|
await this.saveAccessTokenMap();
|
|
377
373
|
await this.setSignInSession(null);
|
|
374
|
+
if (postRedirectUri) {
|
|
375
|
+
await this.adapter.navigate(postRedirectUri, { for: 'post-sign-in' });
|
|
376
|
+
}
|
|
378
377
|
}
|
|
379
378
|
}
|
|
379
|
+
/* eslint-enable max-lines */
|
|
380
380
|
|
|
381
381
|
export { StandardLogtoClient };
|
package/lib/mock.d.ts
CHANGED
|
@@ -26,9 +26,11 @@ export declare const postSignOutRedirectUri = "http://localhost:3000";
|
|
|
26
26
|
export declare const mockCodeChallenge = "code_challenge_value";
|
|
27
27
|
export declare const mockedCodeVerifier = "code_verifier_value";
|
|
28
28
|
export declare const mockedState = "state_value";
|
|
29
|
+
export declare const mockedUserHint = "johndoe@example.com";
|
|
29
30
|
export declare const mockedSignInUri: string;
|
|
30
31
|
export declare const mockedSignInUriWithLoginPrompt: string;
|
|
31
32
|
export declare const mockedSignUpUri: string;
|
|
33
|
+
export declare const mockedSignInUriWithLoginHint: string;
|
|
32
34
|
export declare const accessToken = "access_token_value";
|
|
33
35
|
export declare const refreshToken = "new_refresh_token_value";
|
|
34
36
|
export declare const idToken = "id_token_value";
|
package/lib/types/index.d.ts
CHANGED
|
@@ -62,6 +62,7 @@ export declare const isLogtoSignInSessionItem: (data: unknown) => data is LogtoS
|
|
|
62
62
|
export declare const isLogtoAccessTokenMap: (data: unknown) => data is Record<string, AccessToken>;
|
|
63
63
|
export type LogtoSignInSessionItem = {
|
|
64
64
|
redirectUri: string;
|
|
65
|
+
postRedirectUri?: string;
|
|
65
66
|
codeVerifier: string;
|
|
66
67
|
state: string;
|
|
67
68
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/client",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.cjs",
|
|
6
6
|
"module": "./lib/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"directory": "packages/client"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@logto/js": "^4.0.
|
|
32
|
+
"@logto/js": "^4.0.1",
|
|
33
33
|
"@silverhand/essentials": "^2.8.7",
|
|
34
34
|
"camelcase-keys": "^7.0.1",
|
|
35
35
|
"jose": "^5.2.2"
|