@logto/js 2.1.2 → 3.0.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 CHANGED
@@ -5,8 +5,6 @@
5
5
 
6
6
  The Logto JavaScript Core SDK written in TypeScript. Check out our [docs](https://docs.logto.io/JavaScript/js/) for more information.
7
7
 
8
- We also provide [文档](https://docs.logto.io/zh-cn/sdk/JavaScript/js/) in Simplified Chinese.
9
-
10
8
  ## Installation
11
9
 
12
10
  ### Using npm
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ var openid = require('./openid.cjs');
4
+
3
5
  const ContentType = {
4
6
  formUrlEncoded: { 'Content-Type': 'application/x-www-form-urlencoded' },
5
7
  };
@@ -31,6 +33,8 @@ exports.QueryKey = void 0;
31
33
  QueryKey["Token"] = "token";
32
34
  // Need to align with the OIDC extraParams settings in core
33
35
  QueryKey["InteractionMode"] = "interaction_mode";
36
+ /** The query key for specifying the organization ID. */
37
+ QueryKey["OrganizationId"] = "organization_id";
34
38
  })(exports.QueryKey || (exports.QueryKey = {}));
35
39
  /** The prompt parameter to be used for the authorization request. */
36
40
  exports.Prompt = void 0;
@@ -47,47 +51,23 @@ exports.Prompt = void 0;
47
51
  */
48
52
  Prompt["Login"] = "login";
49
53
  })(exports.Prompt || (exports.Prompt = {}));
50
- // TODO: @sijie @charles find a proper way to sync scopes constants with core
51
- exports.ReservedScope = void 0;
52
- (function (ReservedScope) {
53
- ReservedScope["OpenId"] = "openid";
54
- ReservedScope["OfflineAccess"] = "offline_access";
55
- })(exports.ReservedScope || (exports.ReservedScope = {}));
56
- /**
57
- * Scopes for ID Token and Userinfo Endpoint.
58
- */
59
- exports.UserScope = void 0;
60
- (function (UserScope) {
61
- /**
62
- * Scope for basic user info.
63
- *
64
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
65
- */
66
- UserScope["Profile"] = "profile";
67
- /**
68
- * Scope for user email address.
69
- *
70
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
71
- */
72
- UserScope["Email"] = "email";
73
- /**
74
- * Scope for user phone number.
75
- *
76
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
77
- */
78
- UserScope["Phone"] = "phone";
79
- /**
80
- * Scope for user's custom data.
81
- *
82
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
83
- */
84
- UserScope["CustomData"] = "custom_data";
85
- /**
86
- * Scope for user's social identity details.
87
- *
88
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
89
- */
90
- UserScope["Identities"] = "identities";
91
- })(exports.UserScope || (exports.UserScope = {}));
92
54
 
55
+ Object.defineProperty(exports, 'ReservedResource', {
56
+ enumerable: true,
57
+ get: function () { return openid.ReservedResource; }
58
+ });
59
+ Object.defineProperty(exports, 'ReservedScope', {
60
+ enumerable: true,
61
+ get: function () { return openid.ReservedScope; }
62
+ });
63
+ Object.defineProperty(exports, 'UserScope', {
64
+ enumerable: true,
65
+ get: function () { return openid.UserScope; }
66
+ });
67
+ exports.buildOrganizationUrn = openid.buildOrganizationUrn;
68
+ exports.getOrganizationIdFromUrn = openid.getOrganizationIdFromUrn;
69
+ exports.idTokenClaims = openid.idTokenClaims;
70
+ exports.organizationUrnPrefix = openid.organizationUrnPrefix;
71
+ exports.userClaims = openid.userClaims;
72
+ exports.userinfoClaims = openid.userinfoClaims;
93
73
  exports.ContentType = ContentType;
