@logto/next 2.4.0 → 3.1.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 +13 -10
- package/lib/edge/index.cjs +3 -2
- package/lib/edge/index.js +2 -1
- package/lib/server-actions/client.cjs +89 -0
- package/lib/server-actions/client.d.ts +47 -0
- package/lib/server-actions/client.js +81 -0
- package/lib/server-actions/cookie.cjs +16 -0
- package/lib/server-actions/cookie.d.ts +3 -0
- package/lib/server-actions/cookie.js +13 -0
- package/lib/server-actions/index.cjs +60 -80
- package/lib/server-actions/index.d.ts +25 -45
- package/lib/server-actions/index.js +55 -76
- package/lib/src/client.d.ts +2 -1
- package/lib/src/index.cjs +16 -35
- package/lib/src/index.d.ts +1 -1
- package/lib/src/index.js +3 -3
- package/lib/src/storage.d.ts +1 -2
- package/lib/src/types.d.ts +1 -11
- package/package.json +4 -7
- package/lib/src/session.cjs +0 -73
- package/lib/src/session.d.ts +0 -9
- package/lib/src/session.js +0 -69
- package/lib/src/session.test.d.ts +0 -1
- /package/lib/server-actions/{index.test.d.ts → client.test.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
# Logto Next.js SDK
|
|
2
|
+
|
|
2
3
|
[](https://www.npmjs.com/package/@logto/next)
|
|
3
4
|
[](https://github.com/logto-io/js/actions/workflows/main.yml)
|
|
4
5
|
[](https://app.codecov.io/gh/logto-io/js?branch=master)
|
|
5
6
|
|
|
6
|
-
The Logto Next.js SDK written in TypeScript.
|
|
7
|
+
The Logto Next.js SDK written in TypeScript.
|
|
8
|
+
|
|
9
|
+
Check out our [docs](https://docs.logto.io/sdk/next) for more information.
|
|
10
|
+
|
|
11
|
+
If you are using App Router and Server Actions, check out the [docs](https://docs.logto.io/sdk/next-app-router) for more information.
|
|
7
12
|
|
|
8
13
|
## Installation
|
|
9
14
|
|
|
@@ -25,18 +30,16 @@ yarn add @logto/next
|
|
|
25
30
|
pnpm add @logto/next
|
|
26
31
|
```
|
|
27
32
|
|
|
28
|
-
##
|
|
29
|
-
|
|
30
|
-
A sample project can be found at [Next.js Sample](https://github.com/logto-io/js/tree/master/packages/next-sample)
|
|
33
|
+
## Products
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
| Name | Description |
|
|
36
|
+
| --------------------- | --------------------------------------------- |
|
|
37
|
+
| @logto/next | Traditional Next.js SDK using Page Router |
|
|
38
|
+
| @logto/edge | Next.js SDK running in edge environment |
|
|
39
|
+
| @logto/server-actions | Next.js SDK for App Router and Server Actions |
|
|
37
40
|
|
|
38
41
|
## Resources
|
|
39
42
|
|
|
40
43
|
[](https://logto.io/)
|
|
41
|
-
[](https://docs.logto.io/
|
|
44
|
+
[](https://docs.logto.io/)
|
|
42
45
|
[](https://discord.gg/UEPaF3j5e6)
|
package/lib/edge/index.cjs
CHANGED
|
@@ -3,9 +3,9 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var cookies = require('@edge-runtime/cookies');
|
|
6
|
+
var NodeClient$1 = require('@logto/node');
|
|
6
7
|
var NodeClient = require('@logto/node/edge');
|
|
7
8
|
var client = require('../src/client.cjs');
|
|
8
|
-
var session = require('../src/session.cjs');
|
|
9
9
|
|
|
10
10
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
11
|
|
|
@@ -72,6 +72,7 @@ class LogtoClient extends client.default {
|
|
|
72
72
|
this.getLogtoContext = async (request, config = {}) => {
|
|
73
73
|
const { nodeClient } = await this.createNodeClientFromEdgeRequest(request);
|
|
74
74
|
const context = await nodeClient.getContext(config);
|
|
75
|
+
await this.storage?.save();
|
|
75
76
|
return context;
|
|
76
77
|
};
|
|
77
78
|
}
|
|
@@ -80,7 +81,7 @@ class LogtoClient extends client.default {
|
|
|
80
81
|
const cookies$1 = new cookies.RequestCookies(request.headers);
|
|
81
82
|
const headers = new Headers();
|
|
82
83
|
const responseCookies = new cookies.ResponseCookies(headers);
|
|
83
|
-
const nodeClient = super.createNodeClient(await
|
|
84
|
+
const nodeClient = super.createNodeClient(await NodeClient$1.createSession({
|
|
84
85
|
secret: this.config.cookieSecret,
|
|
85
86
|
crypto,
|
|
86
87
|
}, cookies$1.get(cookieName)?.value ?? '', (value) => {
|
package/lib/edge/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { RequestCookies, ResponseCookies } from '@edge-runtime/cookies';
|
|
2
|
+
import { createSession } from '@logto/node';
|
|
2
3
|
import NodeClient from '@logto/node/edge';
|
|
3
4
|
import LogtoNextBaseClient from '../src/client.js';
|
|
4
|
-
import { createSession } from '../src/session.js';
|
|
5
5
|
|
|
6
6
|
class LogtoClient extends LogtoNextBaseClient {
|
|
7
7
|
constructor(config) {
|
|
@@ -64,6 +64,7 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
64
64
|
this.getLogtoContext = async (request, config = {}) => {
|
|
65
65
|
const { nodeClient } = await this.createNodeClientFromEdgeRequest(request);
|
|
66
66
|
const context = await nodeClient.getContext(config);
|
|
67
|
+
await this.storage?.save();
|
|
67
68
|
return context;
|
|
68
69
|
};
|
|
69
70
|
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var NodeClient$1 = require('@logto/node');
|
|
6
|
+
var NodeClient = require('@logto/node/edge');
|
|
7
|
+
var client = require('../src/client.cjs');
|
|
8
|
+
|
|
9
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
|
|
11
|
+
var NodeClient__default = /*#__PURE__*/_interopDefault(NodeClient);
|
|
12
|
+
|
|
13
|
+
class LogtoClient extends client.default {
|
|
14
|
+
constructor(config) {
|
|
15
|
+
super(config, {
|
|
16
|
+
NodeClient: NodeClient__default.default,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Init sign-in and return the url to redirect to Logto.
|
|
21
|
+
*
|
|
22
|
+
* @param cookie the raw cookie string
|
|
23
|
+
* @param redirectUri the uri (callbackUri) to redirect to after sign in
|
|
24
|
+
* @param interactionMode OIDC interaction mode
|
|
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);
|
|
30
|
+
if (!this.navigateUrl) {
|
|
31
|
+
// Not expected to happen
|
|
32
|
+
throw new Error('navigateUrl is not set');
|
|
33
|
+
}
|
|
34
|
+
return {
|
|
35
|
+
url: this.navigateUrl,
|
|
36
|
+
newCookie: await session.getValues?.(),
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Init sign-out and return the url to redirect to Logto.
|
|
41
|
+
*
|
|
42
|
+
* @param cookie the raw cookie string
|
|
43
|
+
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
44
|
+
* @returns the url to redirect to
|
|
45
|
+
*/
|
|
46
|
+
async handleSignOut(cookie, redirectUri = this.config.baseUrl) {
|
|
47
|
+
const { nodeClient } = await this.createNodeClientFromHeaders(cookie);
|
|
48
|
+
await nodeClient.signOut(redirectUri);
|
|
49
|
+
if (!this.navigateUrl) {
|
|
50
|
+
// Not expected to happen
|
|
51
|
+
throw new Error('navigateUrl is not set');
|
|
52
|
+
}
|
|
53
|
+
return this.navigateUrl;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Handle sign-in callback from Logto.
|
|
57
|
+
*
|
|
58
|
+
* @param cookie the raw cookie string
|
|
59
|
+
* @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
|
+
*/
|
|
62
|
+
async handleSignInCallback(cookie, callbackUrl) {
|
|
63
|
+
const { nodeClient, session } = await this.createNodeClientFromHeaders(cookie);
|
|
64
|
+
await nodeClient.handleSignInCallback(callbackUrl);
|
|
65
|
+
return session.getValues?.();
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get Logto context from cookies.
|
|
69
|
+
*
|
|
70
|
+
* @param cookie the raw cookie string
|
|
71
|
+
* @param config additional configs of GetContextParameters
|
|
72
|
+
* @returns LogtoContext
|
|
73
|
+
*/
|
|
74
|
+
async getLogtoContext(cookie, config = {}) {
|
|
75
|
+
const { nodeClient } = await this.createNodeClientFromHeaders(cookie);
|
|
76
|
+
const context = await nodeClient.getContext(config);
|
|
77
|
+
return context;
|
|
78
|
+
}
|
|
79
|
+
async createNodeClientFromHeaders(cookie) {
|
|
80
|
+
const session = await NodeClient$1.createSession({
|
|
81
|
+
secret: this.config.cookieSecret,
|
|
82
|
+
crypto,
|
|
83
|
+
}, cookie);
|
|
84
|
+
const nodeClient = super.createNodeClient(session);
|
|
85
|
+
return { nodeClient, session };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
exports.default = LogtoClient;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
2
|
+
import BaseClient from '../src/client';
|
|
3
|
+
import type { LogtoNextConfig } from '../src/types.js';
|
|
4
|
+
export type { LogtoContext, InteractionMode } from '@logto/node';
|
|
5
|
+
export default class LogtoClient extends BaseClient {
|
|
6
|
+
constructor(config: LogtoNextConfig);
|
|
7
|
+
/**
|
|
8
|
+
* Init sign-in and return the url to redirect to Logto.
|
|
9
|
+
*
|
|
10
|
+
* @param cookie the raw cookie string
|
|
11
|
+
* @param redirectUri the uri (callbackUri) to redirect to after sign in
|
|
12
|
+
* @param interactionMode OIDC interaction mode
|
|
13
|
+
* @returns the url to redirect to and new cookie if any
|
|
14
|
+
*/
|
|
15
|
+
handleSignIn(cookie: string, redirectUri: string, interactionMode?: InteractionMode): Promise<{
|
|
16
|
+
url: string;
|
|
17
|
+
newCookie?: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Init sign-out and return the url to redirect to Logto.
|
|
21
|
+
*
|
|
22
|
+
* @param cookie the raw cookie string
|
|
23
|
+
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
24
|
+
* @returns the url to redirect to
|
|
25
|
+
*/
|
|
26
|
+
handleSignOut(cookie: string, redirectUri?: string): Promise<string>;
|
|
27
|
+
/**
|
|
28
|
+
* Handle sign-in callback from Logto.
|
|
29
|
+
*
|
|
30
|
+
* @param cookie the raw cookie string
|
|
31
|
+
* @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
|
+
*/
|
|
34
|
+
handleSignInCallback(cookie: string, callbackUrl: string): Promise<string | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* Get Logto context from cookies.
|
|
37
|
+
*
|
|
38
|
+
* @param cookie the raw cookie string
|
|
39
|
+
* @param config additional configs of GetContextParameters
|
|
40
|
+
* @returns LogtoContext
|
|
41
|
+
*/
|
|
42
|
+
getLogtoContext(cookie: string, config?: GetContextParameters): Promise<import("@logto/node").LogtoContext>;
|
|
43
|
+
createNodeClientFromHeaders(cookie: string): Promise<{
|
|
44
|
+
nodeClient: import("@logto/node").default;
|
|
45
|
+
session: import("@logto/node").Session;
|
|
46
|
+
}>;
|
|
47
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { createSession } from '@logto/node';
|
|
2
|
+
import NodeClient from '@logto/node/edge';
|
|
3
|
+
import LogtoNextBaseClient from '../src/client.js';
|
|
4
|
+
|
|
5
|
+
class LogtoClient extends LogtoNextBaseClient {
|
|
6
|
+
constructor(config) {
|
|
7
|
+
super(config, {
|
|
8
|
+
NodeClient,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Init sign-in and return the url to redirect to Logto.
|
|
13
|
+
*
|
|
14
|
+
* @param cookie the raw cookie string
|
|
15
|
+
* @param redirectUri the uri (callbackUri) to redirect to after sign in
|
|
16
|
+
* @param interactionMode OIDC interaction mode
|
|
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);
|
|
22
|
+
if (!this.navigateUrl) {
|
|
23
|
+
// Not expected to happen
|
|
24
|
+
throw new Error('navigateUrl is not set');
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
url: this.navigateUrl,
|
|
28
|
+
newCookie: await session.getValues?.(),
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Init sign-out and return the url to redirect to Logto.
|
|
33
|
+
*
|
|
34
|
+
* @param cookie the raw cookie string
|
|
35
|
+
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
36
|
+
* @returns the url to redirect to
|
|
37
|
+
*/
|
|
38
|
+
async handleSignOut(cookie, redirectUri = this.config.baseUrl) {
|
|
39
|
+
const { nodeClient } = await this.createNodeClientFromHeaders(cookie);
|
|
40
|
+
await nodeClient.signOut(redirectUri);
|
|
41
|
+
if (!this.navigateUrl) {
|
|
42
|
+
// Not expected to happen
|
|
43
|
+
throw new Error('navigateUrl is not set');
|
|
44
|
+
}
|
|
45
|
+
return this.navigateUrl;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Handle sign-in callback from Logto.
|
|
49
|
+
*
|
|
50
|
+
* @param cookie the raw cookie string
|
|
51
|
+
* @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
|
+
*/
|
|
54
|
+
async handleSignInCallback(cookie, callbackUrl) {
|
|
55
|
+
const { nodeClient, session } = await this.createNodeClientFromHeaders(cookie);
|
|
56
|
+
await nodeClient.handleSignInCallback(callbackUrl);
|
|
57
|
+
return session.getValues?.();
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Get Logto context from cookies.
|
|
61
|
+
*
|
|
62
|
+
* @param cookie the raw cookie string
|
|
63
|
+
* @param config additional configs of GetContextParameters
|
|
64
|
+
* @returns LogtoContext
|
|
65
|
+
*/
|
|
66
|
+
async getLogtoContext(cookie, config = {}) {
|
|
67
|
+
const { nodeClient } = await this.createNodeClientFromHeaders(cookie);
|
|
68
|
+
const context = await nodeClient.getContext(config);
|
|
69
|
+
return context;
|
|
70
|
+
}
|
|
71
|
+
async createNodeClientFromHeaders(cookie) {
|
|
72
|
+
const session = await createSession({
|
|
73
|
+
secret: this.config.cookieSecret,
|
|
74
|
+
crypto,
|
|
75
|
+
}, cookie);
|
|
76
|
+
const nodeClient = super.createNodeClient(session);
|
|
77
|
+
return { nodeClient, session };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export { LogtoClient as default };
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
});
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
exports.getCookies = getCookies;
|
|
16
|
+
exports.setCookies = setCookies;
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
+
});
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export { getCookies, setCookies };
|
|
@@ -2,88 +2,68 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var
|
|
6
|
-
var client = require('
|
|
7
|
-
var
|
|
5
|
+
var navigation = require('next/navigation');
|
|
6
|
+
var client = require('./client.cjs');
|
|
7
|
+
var cookie = require('./cookie.cjs');
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Init sign-in and return the url to redirect to Logto.
|
|
21
|
-
*
|
|
22
|
-
* @param cookie the raw cookie string
|
|
23
|
-
* @param redirectUri the uri (callbackUri) to redirect to after sign in
|
|
24
|
-
* @param interactionMode OIDC interaction mode
|
|
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);
|
|
30
|
-
if (!this.navigateUrl) {
|
|
31
|
-
// Not expected to happen
|
|
32
|
-
throw new Error('navigateUrl is not set');
|
|
33
|
-
}
|
|
34
|
-
return {
|
|
35
|
-
url: this.navigateUrl,
|
|
36
|
-
newCookie: await session.getValues?.(),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Init sign-out and return the url to redirect to Logto.
|
|
41
|
-
*
|
|
42
|
-
* @param cookie the raw cookie string
|
|
43
|
-
* @param redirectUri the uri (postSignOutUri) to redirect to after sign out
|
|
44
|
-
* @returns the url to redirect to
|
|
45
|
-
*/
|
|
46
|
-
async handleSignOut(cookie, redirectUri = this.config.baseUrl) {
|
|
47
|
-
const { nodeClient } = await this.createNodeClientFromHeaders(cookie);
|
|
48
|
-
await nodeClient.signOut(redirectUri);
|
|
49
|
-
if (!this.navigateUrl) {
|
|
50
|
-
// Not expected to happen
|
|
51
|
-
throw new Error('navigateUrl is not set');
|
|
52
|
-
}
|
|
53
|
-
return this.navigateUrl;
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Handle sign-in callback from Logto.
|
|
57
|
-
*
|
|
58
|
-
* @param cookie the raw cookie string
|
|
59
|
-
* @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
|
-
*/
|
|
62
|
-
async handleSignInCallback(cookie, callbackUrl) {
|
|
63
|
-
const { nodeClient, session } = await this.createNodeClientFromHeaders(cookie);
|
|
64
|
-
await nodeClient.handleSignInCallback(callbackUrl);
|
|
65
|
-
return session.getValues?.();
|
|
9
|
+
/**
|
|
10
|
+
* Init sign in process and redirect to the Logto sign-in page
|
|
11
|
+
*/
|
|
12
|
+
const signIn = async (config, redirectUri, interactionMode) => {
|
|
13
|
+
const client$1 = new client.default(config);
|
|
14
|
+
const { url, newCookie } = await client$1.handleSignIn(await cookie.getCookies(config), redirectUri ?? `${config.baseUrl}/callback`, interactionMode);
|
|
15
|
+
if (newCookie) {
|
|
16
|
+
await cookie.setCookies(newCookie, config);
|
|
66
17
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
18
|
+
navigation.redirect(url);
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Handle sign in callback from search params, save tokens to session
|
|
22
|
+
*/
|
|
23
|
+
const handleSignIn = async (config, searchParams) => {
|
|
24
|
+
const search = searchParams.toString();
|
|
25
|
+
const client$1 = new client.default(config);
|
|
26
|
+
const newCookie = await client$1.handleSignInCallback(await cookie.getCookies(config), `${config.baseUrl}/callback?${search}`);
|
|
27
|
+
if (newCookie) {
|
|
28
|
+
await cookie.setCookies(newCookie, config);
|
|
78
29
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Init sign out process, clear session, and redirect to the Logto sign-out page
|
|
33
|
+
*/
|
|
34
|
+
const signOut = async (config, redirectUri) => {
|
|
35
|
+
const client$1 = new client.default(config);
|
|
36
|
+
const url = await client$1.handleSignOut(await cookie.getCookies(config), redirectUri);
|
|
37
|
+
await cookie.setCookies('', config);
|
|
38
|
+
navigation.redirect(url);
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Get Logto context from session, including auth status and claims
|
|
42
|
+
*/
|
|
43
|
+
const getLogtoContext = async (config, getContextParameters) => {
|
|
44
|
+
const client$1 = new client.default(config);
|
|
45
|
+
return client$1.getLogtoContext(await cookie.getCookies(config), getContextParameters);
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Get organization tokens from session
|
|
49
|
+
*/
|
|
50
|
+
const getOrganizationTokens = async (config) => {
|
|
51
|
+
const { isAuthenticated } = await getLogtoContext(config);
|
|
52
|
+
if (!isAuthenticated) {
|
|
53
|
+
return [];
|
|
86
54
|
}
|
|
87
|
-
|
|
55
|
+
const client$1 = new client.default(config);
|
|
56
|
+
const { nodeClient } = await client$1.createNodeClientFromHeaders(await cookie.getCookies(config));
|
|
57
|
+
const { organizations = [] } = await nodeClient.getIdTokenClaims();
|
|
58
|
+
return Promise.all(organizations.map(async (organizationId) => ({
|
|
59
|
+
id: organizationId,
|
|
60
|
+
token: await nodeClient.getOrganizationToken(organizationId),
|
|
61
|
+
})));
|
|
62
|
+
};
|
|
88
63
|
|
|
89
|
-
exports.default =
|
|
64
|
+
exports.default = client.default;
|
|
65
|
+
exports.getLogtoContext = getLogtoContext;
|
|
66
|
+
exports.getOrganizationTokens = getOrganizationTokens;
|
|
67
|
+
exports.handleSignIn = handleSignIn;
|
|
68
|
+
exports.signIn = signIn;
|
|
69
|
+
exports.signOut = signOut;
|
|
@@ -1,47 +1,27 @@
|
|
|
1
|
-
import { type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
2
|
-
import BaseClient from '../src/client';
|
|
1
|
+
import { type LogtoContext, type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
3
2
|
import type { LogtoNextConfig } from '../src/types.js';
|
|
4
3
|
export type { LogtoContext, InteractionMode } from '@logto/node';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
* @param cookie the raw cookie string
|
|
31
|
-
* @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
|
-
*/
|
|
34
|
-
handleSignInCallback(cookie: string, callbackUrl: string): Promise<string | undefined>;
|
|
35
|
-
/**
|
|
36
|
-
* Get Logto context from cookies.
|
|
37
|
-
*
|
|
38
|
-
* @param cookie the raw cookie string
|
|
39
|
-
* @param config additional configs of GetContextParameters
|
|
40
|
-
* @returns LogtoContext
|
|
41
|
-
*/
|
|
42
|
-
getLogtoContext(cookie: string, config?: GetContextParameters): Promise<import("@logto/node").LogtoContext>;
|
|
43
|
-
createNodeClientFromHeaders(cookie: string): Promise<{
|
|
44
|
-
nodeClient: import("@logto/node").default;
|
|
45
|
-
session: import("../src/types.js").Session;
|
|
46
|
-
}>;
|
|
47
|
-
}
|
|
4
|
+
/**
|
|
5
|
+
* Init sign in process and redirect to the Logto sign-in page
|
|
6
|
+
*/
|
|
7
|
+
export declare const signIn: (config: LogtoNextConfig, redirectUri?: string, interactionMode?: InteractionMode) => Promise<void>;
|
|
8
|
+
/**
|
|
9
|
+
* Handle sign in callback from search params, save tokens to session
|
|
10
|
+
*/
|
|
11
|
+
export declare const handleSignIn: (config: LogtoNextConfig, searchParams: URLSearchParams) => Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Init sign out process, clear session, and redirect to the Logto sign-out page
|
|
14
|
+
*/
|
|
15
|
+
export declare const signOut: (config: LogtoNextConfig, redirectUri?: string) => Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Get Logto context from session, including auth status and claims
|
|
18
|
+
*/
|
|
19
|
+
export declare const getLogtoContext: (config: LogtoNextConfig, getContextParameters?: GetContextParameters) => Promise<LogtoContext>;
|
|
20
|
+
/**
|
|
21
|
+
* Get organization tokens from session
|
|
22
|
+
*/
|
|
23
|
+
export declare const getOrganizationTokens: (config: LogtoNextConfig) => Promise<{
|
|
24
|
+
id: string;
|
|
25
|
+
token: string;
|
|
26
|
+
}[]>;
|
|
27
|
+
export { default } from './client';
|
|
@@ -1,81 +1,60 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
1
|
+
import { redirect } from 'next/navigation';
|
|
2
|
+
import LogtoClient from './client.js';
|
|
3
|
+
import { getCookies, setCookies } from './cookie.js';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Init sign in process and redirect to the Logto sign-in page
|
|
7
|
+
*/
|
|
8
|
+
const signIn = async (config, redirectUri, interactionMode) => {
|
|
9
|
+
const client = new LogtoClient(config);
|
|
10
|
+
const { url, newCookie } = await client.handleSignIn(await getCookies(config), redirectUri ?? `${config.baseUrl}/callback`, interactionMode);
|
|
11
|
+
if (newCookie) {
|
|
12
|
+
await setCookies(newCookie, config);
|
|
10
13
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
await
|
|
22
|
-
if (!this.navigateUrl) {
|
|
23
|
-
// Not expected to happen
|
|
24
|
-
throw new Error('navigateUrl is not set');
|
|
25
|
-
}
|
|
26
|
-
return {
|
|
27
|
-
url: this.navigateUrl,
|
|
28
|
-
newCookie: await session.getValues?.(),
|
|
29
|
-
};
|
|
14
|
+
redirect(url);
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Handle sign in callback from search params, save tokens to session
|
|
18
|
+
*/
|
|
19
|
+
const handleSignIn = async (config, searchParams) => {
|
|
20
|
+
const search = searchParams.toString();
|
|
21
|
+
const client = new LogtoClient(config);
|
|
22
|
+
const newCookie = await client.handleSignInCallback(await getCookies(config), `${config.baseUrl}/callback?${search}`);
|
|
23
|
+
if (newCookie) {
|
|
24
|
+
await setCookies(newCookie, config);
|
|
30
25
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Init sign out process, clear session, and redirect to the Logto sign-out page
|
|
29
|
+
*/
|
|
30
|
+
const signOut = async (config, redirectUri) => {
|
|
31
|
+
const client = new LogtoClient(config);
|
|
32
|
+
const url = await client.handleSignOut(await getCookies(config), redirectUri);
|
|
33
|
+
await setCookies('', config);
|
|
34
|
+
redirect(url);
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Get Logto context from session, including auth status and claims
|
|
38
|
+
*/
|
|
39
|
+
const getLogtoContext = async (config, getContextParameters) => {
|
|
40
|
+
const client = new LogtoClient(config);
|
|
41
|
+
return client.getLogtoContext(await getCookies(config), getContextParameters);
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Get organization tokens from session
|
|
45
|
+
*/
|
|
46
|
+
const getOrganizationTokens = async (config) => {
|
|
47
|
+
const { isAuthenticated } = await getLogtoContext(config);
|
|
48
|
+
if (!isAuthenticated) {
|
|
49
|
+
return [];
|
|
46
50
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
const { nodeClient, session } = await this.createNodeClientFromHeaders(cookie);
|
|
56
|
-
await nodeClient.handleSignInCallback(callbackUrl);
|
|
57
|
-
return session.getValues?.();
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* Get Logto context from cookies.
|
|
61
|
-
*
|
|
62
|
-
* @param cookie the raw cookie string
|
|
63
|
-
* @param config additional configs of GetContextParameters
|
|
64
|
-
* @returns LogtoContext
|
|
65
|
-
*/
|
|
66
|
-
async getLogtoContext(cookie, config = {}) {
|
|
67
|
-
const { nodeClient } = await this.createNodeClientFromHeaders(cookie);
|
|
68
|
-
const context = await nodeClient.getContext(config);
|
|
69
|
-
return context;
|
|
70
|
-
}
|
|
71
|
-
async createNodeClientFromHeaders(cookie) {
|
|
72
|
-
const session = await createSession({
|
|
73
|
-
secret: this.config.cookieSecret,
|
|
74
|
-
crypto,
|
|
75
|
-
}, cookie);
|
|
76
|
-
const nodeClient = super.createNodeClient(session);
|
|
77
|
-
return { nodeClient, session };
|
|
78
|
-
}
|
|
79
|
-
}
|
|
51
|
+
const client = new LogtoClient(config);
|
|
52
|
+
const { nodeClient } = await client.createNodeClientFromHeaders(await getCookies(config));
|
|
53
|
+
const { organizations = [] } = await nodeClient.getIdTokenClaims();
|
|
54
|
+
return Promise.all(organizations.map(async (organizationId) => ({
|
|
55
|
+
id: organizationId,
|
|
56
|
+
token: await nodeClient.getOrganizationToken(organizationId),
|
|
57
|
+
})));
|
|
58
|
+
};
|
|
80
59
|
|
|
81
|
-
export { LogtoClient as default };
|
|
60
|
+
export { LogtoClient as default, getLogtoContext, getOrganizationTokens, handleSignIn, signIn, signOut };
|
package/lib/src/client.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
+
import { type Session } from '@logto/node';
|
|
1
2
|
import NextStorage from './storage';
|
|
2
|
-
import type { Adapters, LogtoNextConfig
|
|
3
|
+
import type { Adapters, LogtoNextConfig } from './types';
|
|
3
4
|
export default class LogtoNextBaseClient {
|
|
4
5
|
protected readonly config: LogtoNextConfig;
|
|
5
6
|
protected readonly adapters: Adapters;
|
package/lib/src/index.cjs
CHANGED
|
@@ -2,32 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var crypto = require('crypto');
|
|
6
5
|
var NodeClient = require('@logto/node');
|
|
7
6
|
var client = require('./client.cjs');
|
|
8
|
-
var session = require('./session.cjs');
|
|
9
7
|
|
|
10
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
11
9
|
|
|
12
|
-
function _interopNamespace(e) {
|
|
13
|
-
if (e && e.__esModule) return e;
|
|
14
|
-
var n = Object.create(null);
|
|
15
|
-
if (e) {
|
|
16
|
-
Object.keys(e).forEach(function (k) {
|
|
17
|
-
if (k !== 'default') {
|
|
18
|
-
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
19
|
-
Object.defineProperty(n, k, d.get ? d : {
|
|
20
|
-
enumerable: true,
|
|
21
|
-
get: function () { return e[k]; }
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
n.default = e;
|
|
27
|
-
return Object.freeze(n);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
|
|
31
10
|
var NodeClient__default = /*#__PURE__*/_interopDefault(NodeClient);
|
|
32
11
|
|
|
33
12
|
class LogtoClient extends client.default {
|
|
@@ -85,6 +64,7 @@ class LogtoClient extends client.default {
|
|
|
85
64
|
this.withLogtoApiRoute = (handler, config = {}) => async (request, response) => {
|
|
86
65
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
87
66
|
const user = await nodeClient.getContext(config);
|
|
67
|
+
await this.storage?.save();
|
|
88
68
|
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
|
89
69
|
Object.defineProperty(request, 'user', { enumerable: true, get: () => user });
|
|
90
70
|
return handler(request, response);
|
|
@@ -92,6 +72,7 @@ class LogtoClient extends client.default {
|
|
|
92
72
|
this.withLogtoSsr = (handler, configs = {}) => async (context) => {
|
|
93
73
|
const nodeClient = await this.createNodeClientFromNextApi(context.req, context.res);
|
|
94
74
|
const user = await nodeClient.getContext(configs);
|
|
75
|
+
await this.storage?.save();
|
|
95
76
|
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
|
96
77
|
Object.defineProperty(context.req, 'user', { enumerable: true, get: () => user });
|
|
97
78
|
return handler(context);
|
|
@@ -99,9 +80,9 @@ class LogtoClient extends client.default {
|
|
|
99
80
|
}
|
|
100
81
|
async createNodeClientFromNextApi(request, response) {
|
|
101
82
|
const cookieName = `logto:${this.config.appId}`;
|
|
102
|
-
return super.createNodeClient(await
|
|
83
|
+
return super.createNodeClient(await NodeClient.createSession({
|
|
103
84
|
secret: this.config.cookieSecret,
|
|
104
|
-
crypto
|
|
85
|
+
crypto,
|
|
105
86
|
}, request.cookies[cookieName] ?? '', (value) => {
|
|
106
87
|
const secure = this.config.cookieSecure;
|
|
107
88
|
const maxAge = 14 * 3600 * 24;
|
|
@@ -110,51 +91,51 @@ class LogtoClient extends client.default {
|
|
|
110
91
|
}
|
|
111
92
|
}
|
|
112
93
|
|
|
113
|
-
Object.defineProperty(exports,
|
|
94
|
+
Object.defineProperty(exports, "LogtoClientError", {
|
|
114
95
|
enumerable: true,
|
|
115
96
|
get: function () { return NodeClient.LogtoClientError; }
|
|
116
97
|
});
|
|
117
|
-
Object.defineProperty(exports,
|
|
98
|
+
Object.defineProperty(exports, "LogtoError", {
|
|
118
99
|
enumerable: true,
|
|
119
100
|
get: function () { return NodeClient.LogtoError; }
|
|
120
101
|
});
|
|
121
|
-
Object.defineProperty(exports,
|
|
102
|
+
Object.defineProperty(exports, "LogtoRequestError", {
|
|
122
103
|
enumerable: true,
|
|
123
104
|
get: function () { return NodeClient.LogtoRequestError; }
|
|
124
105
|
});
|
|
125
|
-
Object.defineProperty(exports,
|
|
106
|
+
Object.defineProperty(exports, "OidcError", {
|
|
126
107
|
enumerable: true,
|
|
127
108
|
get: function () { return NodeClient.OidcError; }
|
|
128
109
|
});
|
|
129
|
-
Object.defineProperty(exports,
|
|
110
|
+
Object.defineProperty(exports, "PersistKey", {
|
|
130
111
|
enumerable: true,
|
|
131
112
|
get: function () { return NodeClient.PersistKey; }
|
|
132
113
|
});
|
|
133
|
-
Object.defineProperty(exports,
|
|
114
|
+
Object.defineProperty(exports, "Prompt", {
|
|
134
115
|
enumerable: true,
|
|
135
116
|
get: function () { return NodeClient.Prompt; }
|
|
136
117
|
});
|
|
137
|
-
Object.defineProperty(exports,
|
|
118
|
+
Object.defineProperty(exports, "ReservedResource", {
|
|
138
119
|
enumerable: true,
|
|
139
120
|
get: function () { return NodeClient.ReservedResource; }
|
|
140
121
|
});
|
|
141
|
-
Object.defineProperty(exports,
|
|
122
|
+
Object.defineProperty(exports, "ReservedScope", {
|
|
142
123
|
enumerable: true,
|
|
143
124
|
get: function () { return NodeClient.ReservedScope; }
|
|
144
125
|
});
|
|
145
|
-
Object.defineProperty(exports,
|
|
126
|
+
Object.defineProperty(exports, "UserScope", {
|
|
146
127
|
enumerable: true,
|
|
147
128
|
get: function () { return NodeClient.UserScope; }
|
|
148
129
|
});
|
|
149
|
-
Object.defineProperty(exports,
|
|
130
|
+
Object.defineProperty(exports, "buildOrganizationUrn", {
|
|
150
131
|
enumerable: true,
|
|
151
132
|
get: function () { return NodeClient.buildOrganizationUrn; }
|
|
152
133
|
});
|
|
153
|
-
Object.defineProperty(exports,
|
|
134
|
+
Object.defineProperty(exports, "getOrganizationIdFromUrn", {
|
|
154
135
|
enumerable: true,
|
|
155
136
|
get: function () { return NodeClient.getOrganizationIdFromUrn; }
|
|
156
137
|
});
|
|
157
|
-
Object.defineProperty(exports,
|
|
138
|
+
Object.defineProperty(exports, "organizationUrnPrefix", {
|
|
158
139
|
enumerable: true,
|
|
159
140
|
get: function () { return NodeClient.organizationUrnPrefix; }
|
|
160
141
|
});
|
package/lib/src/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
-
import { type IncomingMessage, type ServerResponse } from 'http';
|
|
2
|
+
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
3
3
|
import NodeClient, { type GetContextParameters, type InteractionMode } from '@logto/node';
|
|
4
4
|
import { type GetServerSidePropsResult, type GetServerSidePropsContext, type NextApiHandler } from 'next';
|
|
5
5
|
import { type NextApiRequestCookies } from 'next/dist/server/api-utils/index.js';
|
package/lib/src/index.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import NodeClient from '@logto/node';
|
|
1
|
+
import NodeClient, { createSession } from '@logto/node';
|
|
3
2
|
export { LogtoClientError, LogtoError, LogtoRequestError, OidcError, PersistKey, Prompt, ReservedResource, ReservedScope, UserScope, buildOrganizationUrn, getOrganizationIdFromUrn, organizationUrnPrefix } from '@logto/node';
|
|
4
3
|
import LogtoNextBaseClient from './client.js';
|
|
5
|
-
import { createSession } from './session.js';
|
|
6
4
|
|
|
7
5
|
class LogtoClient extends LogtoNextBaseClient {
|
|
8
6
|
constructor(config) {
|
|
@@ -59,6 +57,7 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
59
57
|
this.withLogtoApiRoute = (handler, config = {}) => async (request, response) => {
|
|
60
58
|
const nodeClient = await this.createNodeClientFromNextApi(request, response);
|
|
61
59
|
const user = await nodeClient.getContext(config);
|
|
60
|
+
await this.storage?.save();
|
|
62
61
|
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
|
63
62
|
Object.defineProperty(request, 'user', { enumerable: true, get: () => user });
|
|
64
63
|
return handler(request, response);
|
|
@@ -66,6 +65,7 @@ class LogtoClient extends LogtoNextBaseClient {
|
|
|
66
65
|
this.withLogtoSsr = (handler, configs = {}) => async (context) => {
|
|
67
66
|
const nodeClient = await this.createNodeClientFromNextApi(context.req, context.res);
|
|
68
67
|
const user = await nodeClient.getContext(configs);
|
|
68
|
+
await this.storage?.save();
|
|
69
69
|
// eslint-disable-next-line @silverhand/fp/no-mutating-methods
|
|
70
70
|
Object.defineProperty(context.req, 'user', { enumerable: true, get: () => user });
|
|
71
71
|
return handler(context);
|
package/lib/src/storage.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { type Storage } from '@logto/node';
|
|
1
|
+
import { type Session, type Storage } from '@logto/node';
|
|
2
2
|
import { PersistKey } from '@logto/node/edge';
|
|
3
|
-
import { type Session } from './types';
|
|
4
3
|
export default class NextStorage implements Storage<PersistKey> {
|
|
5
4
|
private readonly session;
|
|
6
5
|
private sessionChanged;
|
package/lib/src/types.d.ts
CHANGED
|
@@ -1,15 +1,5 @@
|
|
|
1
|
-
import type { LogtoConfig
|
|
1
|
+
import type { LogtoConfig } from '@logto/node';
|
|
2
2
|
import type NodeClient from '@logto/node';
|
|
3
|
-
export type SessionData = {
|
|
4
|
-
[PersistKey.AccessToken]?: string;
|
|
5
|
-
[PersistKey.IdToken]?: string;
|
|
6
|
-
[PersistKey.SignInSession]?: string;
|
|
7
|
-
[PersistKey.RefreshToken]?: string;
|
|
8
|
-
};
|
|
9
|
-
export type Session = SessionData & {
|
|
10
|
-
save: () => Promise<void>;
|
|
11
|
-
getValues?: () => Promise<string>;
|
|
12
|
-
};
|
|
13
3
|
export type LogtoNextConfig = LogtoConfig & {
|
|
14
4
|
cookieSecret: string;
|
|
15
5
|
cookieSecure: boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/next",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.1.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/src/index.cjs",
|
|
6
6
|
"module": "./lib/src/index.js",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@edge-runtime/cookies": "^4.0.0",
|
|
49
|
-
"@logto/node": "^2.
|
|
49
|
+
"@logto/node": "^2.4.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@silverhand/eslint-config": "^5.0.0",
|
|
@@ -65,16 +65,13 @@
|
|
|
65
65
|
"prettier": "^3.0.0",
|
|
66
66
|
"react": "^18.2.0",
|
|
67
67
|
"react-dom": "^18.2.0",
|
|
68
|
-
"typescript": "^5.
|
|
68
|
+
"typescript": "^5.3.3"
|
|
69
69
|
},
|
|
70
70
|
"peerDependencies": {
|
|
71
71
|
"next": ">=12"
|
|
72
72
|
},
|
|
73
73
|
"eslintConfig": {
|
|
74
|
-
"extends": "@silverhand"
|
|
75
|
-
"rules": {
|
|
76
|
-
"unicorn/prefer-node-protocol": "off"
|
|
77
|
-
}
|
|
74
|
+
"extends": "@silverhand"
|
|
78
75
|
},
|
|
79
76
|
"prettier": "@silverhand/eslint-config/.prettierrc",
|
|
80
77
|
"publishConfig": {
|
package/lib/src/session.cjs
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
async function getKeyFromPassword(password, crypto) {
|
|
4
|
-
const encoder = new TextEncoder();
|
|
5
|
-
const data = encoder.encode(password);
|
|
6
|
-
const hash = await crypto.subtle.digest('SHA-256', data);
|
|
7
|
-
// Convert the hash to a hex string
|
|
8
|
-
return Array.from(new Uint8Array(hash))
|
|
9
|
-
.map((byte) => byte.toString(16).padStart(2, '0'))
|
|
10
|
-
.join('');
|
|
11
|
-
}
|
|
12
|
-
async function encrypt(text, password, crypto) {
|
|
13
|
-
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
14
|
-
const encodedPlaintext = new TextEncoder().encode(text);
|
|
15
|
-
const secretKey = await crypto.subtle.importKey('raw', Buffer.from(await getKeyFromPassword(password, crypto), 'hex'), {
|
|
16
|
-
name: 'AES-GCM',
|
|
17
|
-
length: 256,
|
|
18
|
-
}, true, ['encrypt', 'decrypt']);
|
|
19
|
-
const ciphertext = await crypto.subtle.encrypt({
|
|
20
|
-
name: 'AES-GCM',
|
|
21
|
-
iv,
|
|
22
|
-
}, secretKey, encodedPlaintext);
|
|
23
|
-
return {
|
|
24
|
-
ciphertext: Buffer.from(ciphertext).toString('base64'),
|
|
25
|
-
iv: Buffer.from(iv).toString('base64'),
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
async function decrypt(ciphertext, iv, password, crypto) {
|
|
29
|
-
const secretKey = await crypto.subtle.importKey('raw', Buffer.from(await getKeyFromPassword(password, crypto), 'hex'), {
|
|
30
|
-
name: 'AES-GCM',
|
|
31
|
-
length: 256,
|
|
32
|
-
}, true, ['encrypt', 'decrypt']);
|
|
33
|
-
const cleartext = await crypto.subtle.decrypt({
|
|
34
|
-
name: 'AES-GCM',
|
|
35
|
-
iv: Buffer.from(iv, 'base64'),
|
|
36
|
-
}, secretKey, Buffer.from(ciphertext, 'base64'));
|
|
37
|
-
return new TextDecoder().decode(cleartext);
|
|
38
|
-
}
|
|
39
|
-
const unwrapSession = async (cookie, secret, crypto) => {
|
|
40
|
-
try {
|
|
41
|
-
const [ciphertext, iv] = cookie.split('.');
|
|
42
|
-
if (!ciphertext || !iv) {
|
|
43
|
-
return {};
|
|
44
|
-
}
|
|
45
|
-
const decrypted = await decrypt(ciphertext, iv, secret, crypto);
|
|
46
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
47
|
-
return JSON.parse(decrypted);
|
|
48
|
-
}
|
|
49
|
-
catch {
|
|
50
|
-
// Ignore invalid session
|
|
51
|
-
}
|
|
52
|
-
return {};
|
|
53
|
-
};
|
|
54
|
-
const wrapSession = async (session, secret, crypto) => {
|
|
55
|
-
const { ciphertext, iv } = await encrypt(JSON.stringify(session), secret, crypto);
|
|
56
|
-
return `${ciphertext}.${iv}`;
|
|
57
|
-
};
|
|
58
|
-
const createSession = async ({ secret, crypto }, cookie, setCookie) => {
|
|
59
|
-
const data = await unwrapSession(cookie, secret, crypto);
|
|
60
|
-
const getValues = async () => wrapSession(session, secret, crypto);
|
|
61
|
-
const session = {
|
|
62
|
-
...data,
|
|
63
|
-
save: async () => {
|
|
64
|
-
setCookie?.(await getValues());
|
|
65
|
-
},
|
|
66
|
-
getValues,
|
|
67
|
-
};
|
|
68
|
-
return session;
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
exports.createSession = createSession;
|
|
72
|
-
exports.unwrapSession = unwrapSession;
|
|
73
|
-
exports.wrapSession = wrapSession;
|
package/lib/src/session.d.ts
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { type SessionData, type Session } from './types';
|
|
2
|
-
export declare const unwrapSession: (cookie: string, secret: string, crypto: Crypto) => Promise<SessionData>;
|
|
3
|
-
export declare const wrapSession: (session: SessionData, secret: string, crypto: Crypto) => Promise<string>;
|
|
4
|
-
type SessionConfigs = {
|
|
5
|
-
secret: string;
|
|
6
|
-
crypto: Crypto;
|
|
7
|
-
};
|
|
8
|
-
export declare const createSession: ({ secret, crypto }: SessionConfigs, cookie: string, setCookie?: ((value: string) => void) | undefined) => Promise<Session>;
|
|
9
|
-
export {};
|
package/lib/src/session.js
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
async function getKeyFromPassword(password, crypto) {
|
|
2
|
-
const encoder = new TextEncoder();
|
|
3
|
-
const data = encoder.encode(password);
|
|
4
|
-
const hash = await crypto.subtle.digest('SHA-256', data);
|
|
5
|
-
// Convert the hash to a hex string
|
|
6
|
-
return Array.from(new Uint8Array(hash))
|
|
7
|
-
.map((byte) => byte.toString(16).padStart(2, '0'))
|
|
8
|
-
.join('');
|
|
9
|
-
}
|
|
10
|
-
async function encrypt(text, password, crypto) {
|
|
11
|
-
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
12
|
-
const encodedPlaintext = new TextEncoder().encode(text);
|
|
13
|
-
const secretKey = await crypto.subtle.importKey('raw', Buffer.from(await getKeyFromPassword(password, crypto), 'hex'), {
|
|
14
|
-
name: 'AES-GCM',
|
|
15
|
-
length: 256,
|
|
16
|
-
}, true, ['encrypt', 'decrypt']);
|
|
17
|
-
const ciphertext = await crypto.subtle.encrypt({
|
|
18
|
-
name: 'AES-GCM',
|
|
19
|
-
iv,
|
|
20
|
-
}, secretKey, encodedPlaintext);
|
|
21
|
-
return {
|
|
22
|
-
ciphertext: Buffer.from(ciphertext).toString('base64'),
|
|
23
|
-
iv: Buffer.from(iv).toString('base64'),
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
async function decrypt(ciphertext, iv, password, crypto) {
|
|
27
|
-
const secretKey = await crypto.subtle.importKey('raw', Buffer.from(await getKeyFromPassword(password, crypto), 'hex'), {
|
|
28
|
-
name: 'AES-GCM',
|
|
29
|
-
length: 256,
|
|
30
|
-
}, true, ['encrypt', 'decrypt']);
|
|
31
|
-
const cleartext = await crypto.subtle.decrypt({
|
|
32
|
-
name: 'AES-GCM',
|
|
33
|
-
iv: Buffer.from(iv, 'base64'),
|
|
34
|
-
}, secretKey, Buffer.from(ciphertext, 'base64'));
|
|
35
|
-
return new TextDecoder().decode(cleartext);
|
|
36
|
-
}
|
|
37
|
-
const unwrapSession = async (cookie, secret, crypto) => {
|
|
38
|
-
try {
|
|
39
|
-
const [ciphertext, iv] = cookie.split('.');
|
|
40
|
-
if (!ciphertext || !iv) {
|
|
41
|
-
return {};
|
|
42
|
-
}
|
|
43
|
-
const decrypted = await decrypt(ciphertext, iv, secret, crypto);
|
|
44
|
-
// eslint-disable-next-line no-restricted-syntax
|
|
45
|
-
return JSON.parse(decrypted);
|
|
46
|
-
}
|
|
47
|
-
catch {
|
|
48
|
-
// Ignore invalid session
|
|
49
|
-
}
|
|
50
|
-
return {};
|
|
51
|
-
};
|
|
52
|
-
const wrapSession = async (session, secret, crypto) => {
|
|
53
|
-
const { ciphertext, iv } = await encrypt(JSON.stringify(session), secret, crypto);
|
|
54
|
-
return `${ciphertext}.${iv}`;
|
|
55
|
-
};
|
|
56
|
-
const createSession = async ({ secret, crypto }, cookie, setCookie) => {
|
|
57
|
-
const data = await unwrapSession(cookie, secret, crypto);
|
|
58
|
-
const getValues = async () => wrapSession(session, secret, crypto);
|
|
59
|
-
const session = {
|
|
60
|
-
...data,
|
|
61
|
-
save: async () => {
|
|
62
|
-
setCookie?.(await getValues());
|
|
63
|
-
},
|
|
64
|
-
getValues,
|
|
65
|
-
};
|
|
66
|
-
return session;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
export { createSession, unwrapSession, wrapSession };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
File without changes
|