@logto/next 3.6.0 → 3.7.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/lib/edge/index.cjs +38 -25
- package/lib/edge/index.d.ts +3 -2
- package/lib/edge/index.js +39 -26
- package/lib/server-actions/client.cjs +36 -30
- package/lib/server-actions/client.d.ts +19 -15
- package/lib/server-actions/client.js +37 -31
- package/lib/server-actions/index.cjs +12 -25
- package/lib/server-actions/index.d.ts +8 -2
- package/lib/server-actions/index.js +12 -25
- package/lib/src/client.cjs +0 -11
- package/lib/src/client.d.ts +2 -4
- package/lib/src/client.js +0 -11
- package/lib/src/index.cjs +36 -19
- package/lib/src/index.d.ts +5 -2
- package/lib/src/index.js +37 -20
- package/package.json +4 -2
- package/lib/server-actions/cookie.cjs +0 -17
- package/lib/server-actions/cookie.d.ts +0 -3
- package/lib/server-actions/cookie.js +0 -14
- package/lib/src/storage.cjs +0 -43
- package/lib/src/storage.d.ts +0 -14
- package/lib/src/storage.js +0 -39
- package/lib/src/storage.test.d.ts +0 -1
package/lib/edge/index.cjs
CHANGED
|
@@ -16,24 +16,20 @@ class LogtoClient extends client.default {
|
|
|
16
16
|
super(config, {
|
|
17
17
|
NodeClient: NodeClient__default.default,
|
|
18
18
|
});
|
|
19
|
-
this.handleSignIn = (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
headers,
|
|
25
|
-
status: 307,
|
|
26
|
-
});
|
|
27
|
-
if (this.navigateUrl) {
|
|
28
|
-
response.headers.append('Location', this.navigateUrl);
|
|
19
|
+
this.handleSignIn = (options, interactionMode) => {
|
|
20
|
+
// The array function can not have multiple signatures, have to warn the deprecated usage
|
|
21
|
+
if (typeof options === 'string') {
|
|
22
|
+
console.warn('Deprecated: Use the object parameter for handleSignIn instead.');
|
|
23
|
+
return this.handleSignInImplementation({ redirectUri: options, interactionMode });
|
|
29
24
|
}
|
|
30
|
-
return
|
|
25
|
+
return this.handleSignInImplementation(options ?? {
|
|
26
|
+
redirectUri: `${this.config.baseUrl}/api/logto/sign-in-callback`,
|
|
27
|
+
});
|
|
31
28
|
};
|
|
32
29
|
this.handleSignOut = (redirectUri = this.config.baseUrl) => async (request) => {
|
|
33
30
|
const { nodeClient, headers } = await this.createNodeClientFromEdgeRequest(request);
|
|
34
31
|
await nodeClient.signOut(redirectUri);
|
|
35
32
|
await this.storage?.destroy();
|
|
36
|
-
await this.storage?.save();
|
|
37
33
|
const response = new Response(null, {
|
|
38
34
|
headers,
|
|
39
35
|
status: 307,
|
|
@@ -51,7 +47,6 @@ class LogtoClient extends client.default {
|
|
|
51
47
|
const requestUrl = new URL(request.url);
|
|
52
48
|
const callbackUrl = new URL(`${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`, this.config.baseUrl);
|
|
53
49
|
await nodeClient.handleSignInCallback(callbackUrl.toString());
|
|
54
|
-
await this.storage?.save();
|
|
55
50
|
}
|
|
56
51
|
const response = new Response(null, {
|
|
57
52
|
status: 307,
|
|
@@ -72,25 +67,43 @@ class LogtoClient extends client.default {
|
|
|
72
67
|
this.getLogtoContext = async (request, config = {}) => {
|
|
73
68
|
const { nodeClient } = await this.createNodeClientFromEdgeRequest(request);
|
|
74
69
|
const context = await nodeClient.getContext(config);
|
|
75
|
-
await this.storage?.save();
|
|
76
70
|
return context;
|
|
77
71
|
};
|
|
72
|
+
this.handleSignInImplementation = (options) => async (request) => {
|
|
73
|
+
const { nodeClient, headers } = await this.createNodeClientFromEdgeRequest(request);
|
|
74
|
+
await nodeClient.signIn(options);
|
|
75
|
+
const response = new Response(null, {
|
|
76
|
+
headers,
|
|
77
|
+
status: 307,
|
|
78
|
+
});
|
|
79
|
+
if (this.navigateUrl) {
|
|
80
|
+
response.headers.append('Location', this.navigateUrl);
|
|
81
|
+
}
|
|
82
|
+
return response;
|
|
83
|
+
};
|
|
78
84
|
}
|
|
79
85
|
async createNodeClientFromEdgeRequest(request) {
|
|
80
|
-
const cookieName = `logto:${this.config.appId}`;
|
|
81
86
|
const cookies$1 = new cookies.RequestCookies(request.headers);
|
|
82
87
|
const headers = new Headers();
|
|
83
88
|
const responseCookies = new cookies.ResponseCookies(headers);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
89
|
+
this.storage = new NodeClient$1.CookieStorage({
|
|
90
|
+
encryptionKey: this.config.cookieSecret,
|
|
91
|
+
cookieKey: `logto:${this.config.appId}`,
|
|
92
|
+
isSecure: this.config.cookieSecure,
|
|
93
|
+
getCookie: (name) => {
|
|
94
|
+
return cookies$1.get(name)?.value ?? '';
|
|
95
|
+
},
|
|
96
|
+
setCookie: (name, value, options) => {
|
|
97
|
+
responseCookies.set(name, value, options);
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
await this.storage.init();
|
|
101
|
+
const nodeClient = new this.adapters.NodeClient(this.config, {
|
|
102
|
+
storage: this.storage,
|
|
103
|
+
navigate: (url) => {
|
|
104
|
+
this.navigateUrl = url;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
94
107
|
return { nodeClient, headers };
|
|
95
108
|
}
|
|
96
109
|
}
|
package/lib/edge/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
1
|
+
import { type SignInOptions, type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
2
2
|
import { type NextRequest } from 'next/server';
|
|
3
3
|
import BaseClient from '../src/client';
|
|
4
4
|
import type { LogtoNextConfig } from '../src/types.js';
|
|
5
5
|
export type { AccessTokenClaims, IdTokenClaims, LogtoContext, InteractionMode, LogtoErrorCode, UserInfoResponse, } from '@logto/node';
|
|
6
6
|
export default class LogtoClient extends BaseClient {
|
|
7
7
|
constructor(config: LogtoNextConfig);
|
|
8
|
-
handleSignIn: (
|
|
8
|
+
handleSignIn: (options?: SignInOptions | string, interactionMode?: InteractionMode) => (request: Request) => Promise<Response>;
|
|
9
9
|
handleSignOut: (redirectUri?: string) => (request: NextRequest) => Promise<Response>;
|
|
10
10
|
handleSignInCallback: (redirectTo?: string) => (request: NextRequest) => Promise<Response>;
|
|
11
11
|
handleUser: (configs?: GetContextParameters) => (request: NextRequest) => Promise<Response>;
|
|
@@ -14,4 +14,5 @@ export default class LogtoClient extends BaseClient {
|
|
|
14
14
|
nodeClient: import("@logto/node").default;
|
|
15
15
|
headers: Headers;
|
|
16
16
|
}>;
|
|
17
|
+
private readonly handleSignInImplementation;
|
|
17
18
|
}
|
package/lib/edge/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { RequestCookies, ResponseCookies } from '@edge-runtime/cookies';
|
|
2
|
-
import {
|
|
2
|
+
import { CookieStorage } from '@logto/node';
|
|
3
3
|
import NodeClient from '@logto/node/edge';
|
|
4
4
|
import LogtoNextBaseClient from '../src/client.js';
|
|
5
5
|
|
|
@@ -8,24 +8,20 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
8
8
|
super(config, {
|
|
9
9
|
NodeClient,
|
|
10
10
|
});
|
|
11
|
-
this.handleSignIn = (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
headers,
|
|
17
|
-
status: 307,
|
|
18
|
-
});
|
|
19
|
-
if (this.navigateUrl) {
|
|
20
|
-
response.headers.append('Location', this.navigateUrl);
|
|
11
|
+
this.handleSignIn = (options, interactionMode) => {
|
|
12
|
+
// The array function can not have multiple signatures, have to warn the deprecated usage
|
|
13
|
+
if (typeof options === 'string') {
|
|
14
|
+
console.warn('Deprecated: Use the object parameter for handleSignIn instead.');
|
|
15
|
+
return this.handleSignInImplementation({ redirectUri: options, interactionMode });
|
|
21
16
|
}
|
|
22
|
-
return
|
|
17
|
+
return this.handleSignInImplementation(options ?? {
|
|
18
|
+
redirectUri: `${this.config.baseUrl}/api/logto/sign-in-callback`,
|
|
19
|
+
});
|
|
23
20
|
};
|
|
24
21
|
this.handleSignOut = (redirectUri = this.config.baseUrl) => async (request) => {
|
|
25
22
|
const { nodeClient, headers } = await this.createNodeClientFromEdgeRequest(request);
|
|
26
23
|
await nodeClient.signOut(redirectUri);
|
|
27
24
|
await this.storage?.destroy();
|
|
28
|
-
await this.storage?.save();
|
|
29
25
|
const response = new Response(null, {
|
|
30
26
|
headers,
|
|
31
27
|
status: 307,
|
|
@@ -43,7 +39,6 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
43
39
|
const requestUrl = new URL(request.url);
|
|
44
40
|
const callbackUrl = new URL(`${requestUrl.pathname}${requestUrl.search}${requestUrl.hash}`, this.config.baseUrl);
|
|
45
41
|
await nodeClient.handleSignInCallback(callbackUrl.toString());
|
|
46
|
-
await this.storage?.save();
|
|
47
42
|
}
|
|
48
43
|
const response = new Response(null, {
|
|
49
44
|
status: 307,
|
|
@@ -64,25 +59,43 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
64
59
|
this.getLogtoContext = async (request, config = {}) => {
|
|
65
60
|
const { nodeClient } = await this.createNodeClientFromEdgeRequest(request);
|
|
66
61
|
const context = await nodeClient.getContext(config);
|
|
67
|
-
await this.storage?.save();
|
|
68
62
|
return context;
|
|
69
63
|
};
|
|
64
|
+
this.handleSignInImplementation = (options) => async (request) => {
|
|
65
|
+
const { nodeClient, headers } = await this.createNodeClientFromEdgeRequest(request);
|
|
66
|
+
await nodeClient.signIn(options);
|
|
67
|
+
const response = new Response(null, {
|
|
68
|
+
headers,
|
|
69
|
+
status: 307,
|
|
70
|
+
});
|
|
71
|
+
if (this.navigateUrl) {
|
|
72
|
+
response.headers.append('Location', this.navigateUrl);
|
|
73
|
+
}
|
|
74
|
+
return response;
|
|
75
|
+
};
|
|
70
76
|
}
|
|
71
77
|
async createNodeClientFromEdgeRequest(request) {
|
|
72
|
-
const cookieName = `logto:${this.config.appId}`;
|
|
73
78
|
const cookies = new RequestCookies(request.headers);
|
|
74
79
|
const headers = new Headers();
|
|
75
80
|
const responseCookies = new ResponseCookies(headers);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
81
|
+
this.storage = new CookieStorage({
|
|
82
|
+
encryptionKey: this.config.cookieSecret,
|
|
83
|
+
cookieKey: `logto:${this.config.appId}`,
|
|
84
|
+
isSecure: this.config.cookieSecure,
|
|
85
|
+
getCookie: (name) => {
|
|
86
|
+
return cookies.get(name)?.value ?? '';
|
|
87
|
+
},
|
|
88
|
+
setCookie: (name, value, options) => {
|
|
89
|
+
responseCookies.set(name, value, options);
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
await this.storage.init();
|
|
93
|
+
const nodeClient = new this.adapters.NodeClient(this.config, {
|
|
94
|
+
storage: this.storage,
|
|
95
|
+
navigate: (url) => {
|
|
96
|
+
this.navigateUrl = url;
|
|
97
|
+
},
|
|
98
|
+
});
|
|
86
99
|
return { nodeClient, headers };
|
|
87
100
|
}
|
|
88
101
|
}
|
|
@@ -16,36 +16,30 @@ class LogtoClient extends client.default {
|
|
|
16
16
|
NodeClient: NodeClient__default.default,
|
|
17
17
|
});
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
* @returns the url to redirect to and new cookie if any
|
|
26
|
-
*/
|
|
27
|
-
async handleSignIn(cookie, redirectUri, interactionMode) {
|
|
28
|
-
const { nodeClient, session } = await this.createNodeClientFromHeaders(cookie);
|
|
29
|
-
await nodeClient.signIn(redirectUri, interactionMode);
|
|
19
|
+
async handleSignIn(options, interactionMode) {
|
|
20
|
+
const nodeClient = await this.createNodeClient();
|
|
21
|
+
const finalOptions = typeof options === 'string' || options instanceof URL
|
|
22
|
+
? { redirectUri: options, interactionMode }
|
|
23
|
+
: options;
|
|
24
|
+
await nodeClient.signIn(finalOptions);
|
|
30
25
|
if (!this.navigateUrl) {
|
|
31
26
|
// Not expected to happen
|
|
32
27
|
throw new Error('navigateUrl is not set');
|
|
33
28
|
}
|
|
34
29
|
return {
|
|
35
30
|
url: this.navigateUrl,
|
|
36
|
-
newCookie: await session.getValues?.(),
|
|
37
31
|
};
|
|
38
32
|
}
|
|
39
33
|
/**
|
|
40
34
|
* Init sign-out and return the url to redirect to Logto.
|
|
41
35
|
*
|
|
42
|
-
* @param cookie the raw cookie string
|
|
43
36
|
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
44
37
|
* @returns the url to redirect to
|
|
45
38
|
*/
|
|
46
|
-
async handleSignOut(
|
|
47
|
-
const
|
|
39
|
+
async handleSignOut(redirectUri = this.config.baseUrl) {
|
|
40
|
+
const nodeClient = await this.createNodeClient();
|
|
48
41
|
await nodeClient.signOut(redirectUri);
|
|
42
|
+
await this.storage?.destroy();
|
|
49
43
|
if (!this.navigateUrl) {
|
|
50
44
|
// Not expected to happen
|
|
51
45
|
throw new Error('navigateUrl is not set');
|
|
@@ -55,34 +49,46 @@ class LogtoClient extends client.default {
|
|
|
55
49
|
/**
|
|
56
50
|
* Handle sign-in callback from Logto.
|
|
57
51
|
*
|
|
58
|
-
* @param cookie the raw cookie string
|
|
59
52
|
* @param callbackUrl the uri (callbackUri) to redirect to after sign in, should match the one used in handleSignIn
|
|
60
|
-
* @returns new cookie if any
|
|
61
53
|
*/
|
|
62
|
-
async handleSignInCallback(
|
|
63
|
-
const
|
|
54
|
+
async handleSignInCallback(callbackUrl) {
|
|
55
|
+
const nodeClient = await this.createNodeClient();
|
|
64
56
|
await nodeClient.handleSignInCallback(callbackUrl);
|
|
65
|
-
return session.getValues?.();
|
|
66
57
|
}
|
|
67
58
|
/**
|
|
68
59
|
* Get Logto context from cookies.
|
|
69
60
|
*
|
|
70
|
-
* @param cookie the raw cookie string
|
|
71
61
|
* @param config additional configs of GetContextParameters
|
|
72
62
|
* @returns LogtoContext
|
|
73
63
|
*/
|
|
74
|
-
async getLogtoContext(
|
|
75
|
-
const
|
|
64
|
+
async getLogtoContext(config = {}) {
|
|
65
|
+
const nodeClient = await this.createNodeClient({ ignoreCookieChange: true });
|
|
76
66
|
const context = await nodeClient.getContext(config);
|
|
77
67
|
return context;
|
|
78
68
|
}
|
|
79
|
-
async
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
69
|
+
async createNodeClient({ ignoreCookieChange } = {}) {
|
|
70
|
+
const { cookies } = await import('next/headers');
|
|
71
|
+
this.storage = new NodeClient$1.CookieStorage({
|
|
72
|
+
encryptionKey: this.config.cookieSecret,
|
|
73
|
+
cookieKey: `logto:${this.config.appId}`,
|
|
74
|
+
isSecure: this.config.cookieSecure,
|
|
75
|
+
getCookie: (...args) => {
|
|
76
|
+
return cookies().get(...args)?.value ?? '';
|
|
77
|
+
},
|
|
78
|
+
setCookie: (...args) => {
|
|
79
|
+
// In server component (RSC), it is not allowed to modify cookies, see https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options.
|
|
80
|
+
if (!ignoreCookieChange) {
|
|
81
|
+
cookies().set(...args);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
await this.storage.init();
|
|
86
|
+
return new this.adapters.NodeClient(this.config, {
|
|
87
|
+
storage: this.storage,
|
|
88
|
+
navigate: (url) => {
|
|
89
|
+
this.navigateUrl = url;
|
|
90
|
+
},
|
|
91
|
+
});
|
|
86
92
|
}
|
|
87
93
|
}
|
|
88
94
|
|
|
@@ -1,47 +1,51 @@
|
|
|
1
|
-
import { type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
1
|
+
import { type SignInOptions, type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
2
2
|
import BaseClient from '../src/client';
|
|
3
3
|
import type { LogtoNextConfig } from '../src/types.js';
|
|
4
4
|
export type { LogtoContext, InteractionMode } from '@logto/node';
|
|
5
5
|
export default class LogtoClient extends BaseClient {
|
|
6
6
|
constructor(config: LogtoNextConfig);
|
|
7
|
+
/**
|
|
8
|
+
* Start the sign-in flow with the specified options.
|
|
9
|
+
*
|
|
10
|
+
* @param options The options for the sign-in flow.
|
|
11
|
+
*/
|
|
12
|
+
handleSignIn(options: SignInOptions): Promise<{
|
|
13
|
+
url: string;
|
|
14
|
+
newCookie?: string;
|
|
15
|
+
}>;
|
|
7
16
|
/**
|
|
8
17
|
* Init sign-in and return the url to redirect to Logto.
|
|
9
18
|
*
|
|
10
|
-
* @
|
|
19
|
+
* @deprecated Use the object parameter instead.
|
|
11
20
|
* @param redirectUri the uri (callbackUri) to redirect to after sign in
|
|
12
21
|
* @param interactionMode OIDC interaction mode
|
|
13
|
-
* @returns the url to redirect
|
|
22
|
+
* @returns the url to redirect
|
|
14
23
|
*/
|
|
15
|
-
handleSignIn(
|
|
24
|
+
handleSignIn(redirectUri: string, interactionMode?: InteractionMode): Promise<{
|
|
16
25
|
url: string;
|
|
17
26
|
newCookie?: string;
|
|
18
27
|
}>;
|
|
19
28
|
/**
|
|
20
29
|
* Init sign-out and return the url to redirect to Logto.
|
|
21
30
|
*
|
|
22
|
-
* @param cookie the raw cookie string
|
|
23
31
|
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
24
32
|
* @returns the url to redirect to
|
|
25
33
|
*/
|
|
26
|
-
handleSignOut(
|
|
34
|
+
handleSignOut(redirectUri?: string): Promise<string>;
|
|
27
35
|
/**
|
|
28
36
|
* Handle sign-in callback from Logto.
|
|
29
37
|
*
|
|
30
|
-
* @param cookie the raw cookie string
|
|
31
38
|
* @param callbackUrl the uri (callbackUri) to redirect to after sign in, should match the one used in handleSignIn
|
|
32
|
-
* @returns new cookie if any
|
|
33
39
|
*/
|
|
34
|
-
handleSignInCallback(
|
|
40
|
+
handleSignInCallback(callbackUrl: string): Promise<void>;
|
|
35
41
|
/**
|
|
36
42
|
* Get Logto context from cookies.
|
|
37
43
|
*
|
|
38
|
-
* @param cookie the raw cookie string
|
|
39
44
|
* @param config additional configs of GetContextParameters
|
|
40
45
|
* @returns LogtoContext
|
|
41
46
|
*/
|
|
42
|
-
getLogtoContext(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
}>;
|
|
47
|
+
getLogtoContext(config?: GetContextParameters): Promise<import("@logto/node").LogtoContext>;
|
|
48
|
+
createNodeClient({ ignoreCookieChange }?: {
|
|
49
|
+
ignoreCookieChange?: boolean;
|
|
50
|
+
}): Promise<import("@logto/node").default>;
|
|
47
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CookieStorage } from '@logto/node';
|
|
2
2
|
import NodeClient from '@logto/node/edge';
|
|
3
3
|
import LogtoNextBaseClient from '../src/client.js';
|
|
4
4
|
|
|
@@ -8,36 +8,30 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
8
8
|
NodeClient,
|
|
9
9
|
});
|
|
10
10
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* @returns the url to redirect to and new cookie if any
|
|
18
|
-
*/
|
|
19
|
-
async handleSignIn(cookie, redirectUri, interactionMode) {
|
|
20
|
-
const { nodeClient, session } = await this.createNodeClientFromHeaders(cookie);
|
|
21
|
-
await nodeClient.signIn(redirectUri, interactionMode);
|
|
11
|
+
async handleSignIn(options, interactionMode) {
|
|
12
|
+
const nodeClient = await this.createNodeClient();
|
|
13
|
+
const finalOptions = typeof options === 'string' || options instanceof URL
|
|
14
|
+
? { redirectUri: options, interactionMode }
|
|
15
|
+
: options;
|
|
16
|
+
await nodeClient.signIn(finalOptions);
|
|
22
17
|
if (!this.navigateUrl) {
|
|
23
18
|
// Not expected to happen
|
|
24
19
|
throw new Error('navigateUrl is not set');
|
|
25
20
|
}
|
|
26
21
|
return {
|
|
27
22
|
url: this.navigateUrl,
|
|
28
|
-
newCookie: await session.getValues?.(),
|
|
29
23
|
};
|
|
30
24
|
}
|
|
31
25
|
/**
|
|
32
26
|
* Init sign-out and return the url to redirect to Logto.
|
|
33
27
|
*
|
|
34
|
-
* @param cookie the raw cookie string
|
|
35
28
|
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
36
29
|
* @returns the url to redirect to
|
|
37
30
|
*/
|
|
38
|
-
async handleSignOut(
|
|
39
|
-
const
|
|
31
|
+
async handleSignOut(redirectUri = this.config.baseUrl) {
|
|
32
|
+
const nodeClient = await this.createNodeClient();
|
|
40
33
|
await nodeClient.signOut(redirectUri);
|
|
34
|
+
await this.storage?.destroy();
|
|
41
35
|
if (!this.navigateUrl) {
|
|
42
36
|
// Not expected to happen
|
|
43
37
|
throw new Error('navigateUrl is not set');
|
|
@@ -47,34 +41,46 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
47
41
|
/**
|
|
48
42
|
* Handle sign-in callback from Logto.
|
|
49
43
|
*
|
|
50
|
-
* @param cookie the raw cookie string
|
|
51
44
|
* @param callbackUrl the uri (callbackUri) to redirect to after sign in, should match the one used in handleSignIn
|
|
52
|
-
* @returns new cookie if any
|
|
53
45
|
*/
|
|
54
|
-
async handleSignInCallback(
|
|
55
|
-
const
|
|
46
|
+
async handleSignInCallback(callbackUrl) {
|
|
47
|
+
const nodeClient = await this.createNodeClient();
|
|
56
48
|
await nodeClient.handleSignInCallback(callbackUrl);
|
|
57
|
-
return session.getValues?.();
|
|
58
49
|
}
|
|
59
50
|
/**
|
|
60
51
|
* Get Logto context from cookies.
|
|
61
52
|
*
|
|
62
|
-
* @param cookie the raw cookie string
|
|
63
53
|
* @param config additional configs of GetContextParameters
|
|
64
54
|
* @returns LogtoContext
|
|
65
55
|
*/
|
|
66
|
-
async getLogtoContext(
|
|
67
|
-
const
|
|
56
|
+
async getLogtoContext(config = {}) {
|
|
57
|
+
const nodeClient = await this.createNodeClient({ ignoreCookieChange: true });
|
|
68
58
|
const context = await nodeClient.getContext(config);
|
|
69
59
|
return context;
|
|
70
60
|
}
|
|
71
|
-
async
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
async createNodeClient({ ignoreCookieChange } = {}) {
|
|
62
|
+
const { cookies } = await import('next/headers');
|
|
63
|
+
this.storage = new CookieStorage({
|
|
64
|
+
encryptionKey: this.config.cookieSecret,
|
|
65
|
+
cookieKey: `logto:${this.config.appId}`,
|
|
66
|
+
isSecure: this.config.cookieSecure,
|
|
67
|
+
getCookie: (...args) => {
|
|
68
|
+
return cookies().get(...args)?.value ?? '';
|
|
69
|
+
},
|
|
70
|
+
setCookie: (...args) => {
|
|
71
|
+
// In server component (RSC), it is not allowed to modify cookies, see https://nextjs.org/docs/app/api-reference/functions/cookies#cookiessetname-value-options.
|
|
72
|
+
if (!ignoreCookieChange) {
|
|
73
|
+
cookies().set(...args);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
await this.storage.init();
|
|
78
|
+
return new this.adapters.NodeClient(this.config, {
|
|
79
|
+
storage: this.storage,
|
|
80
|
+
navigate: (url) => {
|
|
81
|
+
this.navigateUrl = url;
|
|
82
|
+
},
|
|
83
|
+
});
|
|
78
84
|
}
|
|
79
85
|
}
|
|
80
86
|
|
|
@@ -4,38 +4,30 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var navigation = require('next/navigation');
|
|
6
6
|
var client = require('./client.cjs');
|
|
7
|
-
var cookie = require('./cookie.cjs');
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
* Init sign in process and redirect to the Logto sign-in page
|
|
11
|
-
*/
|
|
12
|
-
const signIn = async (config, redirectUri, interactionMode) => {
|
|
8
|
+
async function signIn(config, options, interactionMode) {
|
|
13
9
|
const client$1 = new client.default(config);
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
}
|
|
10
|
+
const finalOptions = typeof options === 'string' || options === undefined
|
|
11
|
+
? { redirectUri: options ?? `${config.baseUrl}/callback`, interactionMode }
|
|
12
|
+
: options;
|
|
13
|
+
const { url } = await client$1.handleSignIn(finalOptions);
|
|
18
14
|
navigation.redirect(url);
|
|
19
|
-
}
|
|
15
|
+
}
|
|
20
16
|
/**
|
|
21
17
|
* Handle sign in callback from search params or full redirect URL, save tokens to session
|
|
22
18
|
*/
|
|
23
19
|
async function handleSignIn(config, searchParamsOrUrl) {
|
|
24
20
|
const client$1 = new client.default(config);
|
|
25
|
-
|
|
21
|
+
await client$1.handleSignInCallback(searchParamsOrUrl instanceof URL
|
|
26
22
|
? searchParamsOrUrl.toString()
|
|
27
23
|
: `${config.baseUrl}/callback?${searchParamsOrUrl.toString()}`);
|
|
28
|
-
if (newCookie) {
|
|
29
|
-
await cookie.setCookies(newCookie, config);
|
|
30
|
-
}
|
|
31
24
|
}
|
|
32
25
|
/**
|
|
33
26
|
* Init sign out process, clear session, and redirect to the Logto sign-out page
|
|
34
27
|
*/
|
|
35
28
|
const signOut = async (config, redirectUri) => {
|
|
36
29
|
const client$1 = new client.default(config);
|
|
37
|
-
const url = await client$1.handleSignOut(
|
|
38
|
-
await cookie.setCookies('', config);
|
|
30
|
+
const url = await client$1.handleSignOut(redirectUri);
|
|
39
31
|
navigation.redirect(url);
|
|
40
32
|
};
|
|
41
33
|
/**
|
|
@@ -43,7 +35,7 @@ const signOut = async (config, redirectUri) => {
|
|
|
43
35
|
*/
|
|
44
36
|
const getLogtoContext = async (config, getContextParameters) => {
|
|
45
37
|
const client$1 = new client.default(config);
|
|
46
|
-
return client$1.getLogtoContext(
|
|
38
|
+
return client$1.getLogtoContext(getContextParameters);
|
|
47
39
|
};
|
|
48
40
|
/**
|
|
49
41
|
* Get organization tokens from session
|
|
@@ -56,7 +48,7 @@ const getOrganizationTokens = async (config) => {
|
|
|
56
48
|
return [];
|
|
57
49
|
}
|
|
58
50
|
const client$1 = new client.default(config);
|
|
59
|
-
const
|
|
51
|
+
const nodeClient = await client$1.createNodeClient();
|
|
60
52
|
const { organizations = [] } = await nodeClient.getIdTokenClaims();
|
|
61
53
|
return Promise.all(organizations.map(async (organizationId) => ({
|
|
62
54
|
id: organizationId,
|
|
@@ -69,13 +61,8 @@ const getOrganizationTokens = async (config) => {
|
|
|
69
61
|
*/
|
|
70
62
|
const getAccessToken = async (config, resource, organizationId) => {
|
|
71
63
|
const client$1 = new client.default(config);
|
|
72
|
-
const
|
|
64
|
+
const nodeClient = await client$1.createNodeClient();
|
|
73
65
|
const accessToken = await nodeClient.getAccessToken(resource, organizationId);
|
|
74
|
-
// Update access token cache
|
|
75
|
-
const newCookie = await session.getValues?.();
|
|
76
|
-
if (newCookie) {
|
|
77
|
-
await cookie.setCookies(newCookie, config);
|
|
78
|
-
}
|
|
79
66
|
return accessToken;
|
|
80
67
|
};
|
|
81
68
|
/**
|
|
@@ -93,7 +80,7 @@ const getOrganizationToken = async (config, organizationId) => {
|
|
|
93
80
|
*/
|
|
94
81
|
const getAccessTokenRSC = async (config, resource, organizationId) => {
|
|
95
82
|
const client$1 = new client.default(config);
|
|
96
|
-
const
|
|
83
|
+
const nodeClient = await client$1.createNodeClient({ ignoreCookieChange: true });
|
|
97
84
|
return nodeClient.getAccessToken(resource, organizationId);
|
|
98
85
|
};
|
|
99
86
|
/**
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
-
import { type LogtoContext, type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
1
|
+
import { type LogtoContext, type GetContextParameters, type InteractionMode, type SignInOptions } from '@logto/node';
|
|
2
2
|
import type { LogtoNextConfig } from '../src/types.js';
|
|
3
3
|
export type { LogtoContext, InteractionMode } from '@logto/node';
|
|
4
4
|
/**
|
|
5
5
|
* Init sign in process and redirect to the Logto sign-in page
|
|
6
6
|
*/
|
|
7
|
-
export declare
|
|
7
|
+
export declare function signIn(config: LogtoNextConfig, options?: SignInOptions): Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Init sign in process and redirect to the Logto sign-in page
|
|
10
|
+
*
|
|
11
|
+
* @deprecated Use the object parameter instead.
|
|
12
|
+
*/
|
|
13
|
+
export declare function signIn(config: LogtoNextConfig, redirectUri?: string, interactionMode?: InteractionMode): Promise<void>;
|
|
8
14
|
export declare function handleSignIn(config: LogtoNextConfig, searchParams: URLSearchParams): Promise<void>;
|
|
9
15
|
export declare function handleSignIn(config: LogtoNextConfig, url: URL): Promise<void>;
|
|
10
16
|
/**
|
|
@@ -1,37 +1,29 @@
|
|
|
1
1
|
import { redirect } from 'next/navigation';
|
|
2
2
|
import LogtoClient from './client.js';
|
|
3
|
-
import { getCookies, setCookies } from './cookie.js';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
* Init sign in process and redirect to the Logto sign-in page
|
|
7
|
-
*/
|
|
8
|
-
const signIn = async (config, redirectUri, interactionMode) => {
|
|
4
|
+
async function signIn(config, options, interactionMode) {
|
|
9
5
|
const client = new LogtoClient(config);
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
}
|
|
6
|
+
const finalOptions = typeof options === 'string' || options === undefined
|
|
7
|
+
? { redirectUri: options ?? `${config.baseUrl}/callback`, interactionMode }
|
|
8
|
+
: options;
|
|
9
|
+
const { url } = await client.handleSignIn(finalOptions);
|
|
14
10
|
redirect(url);
|
|
15
|
-
}
|
|
11
|
+
}
|
|
16
12
|
/**
|
|
17
13
|
* Handle sign in callback from search params or full redirect URL, save tokens to session
|
|
18
14
|
*/
|
|
19
15
|
async function handleSignIn(config, searchParamsOrUrl) {
|
|
20
16
|
const client = new LogtoClient(config);
|
|
21
|
-
|
|
17
|
+
await client.handleSignInCallback(searchParamsOrUrl instanceof URL
|
|
22
18
|
? searchParamsOrUrl.toString()
|
|
23
19
|
: `${config.baseUrl}/callback?${searchParamsOrUrl.toString()}`);
|
|
24
|
-
if (newCookie) {
|
|
25
|
-
await setCookies(newCookie, config);
|
|
26
|
-
}
|
|
27
20
|
}
|
|
28
21
|
/**
|
|
29
22
|
* Init sign out process, clear session, and redirect to the Logto sign-out page
|
|
30
23
|
*/
|
|
31
24
|
const signOut = async (config, redirectUri) => {
|
|
32
25
|
const client = new LogtoClient(config);
|
|
33
|
-
const url = await client.handleSignOut(
|
|
34
|
-
await setCookies('', config);
|
|
26
|
+
const url = await client.handleSignOut(redirectUri);
|
|
35
27
|
redirect(url);
|
|
36
28
|
};
|
|
37
29
|
/**
|
|
@@ -39,7 +31,7 @@ const signOut = async (config, redirectUri) => {
|
|
|
39
31
|
*/
|
|
40
32
|
const getLogtoContext = async (config, getContextParameters) => {
|
|
41
33
|
const client = new LogtoClient(config);
|
|
42
|
-
return client.getLogtoContext(
|
|
34
|
+
return client.getLogtoContext(getContextParameters);
|
|
43
35
|
};
|
|
44
36
|
/**
|
|
45
37
|
* Get organization tokens from session
|
|
@@ -52,7 +44,7 @@ const getOrganizationTokens = async (config) => {
|
|
|
52
44
|
return [];
|
|
53
45
|
}
|
|
54
46
|
const client = new LogtoClient(config);
|
|
55
|
-
const
|
|
47
|
+
const nodeClient = await client.createNodeClient();
|
|
56
48
|
const { organizations = [] } = await nodeClient.getIdTokenClaims();
|
|
57
49
|
return Promise.all(organizations.map(async (organizationId) => ({
|
|
58
50
|
id: organizationId,
|
|
@@ -65,13 +57,8 @@ const getOrganizationTokens = async (config) => {
|
|
|
65
57
|
*/
|
|
66
58
|
const getAccessToken = async (config, resource, organizationId) => {
|
|
67
59
|
const client = new LogtoClient(config);
|
|
68
|
-
const
|
|
60
|
+
const nodeClient = await client.createNodeClient();
|
|
69
61
|
const accessToken = await nodeClient.getAccessToken(resource, organizationId);
|
|
70
|
-
// Update access token cache
|
|
71
|
-
const newCookie = await session.getValues?.();
|
|
72
|
-
if (newCookie) {
|
|
73
|
-
await setCookies(newCookie, config);
|
|
74
|
-
}
|
|
75
62
|
return accessToken;
|
|
76
63
|
};
|
|
77
64
|
/**
|
|
@@ -89,7 +76,7 @@ const getOrganizationToken = async (config, organizationId) => {
|
|
|
89
76
|
*/
|
|
90
77
|
const getAccessTokenRSC = async (config, resource, organizationId) => {
|
|
91
78
|
const client = new LogtoClient(config);
|
|
92
|
-
const
|
|
79
|
+
const nodeClient = await client.createNodeClient({ ignoreCookieChange: true });
|
|
93
80
|
return nodeClient.getAccessToken(resource, organizationId);
|
|
94
81
|
};
|
|
95
82
|
/**
|
package/lib/src/client.cjs
CHANGED
|
@@ -2,22 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var storage = require('./storage.cjs');
|
|
6
|
-
|
|
7
5
|
class LogtoNextBaseClient {
|
|
8
6
|
constructor(config, adapters) {
|
|
9
7
|
this.config = config;
|
|
10
8
|
this.adapters = adapters;
|
|
11
9
|
}
|
|
12
|
-
createNodeClient(session) {
|
|
13
|
-
this.storage = new storage.default(session);
|
|
14
|
-
return new this.adapters.NodeClient(this.config, {
|
|
15
|
-
storage: this.storage,
|
|
16
|
-
navigate: (url) => {
|
|
17
|
-
this.navigateUrl = url;
|
|
18
|
-
},
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
10
|
}
|
|
22
11
|
|
|
23
12
|
exports.default = LogtoNextBaseClient;
|
package/lib/src/client.d.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
import { type
|
|
2
|
-
import NextStorage from './storage';
|
|
1
|
+
import { type CookieStorage } from '@logto/node';
|
|
3
2
|
import type { Adapters, LogtoNextConfig } from './types';
|
|
4
3
|
export default class LogtoNextBaseClient {
|
|
5
4
|
protected readonly config: LogtoNextConfig;
|
|
6
5
|
protected readonly adapters: Adapters;
|
|
7
6
|
protected navigateUrl?: string;
|
|
8
|
-
protected storage?:
|
|
7
|
+
protected storage?: CookieStorage;
|
|
9
8
|
constructor(config: LogtoNextConfig, adapters: Adapters);
|
|
10
|
-
protected createNodeClient(session: Session): import("@logto/node").default;
|
|
11
9
|
}
|
package/lib/src/client.js
CHANGED
|
@@ -1,19 +1,8 @@
|
|
|
1
|
-
import NextStorage from './storage.js';
|
|
2
|
-
|
|
3
1
|
class LogtoNextBaseClient {
|
|
4
2
|
constructor(config, adapters) {
|
|
5
3
|
this.config = config;
|
|
6
4
|
this.adapters = adapters;
|
|
7
5
|
}
|
|
8
|
-
createNodeClient(session) {
|
|
9
|
-
this.storage = new NextStorage(session);
|
|
10
|
-
return new this.adapters.NodeClient(this.config, {
|
|
11
|
-
storage: this.storage,
|
|
12
|
-
navigate: (url) => {
|
|
13
|
-
this.navigateUrl = url;
|
|
14
|
-
},
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
6
|
}
|
|
18
7
|
|
|
19
8
|
export { LogtoNextBaseClient as default };
|
package/lib/src/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var NodeClient = require('@logto/node');
|
|
6
|
+
var cookie = require('cookie');
|
|
6
7
|
var client = require('./client.cjs');
|
|
7
8
|
var utils = require('./utils.cjs');
|
|
8
9
|
|
|
@@ -15,19 +16,21 @@ class LogtoClient extends client.default {
|
|
|
15
16
|
super(config, {
|
|
16
17
|
NodeClient: NodeClient__default.default,
|
|
17
18
|
});
|
|
18
|
-
this.handleSignIn = (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
response.redirect(this.navigateUrl);
|
|
19
|
+
this.handleSignIn = (options, interactionMode, onError) => {
|
|
20
|
+
// The array function can not have multiple signatures, have to warn the deprecated usage
|
|
21
|
+
if (typeof options === 'string') {
|
|
22
|
+
console.warn('Deprecated: Use the object parameter for handleSignIn instead.');
|
|
23
|
+
return this.handleSignInImplementation({ redirectUri: options, interactionMode, onError });
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
return this.handleSignInImplementation(options ?? {
|
|
26
|
+
redirectUri: `${this.config.baseUrl}/api/logto/sign-in-callback`,
|
|
27
|
+
interactionMode,
|
|
28
|
+
});
|
|
29
|
+
};
|
|
26
30
|
this.handleSignInCallback = (redirectTo = this.config.baseUrl, onError) => utils.buildHandler(async (request, response) => {
|
|
27
31
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
28
32
|
if (request.url) {
|
|
29
33
|
await nodeClient.handleSignInCallback(`${this.config.baseUrl}${request.url}`);
|
|
30
|
-
await this.storage?.save();
|
|
31
34
|
response.redirect(redirectTo);
|
|
32
35
|
}
|
|
33
36
|
}, onError);
|
|
@@ -35,7 +38,6 @@ class LogtoClient extends client.default {
|
|
|
35
38
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
36
39
|
await nodeClient.signOut(redirectUri);
|
|
37
40
|
await this.storage?.destroy();
|
|
38
|
-
await this.storage?.save();
|
|
39
41
|
if (this.navigateUrl) {
|
|
40
42
|
response.redirect(this.navigateUrl);
|
|
41
43
|
}
|
|
@@ -73,7 +75,6 @@ class LogtoClient extends client.default {
|
|
|
73
75
|
this.withLogtoApiRoute = (handler, config = {}, onError) => utils.buildHandler(async (request, response) => {
|
|
74
76
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
75
77
|
const user = await nodeClient.getContext(config);
|
|
76
|
-
await this.storage?.save();
|
|
77
78
|
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
|
78
79
|
Object.defineProperty(request, 'user', { enumerable: true, get: () => user });
|
|
79
80
|
return handler(request, response);
|
|
@@ -83,17 +84,33 @@ class LogtoClient extends client.default {
|
|
|
83
84
|
return handler(context);
|
|
84
85
|
}, configs, onError);
|
|
85
86
|
};
|
|
87
|
+
this.handleSignInImplementation = (options) => utils.buildHandler(async (request, response) => {
|
|
88
|
+
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
89
|
+
await nodeClient.signIn(options);
|
|
90
|
+
if (this.navigateUrl) {
|
|
91
|
+
response.redirect(this.navigateUrl);
|
|
92
|
+
}
|
|
93
|
+
}, options.onError);
|
|
86
94
|
}
|
|
87
95
|
async createNodeClientFromNextApi(request, response) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
this.storage = new NodeClient.CookieStorage({
|
|
97
|
+
encryptionKey: this.config.cookieSecret,
|
|
98
|
+
cookieKey: `logto:${this.config.appId}`,
|
|
99
|
+
isSecure: this.config.cookieSecure,
|
|
100
|
+
getCookie: (name) => {
|
|
101
|
+
return request.cookies[name] ?? '';
|
|
102
|
+
},
|
|
103
|
+
setCookie: (name, value, options) => {
|
|
104
|
+
response.setHeader('Set-Cookie', cookie.serialize(name, value, options));
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
await this.storage.init();
|
|
108
|
+
return new this.adapters.NodeClient(this.config, {
|
|
109
|
+
storage: this.storage,
|
|
110
|
+
navigate: (url) => {
|
|
111
|
+
this.navigateUrl = url;
|
|
112
|
+
},
|
|
113
|
+
});
|
|
97
114
|
}
|
|
98
115
|
}
|
|
99
116
|
|
package/lib/src/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
3
|
-
import NodeClient, { type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
3
|
+
import NodeClient, { type SignInOptions, type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
4
4
|
import { type GetServerSidePropsResult, type GetServerSidePropsContext, type NextApiHandler, type NextApiRequest, type NextApiResponse } from 'next';
|
|
5
5
|
import { type NextApiRequestCookies } from 'next/dist/server/api-utils/index.js';
|
|
6
6
|
import LogtoNextBaseClient from './client.js';
|
|
@@ -10,7 +10,9 @@ export { LogtoError, LogtoRequestError, LogtoClientError, OidcError, Prompt, Res
|
|
|
10
10
|
export type { AccessTokenClaims, IdTokenClaims, LogtoContext, InteractionMode, LogtoErrorCode, UserInfoResponse, } from '@logto/node';
|
|
11
11
|
export default class LogtoClient extends LogtoNextBaseClient {
|
|
12
12
|
constructor(config: LogtoNextConfig);
|
|
13
|
-
handleSignIn: (
|
|
13
|
+
handleSignIn: (options?: (SignInOptions & {
|
|
14
|
+
onError?: ErrorHandler;
|
|
15
|
+
}) | string, interactionMode?: InteractionMode, onError?: ErrorHandler) => NextApiHandler;
|
|
14
16
|
handleSignInCallback: (redirectTo?: string, onError?: ErrorHandler) => NextApiHandler;
|
|
15
17
|
handleSignOut: (redirectUri?: string, onError?: ErrorHandler) => NextApiHandler;
|
|
16
18
|
handleUser: (configs?: GetContextParameters, onError?: ErrorHandler) => NextApiHandler;
|
|
@@ -22,4 +24,5 @@ export default class LogtoClient extends LogtoNextBaseClient {
|
|
|
22
24
|
createNodeClientFromNextApi(request: IncomingMessage & {
|
|
23
25
|
cookies: NextApiRequestCookies;
|
|
24
26
|
}, response: ServerResponse): Promise<NodeClient>;
|
|
27
|
+
private readonly handleSignInImplementation;
|
|
25
28
|
}
|
package/lib/src/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import NodeClient, {
|
|
1
|
+
import NodeClient, { CookieStorage } from '@logto/node';
|
|
2
2
|
export { LogtoClientError, LogtoError, LogtoRequestError, OidcError, PersistKey, Prompt, ReservedResource, ReservedScope, UserScope, buildOrganizationUrn, getOrganizationIdFromUrn, organizationUrnPrefix } from '@logto/node';
|
|
3
|
+
import { serialize } from 'cookie';
|
|
3
4
|
import LogtoNextBaseClient from './client.js';
|
|
4
5
|
import { buildHandler } from './utils.js';
|
|
5
6
|
|
|
@@ -8,19 +9,21 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
8
9
|
super(config, {
|
|
9
10
|
NodeClient,
|
|
10
11
|
});
|
|
11
|
-
this.handleSignIn = (
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
response.redirect(this.navigateUrl);
|
|
12
|
+
this.handleSignIn = (options, interactionMode, onError) => {
|
|
13
|
+
// The array function can not have multiple signatures, have to warn the deprecated usage
|
|
14
|
+
if (typeof options === 'string') {
|
|
15
|
+
console.warn('Deprecated: Use the object parameter for handleSignIn instead.');
|
|
16
|
+
return this.handleSignInImplementation({ redirectUri: options, interactionMode, onError });
|
|
17
17
|
}
|
|
18
|
-
|
|
18
|
+
return this.handleSignInImplementation(options ?? {
|
|
19
|
+
redirectUri: `${this.config.baseUrl}/api/logto/sign-in-callback`,
|
|
20
|
+
interactionMode,
|
|
21
|
+
});
|
|
22
|
+
};
|
|
19
23
|
this.handleSignInCallback = (redirectTo = this.config.baseUrl, onError) => buildHandler(async (request, response) => {
|
|
20
24
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
21
25
|
if (request.url) {
|
|
22
26
|
await nodeClient.handleSignInCallback(`${this.config.baseUrl}${request.url}`);
|
|
23
|
-
await this.storage?.save();
|
|
24
27
|
response.redirect(redirectTo);
|
|
25
28
|
}
|
|
26
29
|
}, onError);
|
|
@@ -28,7 +31,6 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
28
31
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
29
32
|
await nodeClient.signOut(redirectUri);
|
|
30
33
|
await this.storage?.destroy();
|
|
31
|
-
await this.storage?.save();
|
|
32
34
|
if (this.navigateUrl) {
|
|
33
35
|
response.redirect(this.navigateUrl);
|
|
34
36
|
}
|
|
@@ -66,7 +68,6 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
66
68
|
this.withLogtoApiRoute = (handler, config = {}, onError) => buildHandler(async (request, response) => {
|
|
67
69
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
68
70
|
const user = await nodeClient.getContext(config);
|
|
69
|
-
await this.storage?.save();
|
|
70
71
|
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
|
71
72
|
Object.defineProperty(request, 'user', { enumerable: true, get: () => user });
|
|
72
73
|
return handler(request, response);
|
|
@@ -76,17 +77,33 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
76
77
|
return handler(context);
|
|
77
78
|
}, configs, onError);
|
|
78
79
|
};
|
|
80
|
+
this.handleSignInImplementation = (options) => buildHandler(async (request, response) => {
|
|
81
|
+
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
82
|
+
await nodeClient.signIn(options);
|
|
83
|
+
if (this.navigateUrl) {
|
|
84
|
+
response.redirect(this.navigateUrl);
|
|
85
|
+
}
|
|
86
|
+
}, options.onError);
|
|
79
87
|
}
|
|
80
88
|
async createNodeClientFromNextApi(request, response) {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
this.storage = new CookieStorage({
|
|
90
|
+
encryptionKey: this.config.cookieSecret,
|
|
91
|
+
cookieKey: `logto:${this.config.appId}`,
|
|
92
|
+
isSecure: this.config.cookieSecure,
|
|
93
|
+
getCookie: (name) => {
|
|
94
|
+
return request.cookies[name] ?? '';
|
|
95
|
+
},
|
|
96
|
+
setCookie: (name, value, options) => {
|
|
97
|
+
response.setHeader('Set-Cookie', serialize(name, value, options));
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
await this.storage.init();
|
|
101
|
+
return new this.adapters.NodeClient(this.config, {
|
|
102
|
+
storage: this.storage,
|
|
103
|
+
navigate: (url) => {
|
|
104
|
+
this.navigateUrl = url;
|
|
105
|
+
},
|
|
106
|
+
});
|
|
90
107
|
}
|
|
91
108
|
}
|
|
92
109
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/next",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/src/index.cjs",
|
|
6
6
|
"module": "./lib/src/index.js",
|
|
@@ -46,12 +46,14 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@edge-runtime/cookies": "^4.0.0",
|
|
49
|
-
"
|
|
49
|
+
"cookie": "^0.6.0",
|
|
50
|
+
"@logto/node": "^2.5.7"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@silverhand/eslint-config": "^6.0.1",
|
|
53
54
|
"@silverhand/ts-config": "^6.0.0",
|
|
54
55
|
"@silverhand/ts-config-react": "^6.0.0",
|
|
56
|
+
"@types/cookie": "^0.6.0",
|
|
55
57
|
"@vitest/coverage-v8": "^1.6.0",
|
|
56
58
|
"eslint": "^8.57.0",
|
|
57
59
|
"lint-staged": "^15.0.0",
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
const getCookies = async (config) => {
|
|
4
|
-
const { cookies } = await import('next/headers');
|
|
5
|
-
return cookies().get(`logto:${config.appId}`)?.value ?? '';
|
|
6
|
-
};
|
|
7
|
-
const setCookies = async (newCookie, config) => {
|
|
8
|
-
const { cookies } = await import('next/headers');
|
|
9
|
-
cookies().set(`logto:${config.appId}`, newCookie, {
|
|
10
|
-
maxAge: 14 * 3600 * 24,
|
|
11
|
-
secure: config.cookieSecure,
|
|
12
|
-
sameSite: config.cookieSecure ? 'lax' : undefined,
|
|
13
|
-
});
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
exports.getCookies = getCookies;
|
|
17
|
-
exports.setCookies = setCookies;
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
const getCookies = async (config) => {
|
|
2
|
-
const { cookies } = await import('next/headers');
|
|
3
|
-
return cookies().get(`logto:${config.appId}`)?.value ?? '';
|
|
4
|
-
};
|
|
5
|
-
const setCookies = async (newCookie, config) => {
|
|
6
|
-
const { cookies } = await import('next/headers');
|
|
7
|
-
cookies().set(`logto:${config.appId}`, newCookie, {
|
|
8
|
-
maxAge: 14 * 3600 * 24,
|
|
9
|
-
secure: config.cookieSecure,
|
|
10
|
-
sameSite: config.cookieSecure ? 'lax' : undefined,
|
|
11
|
-
});
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
export { getCookies, setCookies };
|
package/lib/src/storage.cjs
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
-
|
|
5
|
-
var NodeClient = require('@logto/node/edge');
|
|
6
|
-
|
|
7
|
-
class NextStorage {
|
|
8
|
-
constructor(session) {
|
|
9
|
-
this.session = session;
|
|
10
|
-
this.sessionChanged = false;
|
|
11
|
-
}
|
|
12
|
-
async setItem(key, value) {
|
|
13
|
-
this.session[key] = value;
|
|
14
|
-
this.sessionChanged = true;
|
|
15
|
-
}
|
|
16
|
-
async getItem(key) {
|
|
17
|
-
const value = this.session[key];
|
|
18
|
-
if (value === undefined) {
|
|
19
|
-
return null;
|
|
20
|
-
}
|
|
21
|
-
return String(value);
|
|
22
|
-
}
|
|
23
|
-
async removeItem(key) {
|
|
24
|
-
this.session[key] = undefined;
|
|
25
|
-
this.sessionChanged = true;
|
|
26
|
-
}
|
|
27
|
-
async destroy() {
|
|
28
|
-
this.session[NodeClient.PersistKey.AccessToken] = undefined;
|
|
29
|
-
this.session[NodeClient.PersistKey.IdToken] = undefined;
|
|
30
|
-
this.session[NodeClient.PersistKey.SignInSession] = undefined;
|
|
31
|
-
this.session[NodeClient.PersistKey.RefreshToken] = undefined;
|
|
32
|
-
this.sessionChanged = true;
|
|
33
|
-
}
|
|
34
|
-
async save() {
|
|
35
|
-
if (!this.sessionChanged) {
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
await this.session.save();
|
|
39
|
-
this.sessionChanged = false;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
exports.default = NextStorage;
|
package/lib/src/storage.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { type Session, type Storage } from '@logto/node';
|
|
2
|
-
import { PersistKey } from '@logto/node/edge';
|
|
3
|
-
export default class NextStorage implements Storage<PersistKey> {
|
|
4
|
-
private readonly session;
|
|
5
|
-
private sessionChanged;
|
|
6
|
-
constructor(session: Session & {
|
|
7
|
-
save: () => Promise<void>;
|
|
8
|
-
});
|
|
9
|
-
setItem(key: PersistKey, value: string): Promise<void>;
|
|
10
|
-
getItem(key: PersistKey): Promise<string | null>;
|
|
11
|
-
removeItem(key: PersistKey): Promise<void>;
|
|
12
|
-
destroy(): Promise<void>;
|
|
13
|
-
save(): Promise<void>;
|
|
14
|
-
}
|
package/lib/src/storage.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { PersistKey } from '@logto/node/edge';
|
|
2
|
-
|
|
3
|
-
class NextStorage {
|
|
4
|
-
constructor(session) {
|
|
5
|
-
this.session = session;
|
|
6
|
-
this.sessionChanged = false;
|
|
7
|
-
}
|
|
8
|
-
async setItem(key, value) {
|
|
9
|
-
this.session[key] = value;
|
|
10
|
-
this.sessionChanged = true;
|
|
11
|
-
}
|
|
12
|
-
async getItem(key) {
|
|
13
|
-
const value = this.session[key];
|
|
14
|
-
if (value === undefined) {
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
return String(value);
|
|
18
|
-
}
|
|
19
|
-
async removeItem(key) {
|
|
20
|
-
this.session[key] = undefined;
|
|
21
|
-
this.sessionChanged = true;
|
|
22
|
-
}
|
|
23
|
-
async destroy() {
|
|
24
|
-
this.session[PersistKey.AccessToken] = undefined;
|
|
25
|
-
this.session[PersistKey.IdToken] = undefined;
|
|
26
|
-
this.session[PersistKey.SignInSession] = undefined;
|
|
27
|
-
this.session[PersistKey.RefreshToken] = undefined;
|
|
28
|
-
this.sessionChanged = true;
|
|
29
|
-
}
|
|
30
|
-
async save() {
|
|
31
|
-
if (!this.sessionChanged) {
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
await this.session.save();
|
|
35
|
-
this.sessionChanged = false;
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export { NextStorage as default };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|