@@ -1,3 +1,4 @@
1
+ export * from './openid.js';
1
2
  export declare const ContentType: {
2
3
  formUrlEncoded: {
3
4
  'Content-Type': string;
@@ -27,7 +28,9 @@ export declare enum QueryKey {
27
28
  Scope = "scope",
28
29
  State = "state",
29
30
  Token = "token",
30
- InteractionMode = "interaction_mode"
31
+ InteractionMode = "interaction_mode",
32
+ /** The query key for specifying the organization ID. */
33
+ OrganizationId = "organization_id"
31
34
  }
32
35
  /** The prompt parameter to be used for the authorization request. */
33
36
  export declare enum Prompt {
@@ -43,42 +46,3 @@ export declare enum Prompt {
43
46
  */
44
47
  Login = "login"
45
48
  }
46
- export declare enum ReservedScope {
47
- OpenId = "openid",
48
- OfflineAccess = "offline_access"
49
- }
50
- /**
51
- * Scopes for ID Token and Userinfo Endpoint.
52
- */
53
- export declare enum UserScope {
54
- /**
55
- * Scope for basic user info.
56
- *
57
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
58
- */
59
- Profile = "profile",
60
- /**
61
- * Scope for user email address.
62
- *
63
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
64
- */
65
- Email = "email",
66
- /**
67
- * Scope for user phone number.
68
- *
69
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
70
- */
71
- Phone = "phone",
72
- /**
73
- * Scope for user's custom data.
74
- *
75
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
76
- */
77
- CustomData = "custom_data",
78
- /**
79
- * Scope for user's social identity details.
80
- *
81
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
82
- */
83
- Identities = "identities"
84
- }
@@ -1,3 +1,5 @@
1
+ export { ReservedResource, ReservedScope, UserScope, buildOrganizationUrn, getOrganizationIdFromUrn, idTokenClaims, organizationUrnPrefix, userClaims, userinfoClaims } from './openid.js';
2
+
1
3
  const ContentType = {
2
4
  formUrlEncoded: { 'Content-Type': 'application/x-www-form-urlencoded' },
3
5
  };
@@ -29,6 +31,8 @@ var QueryKey;
29
31
  QueryKey["Token"] = "token";
30
32
  // Need to align with the OIDC extraParams settings in core
31
33
  QueryKey["InteractionMode"] = "interaction_mode";
34
+ /** The query key for specifying the organization ID. */
35
+ QueryKey["OrganizationId"] = "organization_id";
32
36
  })(QueryKey || (QueryKey = {}));
33
37
  /** The prompt parameter to be used for the authorization request. */
34
38
  var Prompt;
@@ -45,47 +49,5 @@ var Prompt;
45
49
  */
46
50
  Prompt["Login"] = "login";
47
51
  })(Prompt || (Prompt = {}));
48
- // TODO: @sijie @charles find a proper way to sync scopes constants with core
49
- var ReservedScope;
50
- (function (ReservedScope) {
51
- ReservedScope["OpenId"] = "openid";
52
- ReservedScope["OfflineAccess"] = "offline_access";
53
- })(ReservedScope || (ReservedScope = {}));
54
- /**
55
- * Scopes for ID Token and Userinfo Endpoint.
56
- */
57
- var UserScope;
58
- (function (UserScope) {
59
- /**
60
- * Scope for basic user info.
61
- *
62
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
63
- */
64
- UserScope["Profile"] = "profile";
65
- /**
66
- * Scope for user email address.
67
- *
68
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
69
- */
70
- UserScope["Email"] = "email";
71
- /**
72
- * Scope for user phone number.
73
- *
74
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
75
- */
76
- UserScope["Phone"] = "phone";
77
- /**
78
- * Scope for user's custom data.
79
- *
80
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
81
- */
82
- UserScope["CustomData"] = "custom_data";
83
- /**
84
- * Scope for user's social identity details.
85
- *
86
- * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
87
- */
88
- UserScope["Identities"] = "identities";
89
- })(UserScope || (UserScope = {}));
90
52
 
