@logto/connector-dingtalk-web 0.1.0 → 0.2.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 +30 -26
- package/lib/index.js +165 -158
- package/lib/index.js.map +1 -0
- package/package.json +11 -16
- package/lib/constant.d.ts +0 -7
- package/lib/index.d.ts +0 -11
- package/lib/mock.d.ts +0 -5
- package/lib/types.d.ts +0 -65
package/README.md
CHANGED
|
@@ -12,6 +12,7 @@ The official Logto connector for DingTalk social sign-in in web apps.
|
|
|
12
12
|
- [Register a DingTalk Developer Account](#register-a-dingtalk-developer-account)
|
|
13
13
|
- [Create an Application](#create-an-application)
|
|
14
14
|
- [Configure Permissions](#configure-permissions)
|
|
15
|
+
- [Release Application](#release-application)
|
|
15
16
|
- [Configure Your Connector](#configure-your-connector)
|
|
16
17
|
- [Config Types](#config-types)
|
|
17
18
|
- [Test DingTalk Connector](#test-dingtalk-connector)
|
|
@@ -22,6 +23,7 @@ The official Logto connector for DingTalk social sign-in in web apps.
|
|
|
22
23
|
- [注册钉钉开发者账号](#注册钉钉开发者账号)
|
|
23
24
|
- [创建应用](#创建应用)
|
|
24
25
|
- [配置权限](#配置权限)
|
|
26
|
+
- [应用发布](#应用发布)
|
|
25
27
|
- [配置你的连接器](#配置你的连接器)
|
|
26
28
|
- [配置类型](#配置类型)
|
|
27
29
|
- [测试钉钉连接器](#测试钉钉连接器)
|
|
@@ -34,7 +36,6 @@ The DingTalk web connector is designed for desktop web applications. It uses the
|
|
|
34
36
|
## Create a web app in the DingTalk Open Platform
|
|
35
37
|
|
|
36
38
|
> 💡 **Tip**
|
|
37
|
-
>
|
|
38
39
|
> You can skip some sections if you have already finished.
|
|
39
40
|
|
|
40
41
|
### Register a DingTalk developer account
|
|
@@ -43,19 +44,21 @@ If you do not have a DingTalk developer account, please register at the [DingTal
|
|
|
43
44
|
|
|
44
45
|
### Create an application
|
|
45
46
|
|
|
46
|
-
1. In the
|
|
47
|
-
2.
|
|
48
|
-
3. In the left navigation bar, select "Development Configuration"
|
|
49
|
-
4. In the left navigation bar, select "Basic Information"
|
|
50
|
-
5. In the left navigation bar, select "Application Release" -> "Version Management and Release", create and release the first version to activate the "Client ID" and "Client Secret"
|
|
51
|
-
|
|
52
|
-
> ℹ️ **Note**
|
|
53
|
-
> If the application does not release a version, the obtained "Client ID" and "Client Secret" cannot be used, or requests will fail.
|
|
47
|
+
1. In the DingTalk Open Platform "[Application Development](https://open-dev.dingtalk.com/fe/app)" > "Internal Enterprise Application" > "DingTalk Application", click "Create Application"
|
|
48
|
+
2. Fill in the **application name** and **description**, and click "Save"
|
|
49
|
+
3. In the left navigation bar, select "Development Configuration" > "Security Settings", find and configure the "Redirect URL" `${your_logto_origin}/callback/${connector_id}`. You can find the `connector_id` on the connector details page after adding the respective connector in the management console
|
|
50
|
+
4. In the left navigation bar, select "Basic Information" > "Credentials and Basic Information" to get the `Client ID` and `Client Secret`
|
|
54
51
|
|
|
55
52
|
### Configure permissions
|
|
56
53
|
|
|
57
|
-
|
|
58
|
-
|
|
54
|
+
In "Development Configuration" > "Permission Management", select `Contact.User.Read` and `Contact.User.mobile` permissions and authorize them
|
|
55
|
+
|
|
56
|
+
### Release Application
|
|
57
|
+
|
|
58
|
+
In the left navigation bar, select "Application Release" > "Version Management and Release", create and release the first version to activate the `Client ID` and `Client Secret`
|
|
59
|
+
|
|
60
|
+
> ℹ️ **Note**
|
|
61
|
+
> If the application does not release a version, the obtained "Client ID" and "Client Secret" cannot be used, or requests will fail.
|
|
59
62
|
|
|
60
63
|
## Configure your connector
|
|
61
64
|
|
|
@@ -73,7 +76,7 @@ Fill out the `clientId` and `clientSecret` field with _Client ID(formerly AppKey
|
|
|
73
76
|
|
|
74
77
|
## Test DingTalk connector
|
|
75
78
|
|
|
76
|
-
That's it. The DingTalk connector should be available now. Don't forget to [Enable connector in sign-in experience](https://docs.logto.io/docs/
|
|
79
|
+
That's it. The DingTalk connector should be available now. Don't forget to [Enable connector in sign-in experience](https://docs.logto.io/docs/recipes/configure-connectors/social-connector/enable-social-sign-in/).
|
|
77
80
|
|
|
78
81
|
Once DingTalk web connector is enabled, you can sign in to your app again to see if it works.
|
|
79
82
|
|
|
@@ -93,7 +96,6 @@ If you have any questions or need further assistance, please visit the [DingTalk
|
|
|
93
96
|
## 在钉钉开放平台新建一个应用
|
|
94
97
|
|
|
95
98
|
> 💡 **Tip**
|
|
96
|
-
>
|
|
97
99
|
> 你可以跳过已经完成的部分。
|
|
98
100
|
|
|
99
101
|
### 注册钉钉开发者账号
|
|
@@ -102,25 +104,27 @@ If you have any questions or need further assistance, please visit the [DingTalk
|
|
|
102
104
|
|
|
103
105
|
### 创建应用
|
|
104
106
|
|
|
105
|
-
1. 在 [
|
|
106
|
-
2.
|
|
107
|
-
3.
|
|
108
|
-
4.
|
|
109
|
-
5. 在左侧导航栏选择「应用发布」->「版本管理与发布」,创建并发布第一个版本,以使「Client ID」、「Client Secret」生效
|
|
110
|
-
|
|
111
|
-
> ℹ️ **Note**
|
|
112
|
-
> 应用不发布版本,所获取的「Client ID」、「Client Secret」 均无法使用,或请求错误。
|
|
107
|
+
1. 在 钉钉开放平台「[应用开发](https://open-dev.dingtalk.com/fe/app)」>「企业内部应用」>「钉钉应用」中,点击「创建应用」
|
|
108
|
+
2. 填写**应用名称**和**应用描述**,点击「保存」
|
|
109
|
+
3. 在左侧导航栏选择「开发配置」>「安全设置」,找到并配置「重定向 URL」 `${your_logto_origin}/callback/${connector_id}`。其中 `connector_id` 在管理控制台添加了相应的连接器之后,可以在连接器的详情页中找到
|
|
110
|
+
4. 在左侧导航栏选择「基础信息」>「凭证与基础信息」中可以获取「Client ID」、「Client Secret」
|
|
113
111
|
|
|
114
112
|
### 配置权限
|
|
115
113
|
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
在「开发配置」>「权限管理」中,选择`通讯录个人信息读权限`和`个人手机号信息`权限并进行授权
|
|
115
|
+
|
|
116
|
+
### 应用发布
|
|
117
|
+
|
|
118
|
+
在左侧导航栏选择「应用发布」>「版本管理与发布」,点击「创建新版本」发布第一个版本,以使「Client ID」、「Client Secret」生效
|
|
119
|
+
|
|
120
|
+
> ℹ️ **Note**
|
|
121
|
+
> 应用不发布版本,所获取的「Client ID」、「Client Secret」 均无法使用,或请求错误。
|
|
118
122
|
|
|
119
123
|
## 配置你的连接器
|
|
120
124
|
|
|
121
|
-
在 clientId 和 clientSecret 字段中填入你在上一个部分中提到的 OAuth 应用详情页面获取的
|
|
125
|
+
在 `clientId` 和 `clientSecret` 字段中填入你在上一个部分中提到的 OAuth 应用详情页面获取的 _Client ID_(原 AppKey 和 SuiteKey)和 _Client Secret_(原 AppKey 和 SuiteKey)。
|
|
122
126
|
|
|
123
|
-
scope
|
|
127
|
+
`scope` 目前支持两种值:`openid` 和 `openid corpid`。`openid` 授权后可以获取用户的 `userid`,而 `openid corpid` 授权后可以获取用户的 `id` 和登录过程中用户选择的组织 `id`。这些值应以空格分隔。注意:需要进行 URL 编码。
|
|
124
128
|
|
|
125
129
|
### 配置类型
|
|
126
130
|
|
|
@@ -132,7 +136,7 @@ scope 目前支持两种值:openid 和 openid corpid。openid 授权后可以
|
|
|
132
136
|
|
|
133
137
|
## 测试钉钉连接器
|
|
134
138
|
|
|
135
|
-
大功告成。别忘了 [在登录体验中启用本连接器](https://docs.logto.io/docs/
|
|
139
|
+
大功告成。别忘了 [在登录体验中启用本连接器](https://docs.logto.io/docs/recipes/configure-connectors/social-connector/enable-social-sign-in/)。
|
|
136
140
|
|
|
137
141
|
在钉钉web连接器启用后,你可以构建并运行你的应用看看是否生效。
|
|
138
142
|
|
package/lib/index.js
CHANGED
|
@@ -1,177 +1,184 @@
|
|
|
1
|
-
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { got, HTTPError } from "got";
|
|
3
|
+
import {
|
|
4
|
+
ConnectorError,
|
|
5
|
+
ConnectorErrorCodes,
|
|
6
|
+
validateConfig,
|
|
7
|
+
ConnectorType,
|
|
8
|
+
parseJson
|
|
9
|
+
} from "@logto/connector-kit";
|
|
4
10
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
11
|
+
// src/constant.ts
|
|
12
|
+
import { ConnectorConfigFormItemType, ConnectorPlatform } from "@logto/connector-kit";
|
|
13
|
+
var authorizationEndpoint = "https://login.dingtalk.com/oauth2/auth";
|
|
14
|
+
var accessTokenEndpoint = "https://api.dingtalk.com/v1.0/oauth2/userAccessToken";
|
|
15
|
+
var userInfoEndpoint = "https://api.dingtalk.com/v1.0/contact/users/me";
|
|
16
|
+
var scope = "openid";
|
|
17
|
+
var defaultMetadata = {
|
|
18
|
+
id: "dingtalk-web",
|
|
19
|
+
target: "dingtalk",
|
|
20
|
+
platform: ConnectorPlatform.Web,
|
|
21
|
+
name: {
|
|
22
|
+
en: "DingTalk",
|
|
23
|
+
"zh-CN": "\u9489\u9489",
|
|
24
|
+
"tr-TR": "DingTalk",
|
|
25
|
+
ko: "DingTalk"
|
|
26
|
+
},
|
|
27
|
+
logo: "./logo.svg",
|
|
28
|
+
logoDark: null,
|
|
29
|
+
description: {
|
|
30
|
+
en: "DingTalk is an enterprise-level intelligent mobile office platform launched by Alibaba Group.",
|
|
31
|
+
"zh-CN": "\u9489\u9489\u662F\u4E00\u4E2A\u7531\u963F\u91CC\u5DF4\u5DF4\u96C6\u56E2\u63A8\u51FA\u7684\u4F01\u4E1A\u7EA7\u667A\u80FD\u79FB\u52A8\u529E\u516C\u5E73\u53F0\u3002",
|
|
32
|
+
"tr-TR": "DingTalk, Alibaba Grubu taraf\u0131ndan piyasaya s\xFCr\xFClen kurumsal d\xFCzeyde ak\u0131ll\u0131 mobil ofis platformudur.",
|
|
33
|
+
ko: "\uB529\uD1A1\uC740 \uC54C\uB9AC\uBC14\uBC14 \uADF8\uB8F9\uC774 \uCD9C\uC2DC\uD55C \uAE30\uC5C5\uC6A9 \uC9C0\uB2A5\uD615 \uBAA8\uBC14\uC77C \uC624\uD53C\uC2A4 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4."
|
|
34
|
+
},
|
|
35
|
+
readme: "./README.md",
|
|
36
|
+
formItems: [
|
|
37
|
+
{
|
|
38
|
+
key: "clientId",
|
|
39
|
+
label: "Client ID",
|
|
40
|
+
required: true,
|
|
41
|
+
type: ConnectorConfigFormItemType.Text,
|
|
42
|
+
placeholder: "<client-id>"
|
|
22
43
|
},
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
ko: '딩톡은 알리바바 그룹이 출시한 기업용 지능형 모바일 오피스 플랫폼입니다.',
|
|
44
|
+
{
|
|
45
|
+
key: "clientSecret",
|
|
46
|
+
label: "Client Secret",
|
|
47
|
+
required: true,
|
|
48
|
+
type: ConnectorConfigFormItemType.Text,
|
|
49
|
+
placeholder: "<client-secret>"
|
|
30
50
|
},
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
{
|
|
41
|
-
key: 'clientSecret',
|
|
42
|
-
label: 'Client Secret',
|
|
43
|
-
required: true,
|
|
44
|
-
type: ConnectorConfigFormItemType.Text,
|
|
45
|
-
placeholder: '<client-secret>',
|
|
46
|
-
},
|
|
47
|
-
{
|
|
48
|
-
key: 'scope',
|
|
49
|
-
type: ConnectorConfigFormItemType.Text,
|
|
50
|
-
label: 'Scope',
|
|
51
|
-
required: false,
|
|
52
|
-
placeholder: '<scope>',
|
|
53
|
-
description: "The `scope` determines permissions granted by the user's authorization. If you are not sure what to enter, do not worry, just leave it blank.",
|
|
54
|
-
},
|
|
55
|
-
],
|
|
51
|
+
{
|
|
52
|
+
key: "scope",
|
|
53
|
+
type: ConnectorConfigFormItemType.Text,
|
|
54
|
+
label: "Scope",
|
|
55
|
+
required: false,
|
|
56
|
+
placeholder: "<scope>",
|
|
57
|
+
description: "The `scope` determines permissions granted by the user's authorization. If you are not sure what to enter, do not worry, just leave it blank."
|
|
58
|
+
}
|
|
59
|
+
]
|
|
56
60
|
};
|
|
57
|
-
|
|
61
|
+
var defaultTimeout = 5e3;
|
|
58
62
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
+
// src/types.ts
|
|
64
|
+
import { z } from "zod";
|
|
65
|
+
var dingtalkConfigGuard = z.object({
|
|
66
|
+
clientId: z.string(),
|
|
67
|
+
clientSecret: z.string(),
|
|
68
|
+
scope: z.string().optional()
|
|
63
69
|
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
70
|
+
var accessTokenResponseGuard = z.object({
|
|
71
|
+
accessToken: z.string(),
|
|
72
|
+
refreshToken: z.string().optional(),
|
|
73
|
+
expireIn: z.number().optional(),
|
|
74
|
+
// In seconds
|
|
75
|
+
corpId: z.string().optional()
|
|
69
76
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
var userInfoResponseGuard = z.object({
|
|
78
|
+
nick: z.string().optional(),
|
|
79
|
+
avatarUrl: z.string().optional(),
|
|
80
|
+
mobile: z.string().optional(),
|
|
81
|
+
openId: z.string().optional(),
|
|
82
|
+
// DingTalk no longer recommends using OpenId for integration. Instead, use unionId.
|
|
83
|
+
unionId: z.string(),
|
|
84
|
+
email: z.string().optional(),
|
|
85
|
+
stateCode: z.string().optional()
|
|
79
86
|
});
|
|
80
|
-
|
|
87
|
+
var authResponseGuard = z.object({ code: z.string() });
|
|
81
88
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
// src/index.ts
|
|
90
|
+
var getAuthorizationUri = (getConfig) => async ({ state, redirectUri }) => {
|
|
91
|
+
const config = await getConfig(defaultMetadata.id);
|
|
92
|
+
validateConfig(config, dingtalkConfigGuard);
|
|
93
|
+
const { clientId, scope: scope2 } = config;
|
|
94
|
+
const queryParameters = new URLSearchParams({
|
|
95
|
+
client_id: clientId,
|
|
96
|
+
redirect_uri: encodeURI(redirectUri),
|
|
97
|
+
// The variable `redirectUri` should match {clientId, clientSecret}
|
|
98
|
+
response_type: "code",
|
|
99
|
+
scope: scope2 ?? scope,
|
|
100
|
+
state,
|
|
101
|
+
prompt: "consent"
|
|
102
|
+
});
|
|
103
|
+
return `${authorizationEndpoint}?${queryParameters.toString()}`;
|
|
104
|
+
};
|
|
105
|
+
var getAccessToken = async (code, config) => {
|
|
106
|
+
const { clientId, clientSecret } = config;
|
|
107
|
+
const httpResponse = await got.post(accessTokenEndpoint, {
|
|
108
|
+
json: {
|
|
109
|
+
clientId,
|
|
110
|
+
clientSecret,
|
|
111
|
+
code,
|
|
112
|
+
grantType: "authorization_code"
|
|
113
|
+
},
|
|
114
|
+
timeout: { request: defaultTimeout }
|
|
115
|
+
});
|
|
116
|
+
const result = accessTokenResponseGuard.safeParse(parseJson(httpResponse.body));
|
|
117
|
+
if (!result.success) {
|
|
118
|
+
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);
|
|
119
|
+
}
|
|
120
|
+
const { accessToken } = result.data;
|
|
121
|
+
return { accessToken };
|
|
99
122
|
};
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
123
|
+
var getUserInfo = (getConfig) => async (data) => {
|
|
124
|
+
const { code } = await authorizationCallbackHandler(data);
|
|
125
|
+
const config = await getConfig(defaultMetadata.id);
|
|
126
|
+
validateConfig(config, dingtalkConfigGuard);
|
|
127
|
+
const { accessToken } = await getAccessToken(code, config);
|
|
128
|
+
try {
|
|
129
|
+
const httpResponse = await got.get(userInfoEndpoint, {
|
|
130
|
+
headers: {
|
|
131
|
+
"x-acs-dingtalk-access-token": accessToken
|
|
132
|
+
},
|
|
133
|
+
timeout: { request: defaultTimeout }
|
|
110
134
|
});
|
|
111
|
-
const
|
|
135
|
+
const rawData = parseJson(httpResponse.body);
|
|
136
|
+
const result = userInfoResponseGuard.safeParse(rawData);
|
|
112
137
|
if (!result.success) {
|
|
113
|
-
|
|
138
|
+
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);
|
|
114
139
|
}
|
|
115
|
-
const {
|
|
116
|
-
return {
|
|
140
|
+
const { nick: name, avatarUrl: avatar, unionId: id, email, mobile, stateCode } = result.data;
|
|
141
|
+
return {
|
|
142
|
+
id,
|
|
143
|
+
avatar,
|
|
144
|
+
phone: stateCode && mobile ? `${stateCode}${mobile}` : void 0,
|
|
145
|
+
email,
|
|
146
|
+
name,
|
|
147
|
+
rawData
|
|
148
|
+
};
|
|
149
|
+
} catch (error) {
|
|
150
|
+
return getUserInfoErrorHandler(error);
|
|
151
|
+
}
|
|
117
152
|
};
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
try {
|
|
124
|
-
const httpResponse = await got.get(userInfoEndpoint, {
|
|
125
|
-
headers: {
|
|
126
|
-
'x-acs-dingtalk-access-token': accessToken,
|
|
127
|
-
},
|
|
128
|
-
timeout: { request: defaultTimeout },
|
|
129
|
-
});
|
|
130
|
-
const rawData = parseJson(httpResponse.body);
|
|
131
|
-
const result = userInfoResponseGuard.safeParse(rawData);
|
|
132
|
-
if (!result.success) {
|
|
133
|
-
throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);
|
|
134
|
-
}
|
|
135
|
-
const { nick: name, avatarUrl: avatar, unionId: id, email, mobile, stateCode } = result.data;
|
|
136
|
-
return {
|
|
137
|
-
id,
|
|
138
|
-
avatar,
|
|
139
|
-
phone: stateCode && mobile ? `${stateCode}${mobile}` : undefined,
|
|
140
|
-
email,
|
|
141
|
-
name,
|
|
142
|
-
rawData,
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
catch (error) {
|
|
146
|
-
return getUserInfoErrorHandler(error);
|
|
153
|
+
var getUserInfoErrorHandler = (error) => {
|
|
154
|
+
if (error instanceof HTTPError) {
|
|
155
|
+
const { statusCode, body: rawBody } = error.response;
|
|
156
|
+
if (statusCode === 400) {
|
|
157
|
+
throw new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid);
|
|
147
158
|
}
|
|
159
|
+
throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(rawBody));
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
148
162
|
};
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(rawBody));
|
|
157
|
-
}
|
|
158
|
-
throw error;
|
|
163
|
+
var authorizationCallbackHandler = async (parameterObject) => {
|
|
164
|
+
const result = authResponseGuard.safeParse(parameterObject);
|
|
165
|
+
if (!result.success) {
|
|
166
|
+
throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(parameterObject));
|
|
167
|
+
}
|
|
168
|
+
return result.data;
|
|
159
169
|
};
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
var createDingtalkConnector = async ({ getConfig }) => {
|
|
171
|
+
return {
|
|
172
|
+
metadata: defaultMetadata,
|
|
173
|
+
type: ConnectorType.Social,
|
|
174
|
+
configGuard: dingtalkConfigGuard,
|
|
175
|
+
getAuthorizationUri: getAuthorizationUri(getConfig),
|
|
176
|
+
getUserInfo: getUserInfo(getConfig)
|
|
177
|
+
};
|
|
166
178
|
};
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
configGuard: dingtalkConfigGuard,
|
|
172
|
-
getAuthorizationUri: getAuthorizationUri(getConfig),
|
|
173
|
-
getUserInfo: getUserInfo(getConfig),
|
|
174
|
-
};
|
|
179
|
+
var src_default = createDingtalkConnector;
|
|
180
|
+
export {
|
|
181
|
+
src_default as default,
|
|
182
|
+
getAccessToken
|
|
175
183
|
};
|
|
176
|
-
|
|
177
|
-
export { createDingtalkConnector as default, getAccessToken };
|
|
184
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constant.ts","../src/types.ts"],"sourcesContent":["/**\n * DingTalk OAuth2 Connector\n * https://open.dingtalk.com/document/orgapp/obtain-identity-credentials#title-4up-u8w-5ug\n */\n\nimport { got, HTTPError } from 'got';\n\nimport type {\n GetAuthorizationUri,\n GetUserInfo,\n GetConnectorConfig,\n CreateConnector,\n SocialConnector,\n} from '@logto/connector-kit';\nimport {\n ConnectorError,\n ConnectorErrorCodes,\n validateConfig,\n ConnectorType,\n parseJson,\n} from '@logto/connector-kit';\n\nimport {\n authorizationEndpoint,\n accessTokenEndpoint,\n userInfoEndpoint,\n scope as defaultScope,\n defaultMetadata,\n defaultTimeout,\n} from './constant.js';\nimport type { DingtalkConfig } from './types.js';\nimport {\n dingtalkConfigGuard,\n accessTokenResponseGuard,\n userInfoResponseGuard,\n authResponseGuard,\n} from './types.js';\n\nconst getAuthorizationUri =\n (getConfig: GetConnectorConfig): GetAuthorizationUri =>\n async ({ state, redirectUri }) => {\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, dingtalkConfigGuard);\n\n const { clientId, scope } = config;\n\n const queryParameters = new URLSearchParams({\n client_id: clientId,\n redirect_uri: encodeURI(redirectUri), // The variable `redirectUri` should match {clientId, clientSecret}\n response_type: 'code',\n scope: scope ?? defaultScope,\n state,\n prompt: 'consent',\n });\n\n return `${authorizationEndpoint}?${queryParameters.toString()}`;\n };\n\nexport const getAccessToken = async (\n code: string,\n config: DingtalkConfig\n): Promise<{ accessToken: string }> => {\n const { clientId, clientSecret } = config;\n\n const httpResponse = await got.post(accessTokenEndpoint, {\n json: {\n clientId,\n clientSecret,\n code,\n grantType: 'authorization_code',\n },\n timeout: { request: defaultTimeout },\n });\n\n const result = accessTokenResponseGuard.safeParse(parseJson(httpResponse.body));\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);\n }\n\n const { accessToken } = result.data;\n\n return { accessToken };\n};\n\nconst getUserInfo =\n (getConfig: GetConnectorConfig): GetUserInfo =>\n async (data) => {\n const { code } = await authorizationCallbackHandler(data);\n const config = await getConfig(defaultMetadata.id);\n validateConfig(config, dingtalkConfigGuard);\n const { accessToken } = await getAccessToken(code, config);\n\n try {\n const httpResponse = await got.get(userInfoEndpoint, {\n headers: {\n 'x-acs-dingtalk-access-token': accessToken,\n },\n timeout: { request: defaultTimeout },\n });\n const rawData = parseJson(httpResponse.body);\n const result = userInfoResponseGuard.safeParse(rawData);\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.InvalidResponse, result.error);\n }\n\n const { nick: name, avatarUrl: avatar, unionId: id, email, mobile, stateCode } = result.data;\n return {\n id,\n avatar,\n phone: stateCode && mobile ? `${stateCode}${mobile}` : undefined,\n email,\n name,\n rawData,\n };\n } catch (error: unknown) {\n return getUserInfoErrorHandler(error);\n }\n };\n\nconst getUserInfoErrorHandler = (error: unknown) => {\n // https://open.dingtalk.com/document/personalapp/error-code-2#title-m5s-krt-vds\n if (error instanceof HTTPError) {\n const { statusCode, body: rawBody } = error.response;\n\n if (statusCode === 400) {\n throw new ConnectorError(ConnectorErrorCodes.SocialAccessTokenInvalid);\n }\n\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(rawBody));\n }\n\n throw error;\n};\n\nconst authorizationCallbackHandler = async (parameterObject: unknown) => {\n const result = authResponseGuard.safeParse(parameterObject);\n\n if (!result.success) {\n throw new ConnectorError(ConnectorErrorCodes.General, JSON.stringify(parameterObject));\n }\n\n return result.data;\n};\n\nconst createDingtalkConnector: CreateConnector<SocialConnector> = async ({ getConfig }) => {\n return {\n metadata: defaultMetadata,\n type: ConnectorType.Social,\n configGuard: dingtalkConfigGuard,\n getAuthorizationUri: getAuthorizationUri(getConfig),\n getUserInfo: getUserInfo(getConfig),\n };\n};\n\nexport default createDingtalkConnector;\n","import type { ConnectorMetadata } from '@logto/connector-kit';\nimport { ConnectorConfigFormItemType, ConnectorPlatform } from '@logto/connector-kit';\n\n// https://open.dingtalk.com/document/orgapp-server/use-dingtalk-account-to-log-on-to-third-party-websites-1\nexport const authorizationEndpoint = 'https://login.dingtalk.com/oauth2/auth';\n// https://open.dingtalk.com/document/isvapp/obtain-user-token\nexport const accessTokenEndpoint = 'https://api.dingtalk.com/v1.0/oauth2/userAccessToken';\n// https://open.dingtalk.com/document/isvapp/dingtalk-retrieve-user-information\n// To obtain the current authorized person's information, the unionId parameter can be set to \"me\".\nexport const userInfoEndpoint = 'https://api.dingtalk.com/v1.0/contact/users/me';\nexport const scope = 'openid';\n\nexport const defaultMetadata: ConnectorMetadata = {\n id: 'dingtalk-web',\n target: 'dingtalk',\n platform: ConnectorPlatform.Web,\n name: {\n en: 'DingTalk',\n 'zh-CN': '钉钉',\n 'tr-TR': 'DingTalk',\n ko: 'DingTalk',\n },\n logo: './logo.svg',\n logoDark: null,\n description: {\n en: 'DingTalk is an enterprise-level intelligent mobile office platform launched by Alibaba Group.',\n 'zh-CN': '钉钉是一个由阿里巴巴集团推出的企业级智能移动办公平台。',\n 'tr-TR':\n 'DingTalk, Alibaba Grubu tarafından piyasaya sürülen kurumsal düzeyde akıllı mobil ofis platformudur.',\n ko: '딩톡은 알리바바 그룹이 출시한 기업용 지능형 모바일 오피스 플랫폼입니다.',\n },\n readme: './README.md',\n formItems: [\n {\n key: 'clientId',\n label: 'Client ID',\n required: true,\n type: ConnectorConfigFormItemType.Text,\n placeholder: '<client-id>',\n },\n {\n key: 'clientSecret',\n label: 'Client Secret',\n required: true,\n type: ConnectorConfigFormItemType.Text,\n placeholder: '<client-secret>',\n },\n {\n key: 'scope',\n type: ConnectorConfigFormItemType.Text,\n label: 'Scope',\n required: false,\n placeholder: '<scope>',\n description:\n \"The `scope` determines permissions granted by the user's authorization. If you are not sure what to enter, do not worry, just leave it blank.\",\n },\n ],\n};\n\nexport const defaultTimeout = 5000;\n","import { z } from 'zod';\n\nexport const dingtalkConfigGuard = z.object({\n clientId: z.string(),\n clientSecret: z.string(),\n scope: z.string().optional(),\n});\n\nexport type DingtalkConfig = z.infer<typeof dingtalkConfigGuard>;\n\nexport const accessTokenResponseGuard = z.object({\n accessToken: z.string(),\n refreshToken: z.string().optional(),\n expireIn: z.number().optional(), // In seconds\n corpId: z.string().optional(),\n});\n\n// https://open.dingtalk.com/document/isvapp/dingtalk-retrieve-user-information\nexport const userInfoResponseGuard = z.object({\n nick: z.string().optional(),\n avatarUrl: z.string().optional(),\n mobile: z.string().optional(),\n openId: z.string().optional(), // DingTalk no longer recommends using OpenId for integration. Instead, use unionId.\n unionId: z.string(),\n email: z.string().optional(),\n stateCode: z.string().optional(),\n});\n\nexport type UserInfoResponse = z.infer<typeof userInfoResponseGuard>;\n\nexport type UserInfoResponseMessageParser = (userInfo: Partial<UserInfoResponse>) => void;\n\nexport const authResponseGuard = z.object({ code: z.string() });\n"],"mappings":"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","names":["scope"]}
|
package/package.json
CHANGED
|
@@ -1,36 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@logto/connector-dingtalk-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Dingtalk web connector implementation.",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@logto/connector-kit": "^
|
|
6
|
+
"@logto/connector-kit": "^4.0.0",
|
|
7
7
|
"@silverhand/essentials": "^2.9.1",
|
|
8
8
|
"dayjs": "^1.10.5",
|
|
9
9
|
"got": "^14.0.0",
|
|
10
10
|
"iconv-lite": "^0.6.3",
|
|
11
|
-
"snakecase-keys": "^8.0.
|
|
12
|
-
"zod": "^3.
|
|
11
|
+
"snakecase-keys": "^8.0.1",
|
|
12
|
+
"zod": "^3.23.8"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@rollup/plugin-commonjs": "^25.0.7",
|
|
16
|
-
"@rollup/plugin-json": "^6.1.0",
|
|
17
|
-
"@rollup/plugin-node-resolve": "^15.2.3",
|
|
18
|
-
"@rollup/plugin-typescript": "^11.1.6",
|
|
19
15
|
"@shopify/jest-koa-mocks": "^5.0.0",
|
|
20
16
|
"@silverhand/eslint-config": "6.0.1",
|
|
21
17
|
"@silverhand/ts-config": "6.0.0",
|
|
22
18
|
"@types/node": "^20.11.20",
|
|
23
19
|
"@types/supertest": "^6.0.2",
|
|
24
|
-
"@vitest/coverage-v8": "^
|
|
20
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
25
21
|
"eslint": "^8.56.0",
|
|
26
22
|
"lint-staged": "^15.0.2",
|
|
27
23
|
"nock": "^13.3.1",
|
|
28
24
|
"prettier": "^3.0.0",
|
|
29
|
-
"rollup": "^4.12.0",
|
|
30
|
-
"rollup-plugin-output-size": "^1.3.0",
|
|
31
25
|
"supertest": "^7.0.0",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
26
|
+
"tsup": "^8.1.0",
|
|
27
|
+
"typescript": "^5.5.3",
|
|
28
|
+
"vitest": "^2.0.0"
|
|
34
29
|
},
|
|
35
30
|
"main": "./lib/index.js",
|
|
36
31
|
"module": "./lib/index.js",
|
|
@@ -64,9 +59,9 @@
|
|
|
64
59
|
},
|
|
65
60
|
"scripts": {
|
|
66
61
|
"precommit": "lint-staged",
|
|
67
|
-
"
|
|
68
|
-
"build": "
|
|
69
|
-
"dev": "
|
|
62
|
+
"check": "tsc --noEmit",
|
|
63
|
+
"build": "tsup",
|
|
64
|
+
"dev": "tsup --watch",
|
|
70
65
|
"lint": "eslint --ext .ts src",
|
|
71
66
|
"lint:report": "pnpm lint --format json --output-file report.json",
|
|
72
67
|
"test": "vitest src",
|
package/lib/constant.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { ConnectorMetadata } from '@logto/connector-kit';
|
|
2
|
-
export declare const authorizationEndpoint = "https://login.dingtalk.com/oauth2/auth";
|
|
3
|
-
export declare const accessTokenEndpoint = "https://api.dingtalk.com/v1.0/oauth2/userAccessToken";
|
|
4
|
-
export declare const userInfoEndpoint = "https://api.dingtalk.com/v1.0/contact/users/me";
|
|
5
|
-
export declare const scope = "openid";
|
|
6
|
-
export declare const defaultMetadata: ConnectorMetadata;
|
|
7
|
-
export declare const defaultTimeout = 5000;
|
package/lib/index.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* DingTalk OAuth2 Connector
|
|
3
|
-
* https://open.dingtalk.com/document/orgapp/obtain-identity-credentials#title-4up-u8w-5ug
|
|
4
|
-
*/
|
|
5
|
-
import type { CreateConnector, SocialConnector } from '@logto/connector-kit';
|
|
6
|
-
import type { DingtalkConfig } from './types.js';
|
|
7
|
-
export declare const getAccessToken: (code: string, config: DingtalkConfig) => Promise<{
|
|
8
|
-
accessToken: string;
|
|
9
|
-
}>;
|
|
10
|
-
declare const createDingtalkConnector: CreateConnector<SocialConnector>;
|
|
11
|
-
export default createDingtalkConnector;
|
package/lib/mock.d.ts
DELETED
package/lib/types.d.ts
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { z } from 'zod';
|
|
2
|
-
export declare const dingtalkConfigGuard: z.ZodObject<{
|
|
3
|
-
clientId: z.ZodString;
|
|
4
|
-
clientSecret: z.ZodString;
|
|
5
|
-
scope: z.ZodOptional<z.ZodString>;
|
|
6
|
-
}, "strip", z.ZodTypeAny, {
|
|
7
|
-
clientId: string;
|
|
8
|
-
clientSecret: string;
|
|
9
|
-
scope?: string | undefined;
|
|
10
|
-
}, {
|
|
11
|
-
clientId: string;
|
|
12
|
-
clientSecret: string;
|
|
13
|
-
scope?: string | undefined;
|
|
14
|
-
}>;
|
|
15
|
-
export type DingtalkConfig = z.infer<typeof dingtalkConfigGuard>;
|
|
16
|
-
export declare const accessTokenResponseGuard: z.ZodObject<{
|
|
17
|
-
accessToken: z.ZodString;
|
|
18
|
-
refreshToken: z.ZodOptional<z.ZodString>;
|
|
19
|
-
expireIn: z.ZodOptional<z.ZodNumber>;
|
|
20
|
-
corpId: z.ZodOptional<z.ZodString>;
|
|
21
|
-
}, "strip", z.ZodTypeAny, {
|
|
22
|
-
accessToken: string;
|
|
23
|
-
refreshToken?: string | undefined;
|
|
24
|
-
expireIn?: number | undefined;
|
|
25
|
-
corpId?: string | undefined;
|
|
26
|
-
}, {
|
|
27
|
-
accessToken: string;
|
|
28
|
-
refreshToken?: string | undefined;
|
|
29
|
-
expireIn?: number | undefined;
|
|
30
|
-
corpId?: string | undefined;
|
|
31
|
-
}>;
|
|
32
|
-
export declare const userInfoResponseGuard: z.ZodObject<{
|
|
33
|
-
nick: z.ZodOptional<z.ZodString>;
|
|
34
|
-
avatarUrl: z.ZodOptional<z.ZodString>;
|
|
35
|
-
mobile: z.ZodOptional<z.ZodString>;
|
|
36
|
-
openId: z.ZodOptional<z.ZodString>;
|
|
37
|
-
unionId: z.ZodString;
|
|
38
|
-
email: z.ZodOptional<z.ZodString>;
|
|
39
|
-
stateCode: z.ZodOptional<z.ZodString>;
|
|
40
|
-
}, "strip", z.ZodTypeAny, {
|
|
41
|
-
unionId: string;
|
|
42
|
-
nick?: string | undefined;
|
|
43
|
-
avatarUrl?: string | undefined;
|
|
44
|
-
mobile?: string | undefined;
|
|
45
|
-
openId?: string | undefined;
|
|
46
|
-
email?: string | undefined;
|
|
47
|
-
stateCode?: string | undefined;
|
|
48
|
-
}, {
|
|
49
|
-
unionId: string;
|
|
50
|
-
nick?: string | undefined;
|
|
51
|
-
avatarUrl?: string | undefined;
|
|
52
|
-
mobile?: string | undefined;
|
|
53
|
-
openId?: string | undefined;
|
|
54
|
-
email?: string | undefined;
|
|
55
|
-
stateCode?: string | undefined;
|
|
56
|
-
}>;
|
|
57
|
-
export type UserInfoResponse = z.infer<typeof userInfoResponseGuard>;
|
|
58
|
-
export type UserInfoResponseMessageParser = (userInfo: Partial<UserInfoResponse>) => void;
|
|
59
|
-
export declare const authResponseGuard: z.ZodObject<{
|
|
60
|
-
code: z.ZodString;
|
|
61
|
-
}, "strip", z.ZodTypeAny, {
|
|
62
|
-
code: string;
|
|
63
|
-
}, {
|
|
64
|
-
code: string;
|
|
65
|
-
}>;
|