@logto/node 1.1.2 → 2.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.
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ var BaseClient = require('@logto/client');
4
+ var jsBase64 = require('js-base64');
5
+
6
+ /** @link [Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636) */
7
+ /**
8
+ * @param length The length of the raw random data.
9
+ */
10
+ const generateRandomString = (length = 64) => jsBase64.fromUint8Array(crypto.getRandomValues(new Uint8Array(length)), true);
11
+ /**
12
+ * Generates random string for state and encodes them in url safe base64
13
+ */
14
+ const generateState = () => generateRandomString();
15
+ /**
16
+ * Generates code verifier
17
+ *
18
+ * @link [Client Creates a Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1)
19
+ */
20
+ const generateCodeVerifier = () => generateRandomString();
21
+ /**
22
+ * Calculates the S256 PKCE code challenge for an arbitrary code verifier and encodes it in url safe base64
23
+ *
24
+ * @param {String} codeVerifier Code verifier to calculate the S256 code challenge for
25
+ * @link [Client Creates the Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2)
26
+ */
27
+ const generateCodeChallenge = async (codeVerifier) => {
28
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
29
+ if (crypto.subtle === undefined) {
30
+ /**
31
+ * `crypto.subtle` is available only in secure contexts (HTTPS) in some or all supporting browsers,
32
+ * https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle
33
+ * https://www.chromium.org/blink/webcrypto/#accessing-it
34
+ */
35
+ throw new BaseClient.LogtoError('crypto_subtle_unavailable');
36
+ }
37
+ const encodedCodeVerifier = new TextEncoder().encode(codeVerifier);
38
+ const codeChallenge = new Uint8Array(await crypto.subtle.digest('SHA-256', encodedCodeVerifier));
39
+ return jsBase64.fromUint8Array(codeChallenge, true);
40
+ };
41
+
42
+ exports.generateCodeChallenge = generateCodeChallenge;
43
+ exports.generateCodeVerifier = generateCodeVerifier;
44
+ exports.generateState = generateState;
@@ -0,0 +1,18 @@
1
+ /** @link [Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636) */
2
+ /**
3
+ * Generates random string for state and encodes them in url safe base64
4
+ */
5
+ export declare const generateState: () => string;
6
+ /**
7
+ * Generates code verifier
8
+ *
9
+ * @link [Client Creates a Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1)
10
+ */
11
+ export declare const generateCodeVerifier: () => string;
12
+ /**
13
+ * Calculates the S256 PKCE code challenge for an arbitrary code verifier and encodes it in url safe base64
14
+ *
15
+ * @param {String} codeVerifier Code verifier to calculate the S256 code challenge for
16
+ * @link [Client Creates the Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2)
17
+ */
18
+ export declare const generateCodeChallenge: (codeVerifier: string) => Promise<string>;
@@ -0,0 +1,40 @@
1
+ import { LogtoError } from '@logto/client';
2
+ import { fromUint8Array } from 'js-base64';
3
+
4
+ /** @link [Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636) */
5
+ /**
6
+ * @param length The length of the raw random data.
7
+ */
8
+ const generateRandomString = (length = 64) => fromUint8Array(crypto.getRandomValues(new Uint8Array(length)), true);
9
+ /**
10
+ * Generates random string for state and encodes them in url safe base64
11
+ */
12
+ const generateState = () => generateRandomString();
13
+ /**
14
+ * Generates code verifier
15
+ *
16
+ * @link [Client Creates a Code Verifier](https://datatracker.ietf.org/doc/html/rfc7636#section-4.1)
17
+ */
18
+ const generateCodeVerifier = () => generateRandomString();
19
+ /**
20
+ * Calculates the S256 PKCE code challenge for an arbitrary code verifier and encodes it in url safe base64
21
+ *
22
+ * @param {String} codeVerifier Code verifier to calculate the S256 code challenge for
23
+ * @link [Client Creates the Code Challenge](https://datatracker.ietf.org/doc/html/rfc7636#section-4.2)
24
+ */
25
+ const generateCodeChallenge = async (codeVerifier) => {
26
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
27
+ if (crypto.subtle === undefined) {
28
+ /**
29
+ * `crypto.subtle` is available only in secure contexts (HTTPS) in some or all supporting browsers,
30
+ * https://developer.mozilla.org/en-US/docs/Web/API/Crypto/subtle
31
+ * https://www.chromium.org/blink/webcrypto/#accessing-it
32
+ */
33
+ throw new LogtoError('crypto_subtle_unavailable');
34
+ }
35
+ const encodedCodeVerifier = new TextEncoder().encode(codeVerifier);
36
+ const codeChallenge = new Uint8Array(await crypto.subtle.digest('SHA-256', encodedCodeVerifier));
37
+ return fromUint8Array(codeChallenge, true);
38
+ };
39
+
40
+ export { generateCodeChallenge, generateCodeVerifier, generateState };
@@ -0,0 +1,35 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var BaseClient = require('@logto/client');
6
+ var client = require('../src/client.cjs');
7
+ var generators = require('./generators.cjs');
8
+
9
+ // Used for edge runtime, currently only NextJS.
10
+ class LogtoClient extends client.default {
11
+ constructor(config, adapter) {
12
+ super(config, {
13
+ ...adapter,
14
+ requester: BaseClient.createRequester(config.appSecret
15
+ ? async (...args) => {
16
+ const [input, init] = args;
17
+ return fetch(input, {
18
+ ...init,
19
+ headers: {
20
+ Authorization: `Basic ${Buffer.from(
21
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
22
+ `${config.appId}:${config.appSecret}`, 'utf8').toString('base64')}`,
23
+ ...init?.headers,
24
+ },
25
+ });
26
+ }
27
+ : fetch),
28
+ generateCodeChallenge: generators.generateCodeChallenge,
29
+ generateCodeVerifier: generators.generateCodeVerifier,
30
+ generateState: generators.generateState,
31
+ });
32
+ }
33
+ }
34
+
35
+ exports.default = LogtoClient;
@@ -0,0 +1,5 @@
1
+ import type { LogtoConfig, ClientAdapter } from '@logto/client';
2
+ import BaseClient from '../src/client.js';
3
+ export default class LogtoClient extends BaseClient {
4
+ constructor(config: LogtoConfig, adapter: Pick<ClientAdapter, 'navigate' | 'storage'>);
5
+ }
@@ -0,0 +1,31 @@
1
+ import { createRequester } from '@logto/client';
2
+ import LogtoNodeBaseClient from '../src/client.js';
3
+ import { generateCodeChallenge, generateCodeVerifier, generateState } from './generators.js';
4
+
5
+ // Used for edge runtime, currently only NextJS.
6
+ class LogtoClient extends LogtoNodeBaseClient {
7
+ constructor(config, adapter) {
8
+ super(config, {
9
+ ...adapter,
10
+ requester: createRequester(config.appSecret
11
+ ? async (...args) => {
12
+ const [input, init] = args;
13
+ return fetch(input, {
14
+ ...init,
15
+ headers: {
16
+ Authorization: `Basic ${Buffer.from(
17
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
18
+ `${config.appId}:${config.appSecret}`, 'utf8').toString('base64')}`,
19
+ ...init?.headers,
20
+ },
21
+ });
22
+ }
23
+ : fetch),
24
+ generateCodeChallenge,
25
+ generateCodeVerifier,
26
+ generateState,
27
+ });
28
+ }
29
+ }
30
+
31
+ export { LogtoClient as default };
@@ -4,36 +4,14 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var BaseClient = require('@logto/client');
6
6
  var essentials = require('@silverhand/essentials');