91
- export { ContentType, Prompt, QueryKey, ReservedScope, TokenGrantType, UserScope };
53
+ export { ContentType, Prompt, QueryKey, TokenGrantType };
@@ -0,0 +1,155 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * @overview Constants for Logto. Synchronized with `@logto/core-kit` package at hash `081094d`.
5
+ */
6
+ /** Scopes that reserved by Logto, which will be added to the auth request automatically. */
7
+ exports.ReservedScope = void 0;
8
+ (function (ReservedScope) {
9
+ ReservedScope["OpenId"] = "openid";
10
+ ReservedScope["OfflineAccess"] = "offline_access";
11
+ })(exports.ReservedScope || (exports.ReservedScope = {}));
12
+ /** Resources that reserved by Logto, which cannot be defined by users. */
13
+ exports.ReservedResource = void 0;
14
+ (function (ReservedResource) {
15
+ /**
16
+ * The resource for organization template per RFC 0001.
17
+ *
18
+ * @see {@link https://github.com/logto-io/rfcs | RFC 0001} for more details.
19
+ */
20
+ ReservedResource["Organization"] = "urn:logto:resource:organizations";
21
+ })(exports.ReservedResource || (exports.ReservedResource = {}));
22
+ /**
23
+ * Scopes for ID Token and Userinfo Endpoint.
24
+ */
25
+ exports.UserScope = void 0;
26
+ (function (UserScope) {
27
+ /**
28
+ * Scope for basic user info.
29
+ *
30
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
31
+ */
32
+ UserScope["Profile"] = "profile";
33
+ /**
34
+ * Scope for user email address.
35
+ *
36
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
37
+ */
38
+ UserScope["Email"] = "email";
39
+ /**
40
+ * Scope for user phone number.
41
+ *
42
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
43
+ */
44
+ UserScope["Phone"] = "phone";
45
+ /**
46
+ * Scope for user's custom data.
47
+ *
48
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
49
+ */
50
+ UserScope["CustomData"] = "custom_data";
51
+ /**
52
+ * Scope for user's social identity details.
53
+ *
54
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
55
+ */
56
+ UserScope["Identities"] = "identities";
57
+ /**
58
+ * Scope for user's roles.
59
+ *
60
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
61
+ */
62
+ UserScope["Roles"] = "roles";
63
+ /**
64
+ * Scope for user's organization IDs and perform organization token grant per [RFC 0001](https://github.com/logto-io/rfcs).
65
+ *
66
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
67
+ */
68
+ UserScope["Organizations"] = "urn:logto:scope:organizations";
69
+ /**
70
+ * Scope for user's organization roles per [RFC 0001](https://github.com/logto-io/rfcs).
71
+ *
72
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
73
+ */
74
+ UserScope["OrganizationRoles"] = "urn:logto:scope:organization_roles";
75
+ })(exports.UserScope || (exports.UserScope = {}));
76
+ /**
77
+ * Mapped claims that ID Token includes.
78
+ */
79
+ const idTokenClaims = Object.freeze({
80
+ [exports.UserScope.Profile]: ['name', 'picture', 'username'],
81
+ [exports.UserScope.Email]: ['email', 'email_verified'],
82
+ [exports.UserScope.Phone]: ['phone_number', 'phone_number_verified'],
83
+ [exports.UserScope.Roles]: ['roles'],
84
+ [exports.UserScope.Organizations]: ['organizations'],
85
+ [exports.UserScope.OrganizationRoles]: ['organization_roles'],
86
+ [exports.UserScope.CustomData]: [],
87
+ [exports.UserScope.Identities]: [],
88
+ });
89
+ /**
90
+ * Additional claims that Userinfo Endpoint returns.
91
+ */
92
+ const userinfoClaims = Object.freeze({
93
+ [exports.UserScope.Profile]: [],
94
+ [exports.UserScope.Email]: [],
95
+ [exports.UserScope.Phone]: [],
96
+ [exports.UserScope.Roles]: [],
97
+ [exports.UserScope.Organizations]: [],
98
+ [exports.UserScope.OrganizationRoles]: [],
99
+ [exports.UserScope.CustomData]: ['custom_data'],
100
+ [exports.UserScope.Identities]: ['identities'],
101
+ });
102
+ const userClaims = Object.freeze(
103
+ // Hard to infer type directly, use `as` for a workaround.
104
+ // eslint-disable-next-line no-restricted-syntax
105
+ Object.fromEntries(Object.values(exports.UserScope).map((current) => [
106
+ current,
107
+ [...idTokenClaims[current], ...userinfoClaims[current]],
108
+ ])));
109
+ /**
110
+ * The prefix of the URN (Uniform Resource Name) for the organization in Logto.
111
+ *
112
+ * @example
113
+ * ```
114
+ * urn:logto:organization:123 // organization with ID 123
115
+ * ```
116
+ * @see {@link https://en.wikipedia.org/wiki/Uniform_Resource_Name | Uniform Resource Name}
117
+ */
118
+ const organizationUrnPrefix = 'urn:logto:organization:';
119
+ /**
120
+ * Build the URN (Uniform Resource Name) for the organization in Logto.
121
+ *
122
+ * @param organizationId The ID of the organization.
123
+ * @returns The URN for the organization.
124
+ * @see {@link organizationUrnPrefix} for the prefix of the URN.
125
+ * @example
126
+ * ```ts
127
+ * buildOrganizationUrn('1') // returns 'urn:logto:organization:1'
128
+ * ```
129
+ */
130
+ const buildOrganizationUrn = (organizationId) => `${organizationUrnPrefix}${organizationId}`;
131
+ /**
132
+ * Get the organization ID from the URN (Uniform Resource Name) for the organization in Logto.
133
+ *
134
+ * @param urn The URN for the organization. Must start with {@link organizationUrnPrefix}.
135
+ * @returns The ID of the organization.
136
+ * @throws {TypeError} If the URN is invalid.
137
+ * @example
138
+ * ```ts
139
+ * getOrganizationIdFromUrn('1') // throws TypeError
140
+ * getOrganizationIdFromUrn('urn:logto:organization:1') // returns '1'
141
+ * ```
142
+ */
143
+ const getOrganizationIdFromUrn = (urn) => {
144
+ if (!urn.startsWith(organizationUrnPrefix)) {
145
+ throw new TypeError('Invalid organization URN.');
146
+ }
147
+ return urn.slice(organizationUrnPrefix.length);
148
+ };
149
+
150
+ exports.buildOrganizationUrn = buildOrganizationUrn;
151
+ exports.getOrganizationIdFromUrn = getOrganizationIdFromUrn;
152
+ exports.idTokenClaims = idTokenClaims;
153
+ exports.organizationUrnPrefix = organizationUrnPrefix;
154
+ exports.userClaims = userClaims;
155
+ exports.userinfoClaims = userinfoClaims;
@@ -0,0 +1,115 @@
1
+ /**
2
+ * @overview Constants for Logto. Synchronized with `@logto/core-kit` package at hash `081094d`.
3
+ */
4
+ /** Scopes that reserved by Logto, which will be added to the auth request automatically. */
5
+ export declare enum ReservedScope {
6
+ OpenId = "openid",
7
+ OfflineAccess = "offline_access"
8
+ }
9
+ /** Resources that reserved by Logto, which cannot be defined by users. */
10
+ export declare enum ReservedResource {
11
+ /**
12
+ * The resource for organization template per RFC 0001.
13
+ *
14
+ * @see {@link https://github.com/logto-io/rfcs | RFC 0001} for more details.
15
+ */
16
+ Organization = "urn:logto:resource:organizations"
17
+ }
18
+ export type UserClaim = 'name' | 'picture' | 'username' | 'email' | 'email_verified' | 'phone_number' | 'phone_number_verified' | 'roles' | 'organizations' | 'organization_roles' | 'custom_data' | 'identities';
19
+ /**
20
+ * Scopes for ID Token and Userinfo Endpoint.
21
+ */
22
+ export declare enum UserScope {
23
+ /**
24
+ * Scope for basic user info.
25
+ *
26
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
27
+ */
28
+ Profile = "profile",
29
+ /**
30
+ * Scope for user email address.
31
+ *
32
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
33
+ */
34
+ Email = "email",
35
+ /**
36
+ * Scope for user phone number.
37
+ *
38
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
39
+ */
40
+ Phone = "phone",
41
+ /**
42
+ * Scope for user's custom data.
43
+ *
44
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
45
+ */
46
+ CustomData = "custom_data",
47
+ /**
48
+ * Scope for user's social identity details.
49
+ *
50
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
51
+ */
52
+ Identities = "identities",
53
+ /**
54
+ * Scope for user's roles.
55
+ *
56
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
57
+ */
58
+ Roles = "roles",
59
+ /**
60
+ * Scope for user's organization IDs and perform organization token grant per [RFC 0001](https://github.com/logto-io/rfcs).
61
+ *
62
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
63
+ */
64
+ Organizations = "urn:logto:scope:organizations",
65
+ /**
66
+ * Scope for user's organization roles per [RFC 0001](https://github.com/logto-io/rfcs).
67
+ *
68
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
69
+ */
70
+ OrganizationRoles = "urn:logto:scope:organization_roles"
71
+ }
72
+ /**
73
+ * Mapped claims that ID Token includes.
74
+ */
75
+ export declare const idTokenClaims: Readonly<Record<UserScope, UserClaim[]>>;
76
+ /**
77
+ * Additional claims that Userinfo Endpoint returns.
78
+ */
79
+ export declare const userinfoClaims: Readonly<Record<UserScope, UserClaim[]>>;
80
+ export declare const userClaims: Readonly<Record<UserScope, UserClaim[]>>;
81
+ /**
82
+ * The prefix of the URN (Uniform Resource Name) for the organization in Logto.
83
+ *
84
+ * @example
85
+ * ```
86
+ * urn:logto:organization:123 // organization with ID 123
87
+ * ```
88
+ * @see {@link https://en.wikipedia.org/wiki/Uniform_Resource_Name | Uniform Resource Name}
89
+ */
90
+ export declare const organizationUrnPrefix = "urn:logto:organization:";
91
+ /**
92
+ * Build the URN (Uniform Resource Name) for the organization in Logto.
93
+ *
94
+ * @param organizationId The ID of the organization.
95
+ * @returns The URN for the organization.
96
+ * @see {@link organizationUrnPrefix} for the prefix of the URN.
97
+ * @example
98
+ * ```ts
99
+ * buildOrganizationUrn('1') // returns 'urn:logto:organization:1'
100
+ * ```
101
+ */
102
+ export declare const buildOrganizationUrn: (organizationId: string) => string;
103
+ /**
104
+ * Get the organization ID from the URN (Uniform Resource Name) for the organization in Logto.
105
+ *
106
+ * @param urn The URN for the organization. Must start with {@link organizationUrnPrefix}.
107
+ * @returns The ID of the organization.
108
+ * @throws {TypeError} If the URN is invalid.
109
+ * @example
110
+ * ```ts
111
+ * getOrganizationIdFromUrn('1') // throws TypeError
112
+ * getOrganizationIdFromUrn('urn:logto:organization:1') // returns '1'
113
+ * ```
114
+ */
115
+ export declare const getOrganizationIdFromUrn: (urn: string) => string;
@@ -0,0 +1,148 @@
1
+ /**
2
+ * @overview Constants for Logto. Synchronized with `@logto/core-kit` package at hash `081094d`.
3
+ */
4
+ /** Scopes that reserved by Logto, which will be added to the auth request automatically. */
5
+ var ReservedScope;
6
+ (function (ReservedScope) {
7
+ ReservedScope["OpenId"] = "openid";
8
+ ReservedScope["OfflineAccess"] = "offline_access";
9
+ })(ReservedScope || (ReservedScope = {}));
10
+ /** Resources that reserved by Logto, which cannot be defined by users. */
11
+ var ReservedResource;
12
+ (function (ReservedResource) {
13
+ /**
14
+ * The resource for organization template per RFC 0001.
15
+ *
16
+ * @see {@link https://github.com/logto-io/rfcs | RFC 0001} for more details.
17
+ */
18
+ ReservedResource["Organization"] = "urn:logto:resource:organizations";
19
+ })(ReservedResource || (ReservedResource = {}));
20
+ /**
21
+ * Scopes for ID Token and Userinfo Endpoint.
22
+ */
23
+ var UserScope;
24
+ (function (UserScope) {
25
+ /**
26
+ * Scope for basic user info.
27
+ *
28
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
29
+ */
30
+ UserScope["Profile"] = "profile";
31
+ /**
32
+ * Scope for user email address.
33
+ *
34
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
35
+ */
36
+ UserScope["Email"] = "email";
37
+ /**
38
+ * Scope for user phone number.
39
+ *
40
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
41
+ */
42
+ UserScope["Phone"] = "phone";
43
+ /**
44
+ * Scope for user's custom data.
45
+ *
46
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
47
+ */
48
+ UserScope["CustomData"] = "custom_data";
49
+ /**
50
+ * Scope for user's social identity details.
51
+ *
52
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
53
+ */
54
+ UserScope["Identities"] = "identities";
55
+ /**
56
+ * Scope for user's roles.
57
+ *
58
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
59
+ */
60
+ UserScope["Roles"] = "roles";
61
+ /**
62
+ * Scope for user's organization IDs and perform organization token grant per [RFC 0001](https://github.com/logto-io/rfcs).
63
+ *
64
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
65
+ */
66
+ UserScope["Organizations"] = "urn:logto:scope:organizations";
67
+ /**
68
+ * Scope for user's organization roles per [RFC 0001](https://github.com/logto-io/rfcs).
69
+ *
70
+ * See {@link idTokenClaims} for mapped claims in ID Token and {@link userinfoClaims} for additional claims in Userinfo Endpoint.
71
+ */
72
+ UserScope["OrganizationRoles"] = "urn:logto:scope:organization_roles";
73
+ })(UserScope || (UserScope = {}));
74
+ /**
75
+ * Mapped claims that ID Token includes.
76
+ */
77
+ const idTokenClaims = Object.freeze({
78
+ [UserScope.Profile]: ['name', 'picture', 'username'],
79
+ [UserScope.Email]: ['email', 'email_verified'],
80
+ [UserScope.Phone]: ['phone_number', 'phone_number_verified'],
81
+ [UserScope.Roles]: ['roles'],
82
+ [UserScope.Organizations]: ['organizations'],
83
+ [UserScope.OrganizationRoles]: ['organization_roles'],
84
+ [UserScope.CustomData]: [],
85
+ [UserScope.Identities]: [],
86
+ });
87
+ /**
88
+ * Additional claims that Userinfo Endpoint returns.
89
+ */
90
+ const userinfoClaims = Object.freeze({
91
+ [UserScope.Profile]: [],
92
+ [UserScope.Email]: [],
93
+ [UserScope.Phone]: [],
94
+ [UserScope.Roles]: [],
95
+ [UserScope.Organizations]: [],
96
+ [UserScope.OrganizationRoles]: [],
97
+ [UserScope.CustomData]: ['custom_data'],
98
+ [UserScope.Identities]: ['identities'],
99
+ });
100
+ const userClaims = Object.freeze(
101
+ // Hard to infer type directly, use `as` for a workaround.
102
+ // eslint-disable-next-line no-restricted-syntax
103
+ Object.fromEntries(Object.values(UserScope).map((current) => [
104
+ current,
105
+ [...idTokenClaims[current], ...userinfoClaims[current]],
106
+ ])));
107
+ /**
108
+ * The prefix of the URN (Uniform Resource Name) for the organization in Logto.
109
+ *
110
+ * @example
111
+ * ```
112
+ * urn:logto:organization:123 // organization with ID 123
113
+ * ```
114
+ * @see {@link https://en.wikipedia.org/wiki/Uniform_Resource_Name | Uniform Resource Name}
115
+ */
116
+ const organizationUrnPrefix = 'urn:logto:organization:';
117
+ /**
118
+ * Build the URN (Uniform Resource Name) for the organization in Logto.
119
+ *
120
+ * @param organizationId The ID of the organization.
121
+ * @returns The URN for the organization.
122
+ * @see {@link organizationUrnPrefix} for the prefix of the URN.
123
+ * @example
124
+ * ```ts
125
+ * buildOrganizationUrn('1') // returns 'urn:logto:organization:1'
126
+ * ```
127
+ */
128
+ const buildOrganizationUrn = (organizationId) => `${organizationUrnPrefix}${organizationId}`;
129
+ /**
130
+ * Get the organization ID from the URN (Uniform Resource Name) for the organization in Logto.
131
+ *
132
+ * @param urn The URN for the organization. Must start with {@link organizationUrnPrefix}.
133
+ * @returns The ID of the organization.
134
+ * @throws {TypeError} If the URN is invalid.
135
+ * @example
136
+ * ```ts
137
+ * getOrganizationIdFromUrn('1') // throws TypeError
138
+ * getOrganizationIdFromUrn('urn:logto:organization:1') // returns '1'
139
+ * ```
140
+ */
141
+ const getOrganizationIdFromUrn = (urn) => {
142
+ if (!urn.startsWith(organizationUrnPrefix)) {
143
+ throw new TypeError('Invalid organization URN.');
144
+ }
145
+ return urn.slice(organizationUrnPrefix.length);
146
+ };
147
+
148
+ export { ReservedResource, ReservedScope, UserScope, buildOrganizationUrn, getOrganizationIdFromUrn, idTokenClaims, organizationUrnPrefix, userClaims, userinfoClaims };
@@ -24,7 +24,14 @@ const fetchTokenByAuthorizationCode = async ({ clientId, tokenEndpoint, redirect
24
24
  });