7
- var fetch = require('node-fetch');
8
- var generators = require('./utils/generators.js');
9
7
 
10
8
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
9
 
12
10
  var BaseClient__default = /*#__PURE__*/_interopDefault(BaseClient);
13
- var fetch__default = /*#__PURE__*/_interopDefault(fetch);
14
11
 
15
- class LogtoClient extends BaseClient__default.default {
16
- constructor(config, adapter) {
17
- super(config, {
18
- ...adapter,
19
- requester: BaseClient.createRequester(config.appSecret
20
- ? async (...args) => {
21
- const [input, init] = args;
22
- return fetch__default.default(input, {
23
- ...init,
24
- headers: {
25
- Authorization: `basic ${Buffer.from(
26
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
27
- `${config.appId}:${config.appSecret}`, 'utf8').toString('base64')}`,
28
- ...init?.headers,
29
- },
30
- });
31
- }
32
- : fetch__default.default),
33
- generateCodeChallenge: generators.generateCodeChallenge,
34
- generateCodeVerifier: generators.generateCodeVerifier,
35
- generateState: generators.generateState,
36
- });
12
+ class LogtoNodeBaseClient extends BaseClient__default.default {
13
+ constructor() {
14
+ super(...arguments);
37
15
  this.getContext = async ({ getAccessToken, resource, fetchUserInfo, } = {}) => {
38
16
  const isAuthenticated = await this.isAuthenticated();
39
17
  if (!isAuthenticated) {
@@ -51,11 +29,13 @@ class LogtoClient extends BaseClient__default.default {
51
29
  }
52
30
  try {
53
31
  const accessToken = await this.getAccessToken(resource);
32
+ const accessTokenClaims = await this.getAccessTokenClaims(resource);
54
33
  return {
55
34
  isAuthenticated,
56
35
  claims: await this.getIdTokenClaims(),
57
36
  userInfo: essentials.conditional(fetchUserInfo && (await this.fetchUserInfo())),
58
37
  accessToken,
38
+ scopes: accessTokenClaims.scope?.split(' '),
59
39
  };
60
40
  }
61
41
  catch {
@@ -95,4 +75,4 @@ Object.defineProperty(exports, 'UserScope', {
95
75
  enumerable: true,
96
76
  get: function () { return BaseClient.UserScope; }
97
77
  });
98
- exports.default = LogtoClient;
78
+ exports.default = LogtoNodeBaseClient;
@@ -1,10 +1,8 @@
1
- import type { LogtoConfig, ClientAdapter } from '@logto/client';
2
1
  import BaseClient from '@logto/client';
3
- import type { GetContextParameters, LogtoContext } from './types';
4
- export type { LogtoContext, GetContextParameters } from './types';
2
+ import type { GetContextParameters, LogtoContext } from './types.js';
3
+ export type { LogtoContext, GetContextParameters } from './types.js';
5
4
  export type { IdTokenClaims, LogtoErrorCode, LogtoConfig, LogtoClientErrorCode, Storage, StorageKey, InteractionMode, } from '@logto/client';
6
5
  export { LogtoError, OidcError, Prompt, LogtoRequestError, LogtoClientError, ReservedScope, UserScope, } from '@logto/client';
7
- export default class LogtoClient extends BaseClient {
8
- constructor(config: LogtoConfig, adapter: Pick<ClientAdapter, 'navigate' | 'storage'>);
6
+ export default class LogtoNodeBaseClient extends BaseClient {
9
7
  getContext: ({ getAccessToken, resource, fetchUserInfo, }?: GetContextParameters) => Promise<LogtoContext>;
10
8
  }
@@ -1,31 +1,10 @@
1
- import BaseClient, { createRequester } from '@logto/client';
1
+ import BaseClient from '@logto/client';
2
2
  export { LogtoClientError, LogtoError, LogtoRequestError, OidcError, Prompt, ReservedScope, UserScope } from '@logto/client';
3
3
  import { conditional } from '@silverhand/essentials';
4
- import fetch from 'node-fetch';
5
- import { generateCodeChallenge, generateCodeVerifier, generateState } from './utils/generators.mjs';
6
4
 
7
- class LogtoClient extends BaseClient {
8
- constructor(config, adapter) {
9
- super(config, {
10
- ...adapter,
11
- requester: createRequester(config.appSecret
12
- ? async (...args) => {
13
- const [input, init] = args;
14
- return fetch(input, {
15
- ...init,
16
- headers: {
17
- Authorization: `basic ${Buffer.from(
18
- // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
19
- `${config.appId}:${config.appSecret}`, 'utf8').toString('base64')}`,
20
- ...init?.headers,
21
- },
22
- });
23
- }
24
- : fetch),
25
- generateCodeChallenge,
26
- generateCodeVerifier,
27
- generateState,
28
- });
5
+ class LogtoNodeBaseClient extends BaseClient {
6
+ constructor() {
7
+ super(...arguments);
29
8
  this.getContext = async ({ getAccessToken, resource, fetchUserInfo, } = {}) => {
30
9
  const isAuthenticated = await this.isAuthenticated();
31
10
  if (!isAuthenticated) {
@@ -43,11 +22,13 @@ class LogtoClient extends BaseClient {
43
22
  }
44
23
  try {
45
24
  const accessToken = await this.getAccessToken(resource);
25
+ const accessTokenClaims = await this.getAccessTokenClaims(resource);
46
26
  return {
47
27
  isAuthenticated,
48
28
  claims: await this.getIdTokenClaims(),
49
29
  userInfo: conditional(fetchUserInfo && (await this.fetchUserInfo())),
50
30
  accessToken,
31
+ scopes: accessTokenClaims.scope?.split(' '),
51
32
  };
52
33
  }
53
34
  catch {
@@ -59,4 +40,4 @@ class LogtoClient extends BaseClient {
59
40
  }
60
41
  }
61
42
 
62
- export { LogtoClient as default };
43
+ export { LogtoNodeBaseClient as default };
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var BaseClient = require('@logto/client');
6
+ var fetch = require('node-fetch');
7
+ var client = require('./client.cjs');
8
+ var generators = require('./utils/generators.cjs');
9
+
10
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
11
+
12
+ var fetch__default = /*#__PURE__*/_interopDefault(fetch);
13
+
14
+ class LogtoClient extends client.default {
15
+ constructor(config, adapter) {
16
+ super(config, {
17
+ ...adapter,
18
+ requester: BaseClient.createRequester(config.appSecret
19
+ ? async (...args) => {
20
+ const [input, init] = args;
21
+ return fetch__default.default(input, {
22
+ ...init,
23
+ headers: {
24
+ Authorization: `Basic ${Buffer.from(
25
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
26
+ `${config.appId}:${config.appSecret}`, 'utf8').toString('base64')}`,
27
+ ...init?.headers,
28
+ },
29
+ });
30
+ }
31
+ : fetch__default.default),
32
+ generateCodeChallenge: generators.generateCodeChallenge,
33
+ generateCodeVerifier: generators.generateCodeVerifier,
34
+ generateState: generators.generateState,
35
+ });
36
+ }
37
+ }
38
+
39
+ Object.defineProperty(exports, 'LogtoClientError', {
40
+ enumerable: true,
41
+ get: function () { return BaseClient.LogtoClientError; }
42
+ });
43
+ Object.defineProperty(exports, 'LogtoError', {
44
+ enumerable: true,
45
+ get: function () { return BaseClient.LogtoError; }
46
+ });
47
+ Object.defineProperty(exports, 'LogtoRequestError', {
48
+ enumerable: true,
49
+ get: function () { return BaseClient.LogtoRequestError; }
50
+ });
51
+ Object.defineProperty(exports, 'OidcError', {
52
+ enumerable: true,
53
+ get: function () { return BaseClient.OidcError; }
54
+ });
55
+ Object.defineProperty(exports, 'Prompt', {
56
+ enumerable: true,
57
+ get: function () { return BaseClient.Prompt; }
58
+ });
59
+ Object.defineProperty(exports, 'ReservedScope', {
60
+ enumerable: true,
61
+ get: function () { return BaseClient.ReservedScope; }
62
+ });
63
+ Object.defineProperty(exports, 'UserScope', {
64
+ enumerable: true,
65
+ get: function () { return BaseClient.UserScope; }
66
+ });
67
+ exports.default = LogtoClient;
@@ -0,0 +1,8 @@
1
+ import type { LogtoConfig, ClientAdapter } from '@logto/client';
2
+ import BaseClient from './client.js';
3
+ export type { LogtoContext, GetContextParameters } from './types.js';
4
+ export type { IdTokenClaims, LogtoErrorCode, LogtoConfig, LogtoClientErrorCode, Storage, StorageKey, InteractionMode, } from '@logto/client';
5
+ export { LogtoError, OidcError, Prompt, LogtoRequestError, LogtoClientError, ReservedScope, UserScope, } from '@logto/client';
6
+ export default class LogtoClient extends BaseClient {
7
+ constructor(config: LogtoConfig, adapter: Pick<ClientAdapter, 'navigate' | 'storage'>);
8
+ }
@@ -0,0 +1,32 @@
1
+ import { createRequester } from '@logto/client';
2
+ export { LogtoClientError, LogtoError, LogtoRequestError, OidcError, Prompt, ReservedScope, UserScope } from '@logto/client';
3
+ import fetch from 'node-fetch';
4
+ import LogtoNodeBaseClient from './client.js';
5
+ import { generateCodeChallenge, generateCodeVerifier, generateState } from './utils/generators.js';
6
+
7
+ class LogtoClient extends LogtoNodeBaseClient {
8
+ constructor(config, adapter) {
9
+ super(config, {
10
+ ...adapter,
11
+ requester: createRequester(config.appSecret
12
+ ? async (...args) => {
13
+ const [input, init] = args;
14
+ return fetch(input, {
15
+ ...init,
16
+ headers: {
17
+ Authorization: `Basic ${Buffer.from(
18
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
19
+ `${config.appId}:${config.appSecret}`, 'utf8').toString('base64')}`,
20
+ ...init?.headers,
21
+ },
22
+ });
23
+ }
24
+ : fetch),
25
+ generateCodeChallenge,
26
+ generateCodeVerifier,
27
+ generateState,
28
+ });
29
+ }
30
+ }
31
+
32
+ export { LogtoClient as default };
@@ -9,6 +9,7 @@ export type LogtoContext = {
9
9
  claims?: IdTokenClaims;
10
10
  accessToken?: string;
11
11
  userInfo?: UserInfoResponse;
12
+ scopes?: string[];
12
13
  };
13
14
  export type GetContextParameters = {
14
15
  fetchUserInfo?: boolean;
package/package.json CHANGED
@@ -1,14 +1,22 @@
1
1
  {
2
2
  "name": "@logto/node",
3
- "version": "1.1.2",
4
- "source": "./src/index.ts",
5
- "main": "./lib/index.js",
3
+ "version": "2.1.0",
4
+ "type": "module",
5
+ "main": "./lib/src/index.cjs",
6
+ "module": "./lib/src/index.js",
7
+ "types": "./lib/src/index.d.ts",
6
8
  "exports": {
7
- "require": "./lib/index.js",
8
- "import": "./lib/index.mjs"
9
+ ".": {
10
+ "require": "./lib/src/index.cjs",
11
+ "import": "./lib/src/index.js",
12
+ "types": "./lib/src/index.d.ts"
13
+ },
14
+ "./edge": {
15
+ "require": "./lib/edge/index.cjs",
16
+ "import": "./lib/edge/index.js",
17
+ "types": "./lib/edge/index.d.ts"
18
+ }
9
19
  },
10
- "module": "./lib/index.mjs",
11
- "types": "./lib/index.d.ts",
12
20
  "files": [
13
21
  "lib"
14
22
  ],
@@ -18,26 +26,15 @@
18
26
  "url": "https://github.com/logto-io/js.git",
19
27
  "directory": "packages/node"
20
28
  },
21
- "scripts": {
22
- "dev:tsc": "tsc -p tsconfig.build.json -w --preserveWatchOutput",
23
- "precommit": "lint-staged",
24
- "check": "tsc --noEmit",
25
- "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c",
26
- "lint": "eslint --ext .ts src",
27
- "test": "jest",
28
- "test:coverage": "jest --silent --coverage",
29
- "prepack": "pnpm test"
30
- },
31
29
  "dependencies": {
32
- "@logto/client": "^1.1.2",
33
- "@silverhand/essentials": "^2.6.1",
30
+ "@logto/client": "^2.1.0",
31
+ "@silverhand/essentials": "^2.6.2",
34
32
  "js-base64": "^3.7.4",
35
33
  "node-fetch": "^2.6.7"
36
34
  },
37
35
  "devDependencies": {
38
- "@jest/types": "^29.5.0",
39
- "@silverhand/eslint-config": "^2.0.0",
40
- "@silverhand/ts-config": "^1.0.0",
36
+ "@silverhand/eslint-config": "^3.0.1",
37
+ "@silverhand/ts-config": "^3.0.0",
41
38
  "@swc/core": "^1.3.7",
42
39
  "@swc/jest": "^0.2.24",
43
40
  "@types/jest": "^29.5.0",
@@ -51,11 +48,22 @@
51
48
  "typescript": "^5.0.0"
52
49
  },
53
50
  "eslintConfig": {
54
- "extends": "@silverhand"
51
+ "extends": "@silverhand",
52
+ "rules": {
53
+ "unicorn/prefer-node-protocol": "off"
54
+ }
55
55
  },
56
56
  "prettier": "@silverhand/eslint-config/.prettierrc",
57
57
  "publishConfig": {
58
58
  "access": "public"
59
59
  },
60
- "gitHead": "9e9a8b0887ef67baa7c3c564590bb06e7801d03e"
61
- }
60
+ "scripts": {
61
+ "dev:tsc": "tsc -p tsconfig.build.json -w --preserveWatchOutput",
62
+ "precommit": "lint-staged",
63
+ "check": "tsc --noEmit",
64
+ "build": "rm -rf lib/ && tsc -p tsconfig.build.json --noEmit && rollup -c",
65
+ "lint": "eslint --ext .ts src",
66
+ "test": "jest",
67
+ "test:coverage": "node test.cjs && jest --silent --coverage"
68
+ }
69
+ }
File without changes
File without changes
File without changes