25
25
  return camelcaseKeys__default.default(snakeCaseCodeTokenResponse);
26
26
  };
27
- const fetchTokenByRefreshToken = async ({ clientId, tokenEndpoint, refreshToken, resource, scopes }, requester) => {
27
+ /**
28
+ * Fetch access token by refresh token using the token endpoint and `refresh_token` grant type.
29
+ * @param params The parameters for fetching access token.
30
+ * @param requester The requester for sending HTTP request.
31
+ * @returns A Promise that resolves to the access token response.
32
+ */
33
+ const fetchTokenByRefreshToken = async (params, requester) => {
34
+ const { clientId, tokenEndpoint, refreshToken, resource, organizationId, scopes } = params;
28
35
  const parameters = new URLSearchParams();
29
36
  parameters.append(index.QueryKey.ClientId, clientId);
30
37
  parameters.append(index.QueryKey.RefreshToken, refreshToken);
@@ -32,6 +39,9 @@ const fetchTokenByRefreshToken = async ({ clientId, tokenEndpoint, refreshToken,
32
39
  if (resource) {
33
40
  parameters.append(index.QueryKey.Resource, resource);
34
41
  }
42
+ if (organizationId) {
43
+ parameters.append(index.QueryKey.OrganizationId, organizationId);
44
+ }
35
45
  if (scopes?.length) {
36
46
  parameters.append(index.QueryKey.Scope, scopes.join(' '));
37
47
  }
@@ -9,10 +9,20 @@ export type FetchTokenByAuthorizationCodeParameters = {
9
9
  resource?: string;
10
10
  };
11
11
  export type FetchTokenByRefreshTokenParameters = {
12
+ /** The client ID of the application. */
12
13
  clientId: string;
14
+ /** The token endpoint of the authorization server. */
13
15
  tokenEndpoint: string;
16
+ /** The refresh token to be used to fetch the organization access token. */
14
17
  refreshToken: string;
18
+ /** The API resource to be fetch the access token for. */
15
19
  resource?: string;
20
+ /** The ID of the organization to be fetch the access token for. */
21
+ organizationId?: string;
22
+ /**
23
+ * The scopes to request for the access token. If not provided, the authorization server
24
+ * will use all the scopes that the client is authorized for.
25
+ */
16
26
  scopes?: string[];
17
27
  };
18
28
  type SnakeCaseCodeTokenResponse = {
@@ -25,12 +35,18 @@ type SnakeCaseCodeTokenResponse = {
25
35
  export type CodeTokenResponse = KeysToCamelCase<SnakeCaseCodeTokenResponse>;
26
36
  type SnakeCaseRefreshTokenTokenResponse = {
27
37
  access_token: string;
28
- refresh_token: string;
38
+ refresh_token?: string;
29
39
  id_token?: string;
30
40
  scope: string;
31
41
  expires_in: number;
32
42
  };
33
43
  export type RefreshTokenTokenResponse = KeysToCamelCase<SnakeCaseRefreshTokenTokenResponse>;
34
44
  export declare const fetchTokenByAuthorizationCode: ({ clientId, tokenEndpoint, redirectUri, codeVerifier, code, resource, }: FetchTokenByAuthorizationCodeParameters, requester: Requester) => Promise<CodeTokenResponse>;
35
- export declare const fetchTokenByRefreshToken: ({ clientId, tokenEndpoint, refreshToken, resource, scopes }: FetchTokenByRefreshTokenParameters, requester: Requester) => Promise<RefreshTokenTokenResponse>;
45
+ /**
46
+ * Fetch access token by refresh token using the token endpoint and `refresh_token` grant type.
47
+ * @param params The parameters for fetching access token.
48
+ * @param requester The requester for sending HTTP request.
49
+ * @returns A Promise that resolves to the access token response.
50
+ */
51
+ export declare const fetchTokenByRefreshToken: (params: FetchTokenByRefreshTokenParameters, requester: Requester) => Promise<RefreshTokenTokenResponse>;
36
52
  export {};
@@ -18,7 +18,14 @@ const fetchTokenByAuthorizationCode = async ({ clientId, tokenEndpoint, redirect
18
18
  });
19
19
  return camelcaseKeys(snakeCaseCodeTokenResponse);
20
20
  };
21
- const fetchTokenByRefreshToken = async ({ clientId, tokenEndpoint, refreshToken, resource, scopes }, requester) => {
21
+ /**
22
+ * Fetch access token by refresh token using the token endpoint and `refresh_token` grant type.
23
+ * @param params The parameters for fetching access token.
24
+ * @param requester The requester for sending HTTP request.
25
+ * @returns A Promise that resolves to the access token response.
26
+ */
27
+ const fetchTokenByRefreshToken = async (params, requester) => {
28
+ const { clientId, tokenEndpoint, refreshToken, resource, organizationId, scopes } = params;
22
29
  const parameters = new URLSearchParams();
23
30
  parameters.append(QueryKey.ClientId, clientId);
24
31
  parameters.append(QueryKey.RefreshToken, refreshToken);
@@ -26,6 +33,9 @@ const fetchTokenByRefreshToken = async ({ clientId, tokenEndpoint, refreshToken,
26
33
  if (resource) {
27
34
  parameters.append(QueryKey.Resource, resource);
28
35
  }
36
+ if (organizationId) {
37
+ parameters.append(QueryKey.OrganizationId, organizationId);
38
+ }
29
39
  if (scopes?.length) {
30
40
  parameters.append(QueryKey.Scope, scopes.join(' '));
31
41
  }
package/lib/index.cjs CHANGED
@@ -13,6 +13,7 @@ var accessToken = require('./utils/access-token.cjs');
13
13
  var scopes = require('./utils/scopes.cjs');
14
14
  var arbitraryObject = require('./utils/arbitrary-object.cjs');
15
15
  var index = require('./consts/index.cjs');
16
+ var openid = require('./consts/openid.cjs');
16
17
 
17
18
 
18
19
 
@@ -44,15 +45,25 @@ Object.defineProperty(exports, 'QueryKey', {
44
45
  enumerable: true,
45
46
  get: function () { return index.QueryKey; }
46
47
  });
47
- Object.defineProperty(exports, 'ReservedScope', {
48
- enumerable: true,
49
- get: function () { return index.ReservedScope; }
50
- });
51
48
  Object.defineProperty(exports, 'TokenGrantType', {
52
49
  enumerable: true,
53
50
  get: function () { return index.TokenGrantType; }
54
51
  });
52
+ Object.defineProperty(exports, 'ReservedResource', {
53
+ enumerable: true,
54
+ get: function () { return openid.ReservedResource; }
55
+ });
56
+ Object.defineProperty(exports, 'ReservedScope', {
57
+ enumerable: true,
58
+ get: function () { return openid.ReservedScope; }
59
+ });
55
60
  Object.defineProperty(exports, 'UserScope', {
56
61
  enumerable: true,
57
- get: function () { return index.UserScope; }
62
+ get: function () { return openid.UserScope; }
58
63
  });
64
+ exports.buildOrganizationUrn = openid.buildOrganizationUrn;
65
+ exports.getOrganizationIdFromUrn = openid.getOrganizationIdFromUrn;
66
+ exports.idTokenClaims = openid.idTokenClaims;
67
+ exports.organizationUrnPrefix = openid.organizationUrnPrefix;
68
+ exports.userClaims = openid.userClaims;
69
+ exports.userinfoClaims = openid.userinfoClaims;
package/lib/index.js CHANGED
@@ -10,4 +10,5 @@ export { decodeIdToken, verifyIdToken } from './utils/id-token.js';
10
10
  export { decodeAccessToken } from './utils/access-token.js';
11
11
  export { withDefaultScopes } from './utils/scopes.js';
12
12
  export { isArbitraryObject } from './utils/arbitrary-object.js';
13
- export { ContentType, Prompt, QueryKey, ReservedScope, TokenGrantType, UserScope } from './consts/index.js';
13
+ export { ContentType, Prompt, QueryKey, TokenGrantType } from './consts/index.js';
14
+ export { ReservedResource, ReservedScope, UserScope, buildOrganizationUrn, getOrganizationIdFromUrn, idTokenClaims, organizationUrnPrefix, userClaims, userinfoClaims } from './consts/openid.js';
@@ -1,19 +1,46 @@
1
1
  import type { Nullable } from '@silverhand/essentials';
2
2
  import type { JWTVerifyGetKey } from 'jose';
3
3
  export type IdTokenClaims = {
4
+ /** Issuer of this token. */
4
5
  iss: string;
6
+ /** Subject (the user ID) of this token. */
5
7
  sub: string;
8
+ /** Audience (the client ID) of this token. */
6
9
  aud: string;
10
+ /** Expiration time of this token. */
7
11
  exp: number;
12
+ /** Time at which this token was issued. */
8
13
  iat: number;
9
14
  at_hash?: Nullable<string>;
15
+ /** Full name of the user. */
10
16
  name?: Nullable<string>;
17
+ /** Username of the user. */
11
18
  username?: Nullable<string>;
19
+ /** URL of the user's profile picture. */
12
20
  picture?: Nullable<string>;
21
+ /** Email address of the user. */
13
22
  email?: Nullable<string>;
23
+ /** Whether the user's email address has been verified. */
14
24
  email_verified?: boolean;
25
+ /** Phone number of the user. */
15
26
  phone_number?: Nullable<string>;
27
+ /** Whether the user's phone number has been verified. */
16
28
  phone_number_verified?: boolean;
17
- };
29
+ /** Organization IDs that the user has membership in. */
30
+ organizations?: string[];
31
+ /**
32
+ * All organization roles that the user has. The format is `{organizationId}:{roleName}`.
33
+ *
34
+ * Note that not all organizations are included in this list, only the ones that the user has roles in.
35
+ *
36
+ * @example
37
+ * ```ts
38
+ * ['org1:admin', 'org2:member'] // The user is an admin of org1 and a member of org2.
39
+ * ```
40
+ */
41
+ organization_roles?: string[];
42
+ /** Roles that the user has for API resources. */
43
+ roles?: string[];
44
+ } & Record<string, unknown>;
18
45
  export declare const verifyIdToken: (idToken: string, clientId: string, issuer: string, jwks: JWTVerifyGetKey) => Promise<void>;
19
46
  export declare const decodeIdToken: (token: string) => IdTokenClaims;
@@ -1,14 +1,15 @@
1
1
  'use strict';
2
2
 
3
- var index = require('../consts/index.cjs');
3
+ require('../consts/index.cjs');
4
+ var openid = require('../consts/openid.cjs');
4
5
 
5
6
  /**
6
7
  * @param originalScopes
7
8
  * @return scopes should contain all default scopes (`openid`, `offline_access` and `profile`)
8
9
  */
9
10
  const withDefaultScopes = (originalScopes) => {
10
- const reservedScopes = Object.values(index.ReservedScope);
11
- const uniqueScopes = new Set([...reservedScopes, index.UserScope.Profile, ...(originalScopes ?? [])]);
11
+ const reservedScopes = Object.values(openid.ReservedScope);
12
+ const uniqueScopes = new Set([...reservedScopes, openid.UserScope.Profile, ...(originalScopes ?? [])]);
12
13
  return Array.from(uniqueScopes).join(' ');
13
14
  };
14
15
 
@@ -1,4 +1,5 @@
1
- import { ReservedScope, UserScope } from '../consts/index.js';
1
+ import '../consts/index.js';
2
+ import { ReservedScope, UserScope } from '../consts/openid.js';
2
3
 
3
4
  /**
4
5
  * @param originalScopes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logto/js",
3
- "version": "2.1.2",
3
+ "version": "3.0.0",
4
4
  "type": "module",
5
5
  "main": "./lib/index.cjs",
6
6
  "module": "./lib/index.js",
@@ -22,7 +22,7 @@
22
22
  "dependencies": {
23
23
  "@silverhand/essentials": "^2.6.2",
24
24
  "camelcase-keys": "^7.0.1",
25
- "jose": "^4.13.2"
25
+ "jose": "^5.0.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@silverhand/eslint-config": "^4.0.1",
@@ -35,12 +35,12 @@
35
35
  "jest": "^29.5.0",
36
36
  "jest-environment-jsdom": "^29.5.0",
37
37
  "jest-matcher-specific-error": "^1.0.0",
38
- "lint-staged": "^13.0.0",
38
+ "lint-staged": "^15.0.0",
39
39
  "nock": "^13.3.0",
40
40
  "prettier": "^3.0.0",
41
41
  "rollup": "^3.20.2",
42
42
  "text-encoder": "^0.0.4",
43
- "type-fest": "^3.0.0",
43
+ "type-fest": "^4.0.0",
44
44
  "typescript": "^5.0.0"
45
45
  },
46
46
  "eslintConfig": {