# SDK for Node.js

Node SDK 用于 Node 环境下，可以用于管理用户池中所有用户，拥有全部操作权限。

**请注意** [**SDK for JavaScript**](/authing/sdk/sdk-for-node.md) **与** [**SDK for Node.js**](/authing/sdk/sdk-for-node.md) **接口存在差异，请根据需求选择 SDK。**

Github：<https://github.com/Authing/authing.js>。

## 安装

**NPM**

当构建大规模应用时，我们推荐使用 `npm` 进行安装。

```bash
# latest stable
$ npm install authing-js-sdk --save
```

## 初始化

先从 [Authing 控制台](https://authing.cn/dashboard) 中 [获取用户池 ID 和 Secret](https://learn.authing.cn/authing/others/faq#ru-he-huo-qu-client-id-he-client-secret)。

初始化代码：

```javascript
const Authing = require('authing-js-sdk');
const auth = new Authing({
	userPoolId: 'your_userpool_id',
	secret: 'your_userpool_secret'
});
// 初始化之后可以直接使用相关代码
auth.register({...}).then((info) => {

});
auth.login({...}).then((info) => {

});
```

也可以通过用户池管理员的 token 初始化，获得此用户池管理员的权限，之后可以操作用户池中的所有用户，例如获取任意用户池中用户的信息。

* accessToken
  * 用户池管理员 token

**示例**

```javascript
const auth = new Authing({
	accessToken: 'userpool_manager_token',
});
// authing.user({id: '任意用户池中的用户 id'}).then(info => {})

```

#### 其他参数

* **preflight**
  * 是否开启网络状况预检，默认为 false。此参数适用于检查用户的网络是否屏蔽了 authing.cn 这个域名（某些企业的内网会屏蔽这个域名），检查成功不进行任何通知，检查失败后会调用传入的错误处理函数。**执行预检之后会导致 SDK 初始化速度变慢，请谨慎使用。**
* **cdnPreflight**
  * 是否开启 CDN 网络状况预检，默认为 false。此参数适用于检查用户的网络是否可以访问七牛云 CDN（某些开了代理的场景下无法访问），检查成功不进行任何通知，检查失败后会调用传入的错误处理函数。**执行 CDN 预检之后会导致 SDK 初始化速度变慢，请谨慎使用。**
* **timeout**
  * 超时时间，默认为 10000 毫秒（10 秒）。
* **passwordEncPublicKey**
  * PEM 格式密码加密公钥，默认为 Authing 官方的加密公钥。私有化部署用户需要传入自己的加密公钥。
* **onInitError，**`function(err) {}`
  * 错误处理函数，用于处理初始化失败错误、预检错误。

## 使用

Authing SDK 的所有 API 都支持 **Promise**。

```javascript
const Authing = require('authing-js-sdk');

const authing = new Authing({
	userPoolId: 'your_userpool_id',
	secret: 'your_userpool_secret'
});

authing.login({
	email: 'test@testmail.com',
	password: 'testpassword'
}).then(function(user) {
	console.log(user);	
}).catch(function(error) {
	console.log(error);	
});
```

如果你使用 `ES6+` 推荐用 `await` 处理异步，示例如下：

```javascript
const Authing = require('authing-js-sdk');

const main = async () => {

	let auth = new Authing({
		userPoolId: 'your_client_id',
		secret: 'your_userpool_secret'
	});

	let user;

	//使用async时需要使用 try...catch... 捕捉错误
	try {
		user = await auth.login({
			email: 'test@testmail.com',
			password: 'testpassword'
		});
	}catch(error) {
		console.log('登录失败:', error);
	}

	if(user) {
		console.log('login success');
	}else {
		console.log('login failed');
	}

}

main();
```

## 异常捕获

所有失败的操作，都需要使用 try catch 捕获异常。操作失败有两种情况：

* 网络请求出错，常见情况包括：传递参数不合法，这会被 GraphQL 过滤层直接拦截；网络无法连接。
* 业务逻辑出错，常见情况包括：密码不正确，删除某资源传递的 id 不存在等。

为了方便开发者快速定位出错原因，我们提供一个 formatError 函数：

```javascript
function formatError(error) {
  if (typeof error === 'string') return error;
  if (error.request) {
    // 网络请求错误
    if(error.response)
      return JSON.stringify(error.response.data);
    else
      return JSON.stringify(error.request);
  } else if (typeof error.message === 'object') {
    // 业务逻辑错误
    if (error.message.message) {
      return JSON.stringify(error.message.message);
    } else {
      return JSON.stringify(error.message);
    }
  } else {
    return error;
  }
}
```

示例如下：

```javascript
  try {
    const res = await authing.authz.deleteGroup("不存在的 groupId")
    console.log(res)
  } catch (error) {
    console.log(formatError(error))
  }
```

## 注册

{% hint style="info" %}
如果你希望用手机号注册用户，可以使用 loginByPhone （手机验证码登录）方法，该方法在用户不存在的时候会自动创建。
{% endhint %}

**Authing.register(options)**

* **参数:**
  * `{Object} options`
    * **email**
    * **password**
    * **unionid**，若不使用 email 和 password 则 unionid 必选
    * **oauth** 可选，oauth 信息的字符串，或者其他自定义的用户字段都可以以 JSON 字符串的形式存在这里
    * **username**，可选，用户名
    * **phone**，可选，手机号
    * **nickname**，可选，昵称
    * **company**，可选，公司名称
    * **photo**，可选，用户头像
    * **lastIP**，可选，用户登录的 IP 地址
    * **signedUp** `{JS Date Object}`，可选，注册时间
    * **lastLogin** `{JS Date Object}`，可选，上次登录时间
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
        secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.register({
        email: email,
        password: password
      }).catch((error) => { ... });;
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "test@test.com",
        "emailVerified": false,
        "username": "test@test.com",
        "nickname": "",
        "company": "",
        "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false,
        "group": {
          "_id": "59e374332023830871913ebd",
          "name": "default",
          "descriptions": "default",
          "createdAt": "Sun Oct 15 2017 22:44:03 GMT+0800 (CST)"
        }
    }
    ```

## 登录

**Authing.login(options)**

* **参数:**
  * `{Object} options`
    * **email**
    * **password**
    * **unionid，**&#x82E5;不使用 email 和 password 则 unioinid 必选
    * **verifyCode，**&#x53EF;选，频繁注册时会要求输入验证码，返回数据会包含
    * **MFACode，**&#x53EF;选，如果用户开启了 MFA 会要求输入 6 位动态口令，返回数据会出现 1635 错误代码
    * **lastIP，**&#x53EF;选，若连续出现验证码验证失败情况，请将客户端 IP 填入
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.login({
        email: email,
        password: password
      }).catch((error) => {
        /* 如果错误信息提示需要输入验证码，则登录参数应为
          { 
            email: email, 
            password: password, 
            verifyCode: verifyCode 
          } 
         /* 
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "86700229ww6ss@163.com",
        "emailVerified": false,
        "username": "86700229ww6ss@163.com",
        "nickname": "",
        "company": "",
        "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false,
        "group": {
          "_id": "59e374332023830871913ebd",
          "name": "default",
          "descriptions": "default",
          "createdAt": "Sun Oct 15 2017 22:44:03 GMT+0800 (CST)"
        }
     }
    ```

##

## 使用 ODIC 登录

### Authing.loginByOidc(option)

* **参数**:
  * `{object} options`
    * **client\_id 必填**  （必填）OIDC 应用 ID
    * **client\_secret** （必填）OIDC 应用 Secret
    * **email** （必填） 用户 Email
    * **password** （必填） 用户密码

```javascript
(async function() { const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  
  const response = await authing.loginByOidc({
    client_id: 'your userpoolId',
    client_secret: 'your client_serret',
    email: 'your email',
    password: 'your password ',
  }).catch((error) => { ... })
})();
```

## 刷新 OIDC Token

**Authing.refreshOidcToken(options)**

* **参数：**
  * `{Object} options`
    * **client\_id**   OIDC 应用 id
    * **client\_secret**    OIDC 应用 secret
    * **refresh\_token**   要刷新的 Token

```javascript
(async function() { const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  
  const response = await authing.refreshOidcToken({
    client_id: 'your OIDC client_id',
    client_secret: 'your OIDC secret',
    refresh_token: 'your Token '
  }).catch((error) => { ... })
})();
```

## AuthingToken 换 OIDC Token

需要先在[**控制台**](https://authing.cn/dashboard) > **第三方登录** > **OIDC 应用**，授权模式中勾选 authingToken。

**Authing.authingTokenToOidcToken(options)**

* **参数：**
  * `{Object} options`
    * **client\_id**，OIDC 应用 id
    * **client\_secret**，OIDC 应用 secret
    * **authingToken，**&#x41;uthing Token

```javascript
(async function() { const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  
  const response = await authing.authingTokenToOidcToken({
    client_id: 'your OIDC client_id',
    client_secret: 'your OIDC secret',
    authingToken: 'your Authing Token'
  }).catch((error) => { ... })
})();
```

返回数据：

* 请求成功

```
{
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJJQ015UV9yVFFESlZGYkJEclBDdml0ME9LczBSNWNRX3N1Vmt4alRmOUkifQ.eyJqdGkiOiJXWEl3TldJZ3ZCZ0tXN0lncnVzdXQiLCJzdWIiOiI1ZTg1YWRlZDljYzE4ZTRjYzY3ZTc4MGEiLCJpc3MiOiJodHRwczovL3Rlc3Q4OC5jZWxlYmVzLmxpdmUvb2F1dGgvb2lkYyIsImlhdCI6MTU4NTgxOTExOCwiZXhwIjoxNTg1ODIyNzE4LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIHBob25lIG9mZmxpbmVfYWNjZXNzIiwiYXVkIjoiNWU1ZmMzNGZmMTRiYjI1OTkyZWUyNzgxIn0.Tk4npueRIyJPVxrfiOVQgMKEbk4z_KOvOkOGNyVKyeMtSHEcvU8tMRhjBP_ZrISaT4XO-vu_O1tDUBFhCKMDXWnPMwNotbbcRwRdmzueoe1G0YyxHvcuNihAFyfT_99Skaq3TuG7EzeeFuuvkUejFKRmaODraQY1vQrJl_0WNX1f6NZVYNUcOTCslb_R6qNodFQvjfOJv73FyArETKRAKN5sdTtUWuwxf9QfNm5jwJ_iratqSb5GYU-hd6U-47JKzqv_NEEVrGcRSDrW4ICrulOVPduKOwUqwg7VjHqpvAk2cIt5UdgSh2aaj3KpBhRWm2Exp2AY62sP-oLU3qigBQ",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlJJQ015UV9yVFFESlZGYkJEclBDdml0ME9LczBSNWNRX3N1Vmt4alRmOUkifQ.eyJzdWIiOiI1ZTg1YWRlZDljYzE4ZTRjYzY3ZTc4MGEiLCJiaXJ0aGRhdGUiOiIiLCJmYW1pbHlfbmFtZSI6IiIsImdlbmRlciI6IiIsImdpdmVuX25hbWUiOiIiLCJsb2NhbGUiOiIiLCJtaWRkbGVfbmFtZSI6IiIsIm5hbWUiOiIiLCJuaWNrbmFtZSI6IiIsInBpY3R1cmUiOiJodHRwczovL3VzZXJjb250ZW50cy5hdXRoaW5nLmNuL2F1dGhpbmctYXZhdGFyLnBuZyIsInByZWZlcnJlZF91c2VybmFtZSI6IiIsInByb2ZpbGUiOiIiLCJ1cGRhdGVkX2F0IjoiIiwid2Vic2l0ZSI6IiIsInpvbmVpbmZvIjoiIiwidXNlcm5hbWUiOiJwNGdnMnVhcWRjZUB0ZXN0LmNvbSIsImNvbXBhbnkiOiIiLCJicm93c2VyIjoiIiwiZGV2aWNlIjoiIiwibG9naW5zX2NvdW50IjoxLCJyZWdpc3Rlcl9tZXRob2QiOiJkZWZhdWx0OnVzZXJuYW1lLXBhc3N3b3JkIiwiYmxvY2tlZCI6ZmFsc2UsImxhc3RfaXAiOiIxMjQuMjA0LjU2Ljk4IiwicmVnaXN0ZXJfaW5fdXNlcnBvb2wiOiI1ZTE5OTQyMTg4YjAxMzA3ODEyN2MwMjQiLCJsYXN0X2xvZ2luIjoiMjAyMC0wNC0wMlQwOToxODozNy4zNDJaIiwic2lnbmVkX3VwIjoiMjAyMC0wNC0wMlQwOToxODozNy4xODFaIiwiZW1haWwiOiJwNGdnMnVhcWRjZUB0ZXN0LmNvbSIsImVtYWlsX3ZlcmlmaWVkIjpmYWxzZSwicGhvbmVfbnVtYmVyIjoiIiwicGhvbmVfbnVtYmVyX3ZlcmlmaWVkIjpmYWxzZSwiYXdzIjoiZGVtbyIsImF1ZCI6IjVlNWZjMzRmZjE0YmIyNTk5MmVlMjc4MSIsImV4cCI6MTU4NTgyMjcxOCwiaWF0IjoxNTg1ODE5MTE4LCJpc3MiOiJodHRwczovL3Rlc3Q4OC5jZWxlYmVzLmxpdmUvb2F1dGgvb2lkYyJ9.XUOWiKi0mpkcw570rCBZVz0wHWz1gBi5N5Bgz8mqU08FA2dlFradoZ9m_pZYlZPHW6A9R54rI7MzONQlt-sDjGqxLkL6wSNrYIJuYlysRldK3E1NRmziVukMQn8jkyq1DLhKK3WzX_ODbkasHTxdFmJ6iAgouuTjdCdcGv1B1ZTXIKJoIgXwMnYjrWbDULkJg_5_o7eP1GCVG8l5UgIRy5YNunEg7nEVLAu0aj-ob613x5k7ceb-jYLjCX2_9PVIEDeE5exGbz-3txhAxn77xjTi7m1-NEhusTHhd_p315fs0ziCYCaXXsO9eRlJ7I78geP87Thq3-vgQH7YgNy8tA",
    "refresh_token": "vRZXKWcvyVE9_kKq26OD2gFyame",
    "expires_in": 3600,
    "token_type": "Bearer",
    "scope": "openid profile email phone offline_access"
}
```

* 请求失败

```
{
  error: 'invalid_grant',
  error_description: 'invalid credentials provided',
}
```

## 发送手机验证码

此接口可结合[使用手机验证码登录](/authing/sdk/sdk-for-node.md#shi-yong-shou-ji-yan-zheng-ma-deng-lu)使用。

**Authing.getVerificationCode(phone)**

* **参数:**
  * `{String} phone`
  * 手机号
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const result = await authing.getVerificationCode('phone number')
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      code: 200, // 500 为失败
      message: '发送成功'
    }
    ```

**短信模版**

> 【Authing】{S8} 是你的验证码，有效时间为 {S2} 分钟。如非本人操作请忽略。

{% hint style="info" %}
当前不支持修改短信模版。
{% endhint %}

## 使用手机验证码登录

**Authing.loginByPhoneCode(options)**

* **参数:**
  * `{Object} options`
    * **phone**，必填，手机号
    * **phoneCode**，必填，使用发送短信接口获取
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.loginByPhoneCode({
        phone: 'Your Phone',
        phoneCode: 'Your Phone Code',
      }).catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "用户邮箱",
        "emailVerified": false,
        "username": "用户名",
        "nickname": "",
        "phone": "用户手机号",
        "company": "",
        "photo": "https://usercontents.authing.cn/client/logo@2.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false,
    }
    ```

## 检测手机号验证码是否正确

**Authing.verifyPhoneCode(options)**

* **参数:**
  * `{Object} options`
    * **phone**，必填，手机号
    * **phoneCode**，必填，使用发送短信接口获取
* **使用方法:**

```javascript
(async function() {
  const authing = new Authing({
    userPoolId: 'your_userpool_id',
  	secret: 'your_userpool_secret'
  });
  
  const result = await authing.verifyPhoneCode({
    phone: 'Your Phone',
    phoneCode: 'Your Phone Code',
  })
})();
```

* 返回数据

```javascript
// 验证码正确的返回数据
{
    code: 200,
    message: '验证码正确',
    status: true
}

// 验证码不正确的示例
{
    code: 2300,
    message: '验证码过期',
    status: false
}
```

## 使用手机号注册

### 1. 发送验证码 Authing.sendRegisterPhoneCode(phone)

```javascript
(async function() { const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  
  const response = await authing.sendRegisterPhoneCode(
  'Your Phone'
  ).catch((error) => { ... })
})();
```

### 2. 调用接口注册 Authing.register(options)

* **参数:**
  * `{Object} options`
    * **phone** 手机号
    * **phoneCode** 使用步骤一中的发送短信接口获取
    * **password** 可选，密码

```javascript
(async function() {  
const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  
  const userInfo = await authing.register({
    phone: 'Your Phone',
    password: 'password',
    phoneCode: 'Your Phone Code',
  }).catch((error) => { ... })
})();
```

## 使用手机号密码登录

**Authing.loginByPhonePassword(options)**

* **参数:**
  * {Object} options
    * **phone**，必填，手机号
    * **password**，必填，密码
* 使用方法：
  * ```javascript
    (async function() {
    const authing = new Authing({
    userPoolId: 'your_userpool_id'
    });

    const userInfo = await authing.loginByPhonePassword({
    phone: ‘Your Phone’,
    password: ‘Your Password’,
    }).catch((error) => { ... })
    })();
    ```
* 返回数据：
  * ```javascript
    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "86700229ww6ss@163.com",
        "emailVerified": false,
        "username": "86700229ww6ss@163.com",
        "nickname": "",
        "company": "",
        "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false,
        "group": {
          "_id": "59e374332023830871913ebd",
          "name": "default",
          "descriptions": "default",
          "createdAt": "Sun Oct 15 2017 22:44:03 GMT+0800 (CST)"
        }
     }
    ```

## 使用 AD 登录

Active Directory 的连接流程请参考：

{% content-ref url="/pages/-M4j2-nYtxayAA-VNOWB" %}
[接入 Active Directory](/authing/authentication/active-directory.md)
{% endcontent-ref %}

**Authing.loginByAd(options)**

* **参数:**
  * `{Object} options`
    * `username`，必传，在 Active Directory 服务中的用户名，必须是 `username@domain.com` 或 `domain\username` 形式。
    * `password`，必传，AD 域用户密码。
    * `adConnectorId`，必传，AD Connector ID，可以在[**控制台**](https://authing.cn/dashboard) > **第三方登录** > **Active Directory** 获得。
* **使用方法：**

```javascript
(async function() {
  const authing = new Authing({
    userPoolId: 'your_userpool_id',
  	secret: 'your_userpool_secret'
  });
  
  const userInfo = await authing.loginByAd({
    adConnectorId: 'Your AD Connector ID',
    username: 'Your AD domain username',
    passowrd: 'Your AD domain password',
  }).catch((error) => { ... })
})();
```

* **返回数据**：

```javascript
{
  "_id": "5e95788552c17c38d6674fbf",
  "email": "mary@123.com",
  "phone": "13112341234",
  "name": null,
  "givenName": null,
  "familyName": null,
  "username": "mycompany\\mary.smith",
  "nickname": "Mary Smith",
  "company": "acompany",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoibWFyeUAxMjMuY29tIiwidW5pb25pZCI6ImFkfDVlOTJkOGVlNjZlY2Y3NWI4MTI3ODNhNHxDTj1NYXJ5IFNtaXRoLENOPVVzZXJzLERDPW15Y29tcGFueSxEQz1sb2NhbCIsImlkIjoiNWU5NTc4ODU1MmMxN2MzOGQ2Njc0ZmJmIiwiY2xpZW50SWQiOiI1ZThjMWY4MmUzYWUxNDJlY2I3YWZhNjciLCJwaG9uZSI6IjEzMTEyMzQxMjM0In0sImlhdCI6MTU4Njg3Mzk2MSwiZXhwIjoxNTg4MTY5OTYxfQ.cmP9k9CKvqqrskcW42LHlOEbvJ2gG2ERJ8VaCmBRRi4",
  "registerMethod": "ad",
  "unionid": "ad|5e92d8ee66ecf75b812783a4|CN=Mary Smith,CN=Users,DC=mycompany,DC=local",
  "postalCode": null
}
```

## 使用 LDAP 登录

LDAP 服务的配置流程请参考[配置 LDAP 服务](/authing/authentication/ldap/ldap.md)。

**Authing.loginByLDAP(options)**

* **参数:**
  * `{Object} options`
    * `username`，在 LDAP 服务中的登录名，可以是邮箱或用户名
    * `password`，在 LDAP 服务中的密码
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.loginByLDAP({
        username: 'Your LDAP username',
        passowrd: 'Your LDAP password',
      }).catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "_id": "5cbe9a4347618069372e75ff",
      "username": "Nikola Tesla",
      "nickname": "Nikola Tesla",
      "oauth": "{\"dn\":\"uid=tesla,dc=example,dc=com\",\"controls\":[],\"objectClass\":[\"inetOrgPerson\",\"organizationalPerson\",\"person\",\"top\",\"posixAccount\"],\"cn\":\"Nikola Tesla\",\"sn\":\"Tesla\",\"uid\":\"tesla\",\"mail\":\"tesla@ldap.forumsys.com\",\"uidNumber\":\"88888\",\"gidNumber\":\"99999\",\"homeDirectory\":\"home\"}",
      "unionid": "uid=tesla,dc=example,dc=com",
      "registerMethod": "ldap:default::from-undefined",
      "email": "tesla@ldap.forumsys.com",
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoidGVzbGFAbGRhcC5mb3J1bXN5cy5jb20iLCJ1bmlvbmlkIjoidWlkPXRlc2xhLGRjPWV4YW1wbGUsZGM9Y29tIiwiaWQiOiI1Y2JlOWE0MzQ3NjE4MDY5MzcyZTc1ZmYiLCJjbGllbnRJZCI6IjVjYTQwMjdjOGEzNjJjODIyZTI2ZDA0ZiJ9LCJpYXQiOjE1NTU5OTY1MjUsImV4cCI6MTU1NzI5MjUyNX0.gcKasWAzO0ZS4ay_KGGp_ihPKG_GaGXk5iQKzP6R4_w",
      "company": ""
    }
    ```

## 验证用户 Token

**Authing.checkLoginStatus(token)**

* **参数：**
  * `token {String}`，必填，Authing 签发的用户 token
* **使用方法:**
  * ```javascript
    (async () => {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
        
      const result = await authing.checkLoginStatus('USER_JWT_TOKEN');
    })()
    ```
* **返回数据:**

若 Token 合法，则返回数据为：

```javascript
{
  status: true,
  code: 200,
  message: '已登录',
  token: {
    ... // Token 数据
  }
}
```

当 status 为 false 时，有三种情况，分别返回：

```javascript
{
  status: false,
  code: 2020,
  message: '未登录'
}
```

```javascript
{
  status: false,
  code: 2206,
  message: '登录信息已过期' 
}
```

```javascript
{
  status: false,
  code: 2207,
  message: '登录信息有误'
}
```

## 刷新用户 Token <a href="#refresh-user-token" id="refresh-user-token"></a>

**Authing.refreshToken(options)**

* **参数:**
  * `{Object} options`
    * **user**，必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
        secret: 'your_userpool_secret'
      });
      
      const token = await authing.refreshToken({
        user: '59e5ff4935eebf1913cfe8a1'
      })
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoieGlleWFuZ0Bkb2RvcmEuY24iLCJpZCI6IjVkMDQ2M2FjODdkNmU5NTEwM2E3MTBjNSJ9LCJpYXQiOjE1NjA1NzEwNzYsImV4cCI6MTU2MTg2NzA3Nn0.qs-Q7UOC5wFa40uIau-50-VjSAVOVjr5nw2opzQeLYg",
      "iat": 1560571076,
      "exp": 1561867076,
      "thirdPartyIdentity": {
        "refreshSuccess": true,
        "message": "qq token 刷新成功",
        "provider": "qq",
        "refreshToken": "929BF76A31B5F32D3A10F871ABC809F4",
        "accessToken": "5B99DCFB144917B3D04E522499BD340C",
        "updatedAt": "2020-02-08T18:12:04+08:00"
      }
    }
    ```

## 刷新用户三方 Token <a href="#refresh-user-third-party-token" id="refresh-user-third-party-token"></a>

**Authing.refreshThirdPartyToken(userId)**

此接口用于刷新用户在社会化登录时产生的 access\_token。例如使用 QQ 登录后的 access\_token，可用于调用 QQ 相关业务接口。

* **参数:**
  * `{String} userId`必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
        secret: 'your_userpool_secret'
      });
      
      const token = await authing.refreshToken('59e5ff4935eebf1913cfe8a1')
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        "refreshSuccess": true,
        "message": "qq token 刷新成功",
        "provider": "qq",
        "refreshToken": "929BF76A31B5F32D3A10F871ABC809F4",
        "accessToken": "5B99DCFB144917B3D04E522499BD340C",
        "updatedAt": "2020-02-08T18:12:04+08:00"
    }
    ```

## 退出

**Authing.logout(uid)**

* **参数:**
  * `{String} uid`，必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      await authing.logout('59e5ff4935eebf1913cfe8a1')
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
    	id: "59e5ff4935eebf1913cfe8a1"
    }
    ```

### 退出 SSO

如果你使用了 OAuth、OIDC 或 SAML 实现了单点登录，那么使用户退出登录需要跳转到一个 URL：

> https\://<你的域名>.authing.cn/login/profile/logout?app\_id=\<OAuth 应用 ID>\&redirect\_uri=<退出之后的回调地址>

其中 `app_id` 和 `redirect_uri` 都是必填选项，`redirect_uri` 是退出后你想要返回的地址。

## 管理用户权限

{% content-ref url="/pages/-LdsvfH3FefEwkF3we-a" %}
[配置用户权限](/authing/advanced/roles.md)
{% endcontent-ref %}

{% content-ref url="/pages/-LrEOJBpsUnzhZ8dcGkc" %}
[老版权限控制（deprecated）](/authing/sdk/sdk-for-node/update-user-permissions.md)
{% endcontent-ref %}

## 获取单个用户资料 <a href="#get-single-user-data" id="get-single-user-data"></a>

**Authing.user(options)**

除 Authing 用户信息外，`thirdPartyIdentity` 字段包含用户在**第三方社会化登录时**产生的 **access\_token**，可用于调用第三方相关业务接口。

* **参数:**
  * `{Object} options`
    * **id**，必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.user({
        id: '59e5ff4935eebf1913cfe8a1'
      })
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        "_id": "5a584dcd32e6510001a8f144", 
        "email": "1968198962@qq.com", 
        "emailVerified": false, 
        "username": "1968198962@qq.com", 
        "nickname": "", 
        "company": "", 
        "photo": "http://oxacbp94f.bkt.clouddn.com/user-avatars/Fqy_de1Jj5TmngEFiiY1-RsCCDcO", 
        "browser": "", 
        "registerInClient": "59f86b4832eb28071bdd9214", 
        "registerMethod": "default:username-password", 
        "oauth": "", 
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoiMTk2ODE5ODk2MkBxcS5jb20iLCJpZCI6IjVhNTg0ZGNkMzJlNjUxMDAwMWE4ZjE0NCJ9LCJpYXQiOjE1MTcwMzI1MjV9.Ah0Oii741L_wJHhiE5KtWDgRU1Q3x_fNZBNNM5MhqDc", 
        "tokenExpiredAt": "Sat Jan 27 2018 13:55:25 GMT+0800 (CST)", 
        "loginsCount": 0, 
        "lastLogin": "Fri Jan 12 2018 13:55:25 GMT+0800 (CST)", 
        "lastIP": null, 
        "signedUp": "Fri Jan 12 2018 13:55:25 GMT+0800 (CST)", 
        "blocked": false, 
        "isDeleted": false,
        "thirdPartyIdentity" : {
    		  "provider" : "wechat-mp",
    		  "refreshToken" : "30_dfRXbdXTTb3MLeQawh3v-Qcs94cLWbQixkSXlzTtOyaM0ym-K_0kcytTspceZcvu3CCkb6g1NAjId82Vw2DWfGv8sayIjHDFepR1H0SKxyc",
    		  "accessToken" : "30_MFUPDUNMrQ-3Z9GSlpZaM3VZjz4guazxZwTyD9pH4640xy1XAYKpFA6eBhYhXFvyTSwtVC3TvyXBemTEkqrALwQ3FzCQsHl43MePbEbzg1Y",
    		  "expiresIn" : 7200,
    		  "updatedAt" : "2020-02-08T18:11:37.807+08:00"
    	  },
        "__typename": "ExtendUser"
    }
    ```

## 一次性获取多个用户的资料 <a href="#yi-ci-xing-huo-qu-duo-ge-yong-hu-de-zi-liao" id="yi-ci-xing-huo-qu-duo-ge-yong-hu-de-zi-liao"></a>

**Authing.userPatch(options)**

* **参数:**
  * `{Object} options`
    * ids
      * 要获取的用户 id 列表，使用逗号分割，不要出现多余的空格；如果使用非法 id 查询时系统会自动忽略。
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.userPatch({
        ids: '5a584dcd32e6510001a8f144,5c08fa74583d9d00019d245e'
      })
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    { list: 
    [ { _id: '5c0a3565583d9d000219d3960',
       unionid: 'oVzVG4wo1v0c7uyiFQtHc3Nrl2hg',
       email: null,
       emailVerified: false,
       username: 'xxxxxxxxxxxxxxxxx',
       nickname: 'xxxxxxxxxxxxxxxxx',
       company: '',
       photo: 'xxxxxxxxxxxxxxxxx',
       browser: '',
       registerInClient: 'xxxxxxxxxxxxxxxxx',
       registerMethod: 'oauth:wechat',
       oauth: 'xxxxxxxxxxxxxxxxx',
       token: 'xxxxxxxxxxxxxxxxx',
       tokenExpiredAt: 'Sat Dec 22 2018 16:55:01 GMT+0800 (CST)',
       loginsCount: 1,
       lastLogin: 'Fri Dec 07 2018 16:55:01 GMT+0800 (CST)',
       lastIP: '114.93.36.228',
       signedUp: 'Fri Dec 07 2018 16:55:01 GMT+0800 (CST)',
       blocked: false,
       isDeleted: false,
       userLocation: null,
       userLoginHistory: null },
     { _id: '5c08fa74583d9d00019d24ee',
       unionid: 'xxxxxxxxxxxxxxxxx',
       email: null,
       emailVerified: false,
       username: 'xxxxxxxxxxxxxxxxx',
       nickname: 'xxxxxxxxxxxxxxxxx',
       company: '',
       photo: 'xxxxxxxxxxxxxxxxx',
       browser: '',
       registerInClient: 'xxxxxxxxxxxxxxxxx',
       registerMethod: 'oauth:wechat',
       oauth: 'xxxxxxx',
       token: 'xxxxxxx',
       tokenExpiredAt: 'Fri Dec 21 2018 18:31:16 GMT+0800 (CST)',
       loginsCount: 1,
       lastLogin: 'Thu Dec 06 2018 18:31:16 GMT+0800 (CST)',
       lastIP: '221.192.178.75',
       signedUp: 'Thu Dec 06 2018 18:31:16 GMT+0800 (CST)',
       blocked: false,
       isDeleted: false,
       userLocation: null,
       userLoginHistory: null } ],
    totalCount: 2 }
    ```

## 获取用户列表 <a href="#huo-qu-yong-hu-lie-biao" id="huo-qu-yong-hu-lie-biao"></a>

**Authing.list(page, count)**

* **参数:**
  * `{Number} page`
    * Default: `1`
  * `{Number} count`
    * Default: `10`
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const userInfo = await authing.list()
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      totalCount: 222,
      list: [{
                "_id": "59e5ff4935eebf1913cfe8a1",
                "email": "86700229ww6ss@163.com",
                "emailVerified": false,
                "username": "86700229ww6ss@163.com",
                "nickname": "",
                "company": "",
                "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
                "browser": "",
                "token": null,
                "tokenExpiredAt": null,
                "loginsCount": 0,
                "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
                "lastIP": null,
                "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
                "blocked": false,
                "isDeleted": false,
                "group": {
                  "_id": "59e374332023830871913ebd",
                  "name": "default",
                  "descriptions": "default",
                  "createdAt": "Sun Oct 15 2017 22:44:03 GMT+0800 (CST)"
                  }
             },
              ...
            ]
    }
    ```

## 删除用户 <a href="#shan-chu-yong-hu" id="shan-chu-yong-hu"></a>

**Authing.remove(uid)**

* **参数:**
  * `{String} uid`
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      const uid = '59e5ff4935eebf1913cfe8a1';
      const userInfo = await authing.remove(uid)
        .catch((error) => { ... })
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        _id: '59e5ff4935eebf1913cfe8a1'
    }
    ```

## 修改密码

**Authing.update(options)**

* **参数:**
  * `{Object} options`
    * password: `{String}，必填，用户新密码`
    * oldPassword: `{String}，选填，用户原始密码`
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id'
      });
      // 以用户身份登录
      const login = await authing.login({
        email: 'test@test.com',
        password: '123456'
      })
      // 修改邮箱
      await authing.update({
        _id: login._id,
        password: '123456',
      });
    })();
    ```
* **返回数据:**
  * ```javascript

    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "xxx@xxx.com",
        "emailVerified": false,
        "username": "premail@premail.com",
        "nickname": "",
        "company": "",
        "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false,
        "group": {
          "_id": "59e374332023830871913ebd",
          "name": "default",
          "descriptions": "default",
          "createdAt": "Sun Oct 15 2017 22:44:03 GMT+0800 (CST)"
        }
     }
    ```

## 修改用户资料 <a href="#xiu-gai-yong-hu-she-zhi" id="xiu-gai-yong-hu-she-zhi"></a>

{% hint style="info" %}
此接口不能用来直接修改手机号和邮箱！

修改手机号请使用  changePhone 接口。

修改邮箱请使用 changeEmail 接口。
{% endhint %}

若使用 `JavaScript` 调用，需要使用 `then().catch()` 捕获结果和错误。

**Authing.update(options)**

此接口可以用来修改密码、昵称、头像等各种用户信息

* **参数:**
  * `{Object} options`
    * \_id `{String} 必填`
    * email `{String}，选填`
    * emailVerified: `{Boolean}，选填，邮箱是否经过验证`
    * username: `{String}，选填`
    * nickname: `{String}，选填`
    * company: `{String}，选填`
    * phone: `{String}，选填`
    * oauth: `{String}，选填，oauth 信息`
    * photo: `{String || file object}，选填，用户头像`
    * browser: `{String}，选填，用户注册时所用的浏览器`
    * password: `{String}，选填，用户密码`
    * oldPassword: `{String}（`当有 password 时，旧密码参数必需填写）
    * token: `{String}，选填`
    * tokenExpiredAt: `{String}，选填，token 过期时间`
    * loginsCount: `{Number}，选填，登录次数`
    * lastLogin: `{String}，选填，最后登录时间`
    * lastIP: `{String}，选填，最后登录 IP`
    * signedUp: `{String}，选填，注册时间`
    * blocked: `{Boolean}，选填，是否被锁定`
    * isDeleted: `{Boolean}，选填，是否被删除`
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      // 修改邮箱
      await authing.update({
        _id: "59e5ff4935eebf1913cfe8a1",
        email: 'xxx@xxx.com',
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "xxx@xxx.com",
        "emailVerified": false,
        "username": "premail@premail.com",
        "nickname": "",
        "company": "",
        "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false,
        "group": {
          "_id": "59e374332023830871913ebd",
          "name": "default",
          "descriptions": "default",
          "createdAt": "Sun Oct 15 2017 22:44:03 GMT+0800 (CST)"
        }
     }
    ```

## 修改邮箱

如果用户已经绑定了邮箱，默认情况下，需要同时验证原有邮箱（目前账号绑定的邮箱）和当前邮箱（将要绑定的邮箱）。也就是说，用户 A 当前绑定的邮箱为 <123456@qq.com>，想修改为 <1234567@qq.com>，那么就需要同时验证这两个邮箱。

开发者也可以选择不开启 “验证原有邮箱“ ，可以在 [Authing 控制台](https://authing.cn/dashboard) 的 **基础配置** - **基础设置** 页面的**安全设置**模块进行关闭。如下图所示：

![](/files/-LvLaDulvTVel_HNbNsV)

> 验证码通过的 sendChangeEmailVerifyCode 接口发送。

**Authing.updateEmail(options)**

* 参数：
  * {Object} options
    * email : 当前邮箱，必填。
    * emailCode: 当前邮箱验证码，必填。
    * oldEmail：原有邮箱，选填。
    * oldEmailCode: 原有邮箱验证码，选填。
* 使用方法

```javascript
(async function() {
  const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  // 以用户身份登录
  const login = await authing.login({
    email: 'test@test.com',
    password: '123456'
  })
  await authing.updateEmail({
	email: "YOUR_NEW_EMAIL"
	emailCode: "YOUR_EMAIL_CODE"
  });
})();
```

* 返回数据：最新的用户信息

```javascript
{
    "_id": "5a584dcd32e6510001a8f144", 
    "email": "1968198962@qq.com", 
    "emailVerified": false, 
    "username": "1968198962@qq.com", 
    "nickname": "", 
    "company": "", 
    "photo": "http://oxacbp94f.bkt.clouddn.com/user-avatars/Fqy_de1Jj5TmngEFiiY1-RsCCDcO", 
    "browser": "", 
    "registerInClient": "59f86b4832eb28071bdd9214", 
    "registerMethod": "default:username-password", 
    "oauth": "", 
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoiMTk2ODE5ODk2MkBxcS5jb20iLCJpZCI6IjVhNTg0ZGNkMzJlNjUxMDAwMWE4ZjE0NCJ9LCJpYXQiOjE1MTcwMzI1MjV9.Ah0Oii741L_wJHhiE5KtWDgRU1Q3x_fNZBNNM5MhqDc", 
    "tokenExpiredAt": "Sat Jan 27 2018 13:55:25 GMT+0800 (CST)", 
    "loginsCount": 0, 
    "lastLogin": "Fri Jan 12 2018 13:55:25 GMT+0800 (CST)", 
    "lastIP": null, 
    "signedUp": "Fri Jan 12 2018 13:55:25 GMT+0800 (CST)", 
    "blocked": false, 
    "isDeleted": false, 
    "__typename": "ExtendUser"
}
```

## &#x20;发送修改邮箱验证码

开发者可以在 **消息服务 - 邮件模版** 中设置邮件模板，默认的邮件如下图所示：

![](/files/-LvLEkmHl8J-O26OwcBw)

开发者可以自定义 CSS 样式、主题等。

注意：如果请求发送的邮箱已经注册过了，会提示 “该邮箱已绑定，请换一个吧“ 错误。

**Authing.sendChangeEmailVerifyCode(options)**

* 参数：
  * `{Object} options`
    * `email`
* 使用方法

```javascript
(async function() {
  const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  // 以用户身份登录
  const login = await authing.login({
    email: 'test@test.com',
    password: '123456'
  })
  await authing.sendChangeEmailVerifyCode({
	email: "YOUR_NEW_EMAIL"
  });
})();
```

* 返回数据

成功示例

```javascript
{
    code: 200,
    message: "成功"
}
```

失败示例：

```javascript
{
    code: 2035,
    message: "该邮箱已绑定，请换一个吧"
}
```

## 修改手机号

和修改邮箱一样，默认情况下，如果用户当前已经绑定了手机号，需要同时验证原有手机号（目前账号绑定的手机号）和当前邮箱（将要绑定的手机号）。也就是说，用户 A 当前绑定的手机号为 15888888888，想修改为 15899999999，那么就需要同时验证这两个手机号。

开发者也可以选择不开启 “验证原有手机号“ ，可以在 [Authing 控制台](https://authing.cn/dashboard) 的 **基础配置** - **基础设置** 页面的**安全设置**模块进行关闭。如下图所示：

![](/files/-LvLb0pZ5EB-IwwPbIwS)

> 手机号短信验证码通过  **getVerificationCode** 接口发&#x9001;**。**

**Authing.updatePhone(options)**

* 参数：
  * {Object} options
    * phone : 当前手机号，必填。
    * phoneCode: 当前手机号短信验证码，必填。
    * oldPhone：原有手机号，选填。
    * oldPhoneCode: 原有手机号短信验证码，选填。
* 使用方法

```javascript
(async function() {
  const authing = new Authing({
    userPoolId: 'your_userpool_id'
  });
  // 以用户身份登录
  const login = await authing.login({
    email: 'test@test.com',
    password: '123456'
  })
  await authing.updateEmail({
	phone: "YOUR_NEW_PHONE_NUMBER"
	phoneCode: "YOUR_PHONE_CODE",
  oldPhone: "YOUR_CURRENT_PHONE_NUMBER",
  oldPhoneCode: "YOUR_CURRENT_PHONE_CODE"
  });
})();
```

* 返回数据：最新的用户信息。

## &#x20;<a href="#zhong-zhi-mi-ma" id="zhong-zhi-mi-ma"></a>

## 重置密码 <a href="#zhong-zhi-mi-ma" id="zhong-zhi-mi-ma"></a>

### **1. 发送验证码 Authing.sendResetPasswordEmail(options)**

* **参数:**
  * `{Object} options`
    * email
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      // 发送验证码到指定邮箱
      await authing.sendResetPasswordEmail({
        email: 'xxx@xxx.com',
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "message":"成功",
      "code":null,
      "__typename": "CommonMessage"
    }
    ```

### **2. 验证验证码 Authing.verifyResetPasswordVerifyCode(options)**

* **参数:**
  * `{Object} options`
    * email
    * verifyCode
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      // 验证验证码
      await authing.verifyResetPasswordVerifyCode({
        email: 'xxx@xxx.com',
        verifyCode: 'verifyCode',
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "message": "验证成功，请输入新密码",
      "code": null,
      "__typename": "CommonMessage"
    }
    ```

### **3. 发送新密码 Authing.changePassword(options)**

* **参数:**
  * `{Object} options`
    * email
    * password
    * verifyCode
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      await authing.changePassword({
        email: 'xxx@xxx.com',
        password: 'new_password',
        verifyCode: 'verifyCode',
      });
    })();
    ```
* **返回数据:**
  * ```javascript
      {
        "_id":"5a2a723d598e37000106786a",
        "email":"1968108962@qq.com",
        "emailVerified":true,
        "username":"1968108962@qq.com",
        "nickname":"",
        "company":"","photo":"http://oxacbp94f.bkt.clouddn.com/authing-avatar.png","browser":"",
        "registerInClient":"59f86b4832eb28071bdd9214","registerMethod":"default:username-password",
        "oauth":"","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJkYXRhIjp7ImVtYWlsIjoiMTk2ODEwODk2MkBxcS5jb20iLCJpZCI6IjVhMmE3MjNkNTk4ZTM3MDAwMTA2Nzg2YSJ9LCJpYXQiOjE1MTQwMjcyNDd9.vWrlzKY-Qr0SXwx8k__BF0ADCBjqGgMWP-wVOWgbH7A","tokenExpiredAt":"Sat Dec 23 2017 19:07:27 GMT+0800 (CST)","loginsCount":1,"lastLogin":"Fri Dec 08 2017 19:07:27 GMT+0800 (CST)","lastIP":"172.20.0.1",
        "signedUp":"Fri Dec 08 2017 19:06:37 GMT+0800 (CST)",
        "blocked":false,"isDeleted":false,
        "__typename":"ExtendUser"
      }
    ```

## 验证用户邮箱 <a href="#yan-zheng-you-xiang" id="yan-zheng-you-xiang"></a>

### **发送验证邮件 Authing.sendVerifyEmail(options)**

* **参数:**
  * `{Object} options`
    * email: 需要验证的邮箱
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      await authing.sendVerifyEmail({
        email: 'xxx@xxx.com',
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
         message: "发送验证邮件成功", 
         __typename: "CommonMessage"
    }
    ```

发送之后，用户将会收到一个包含验证链接的邮件，当用户打开此链接，我们将进行验证。

## 解绑邮箱 <a href="#jie-bang-you-xiang" id="jie-bang-you-xiang"></a>

若使用 `JavaScript` 调用，需要使用 `then().catch()` 捕获结果和错误。

**Authing.unbindEmail(options)**

* **参数:**
  * `{Object} options`
    * user `{String} 用户 ID，可选，默认为当前登录用户的 ID`
    * client `{String} 应用 ID，可选，默认为当前登录应用的 ID`
* **使用方法:**
  * ```javascript
    Authing.unbindEmail();
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      await authing.unbindEmail();
    })();
    ```
* **返回数据:**
  * ```javascript

    {
        "_id": "59e5ff4935eebf1913cfe8a1",
        "email": "86700229ww6ss@163.com",
        "emailVerified": false,
        "username": "86700229ww6ss@163.com",
        "nickname": "",
        "company": "",
        "photo": "http://www.xiaohehe.net/uploads/allimg/150305/304-1503051H136.png",
        "browser": "",
        "token": null,
        "tokenExpiredAt": null,
        "loginsCount": 0,
        "lastLogin": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "lastIP": null,
        "signedUp": "Tue Oct 17 2017 21:02:01 GMT+0800 (CST)",
        "blocked": false,
        "isDeleted": false
     }
    ```

**注意事项**

若未绑定其他登录方式, 则不可解绑邮箱

## 查询用户授权的 SSO 应用列表 <a href="#yan-zheng-you-xiang" id="yan-zheng-you-xiang"></a>

该接口返回用户在一个用户池下授权过的 OAuth 和 OIDC 应用列表。

### **Authing.**&#x67;etAuthedAppLis&#x74;**(options)**

* **参数:**
  * `{Object} options`
    * **clientId**: 用户池 id，必传
    * **userId**：用户 id，必传
    * **page**：页数，可选，默认 1
    * **count**：每页数目，可选，默认 10
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      await authing.getAuthedAppList({
      	clientId: "5d023c7b5642461234b9c62e",
    	userId: "5d765d4013d73a5e90b7857a",
    	page: 1,
    	count: 10
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "OAuthApps": [
        {
          "_id": "5d5a8a7bbc7275af2cb71920",
          "name": "test1",
          "domain": "test123",
          "clientId": "5d5921ffaa016518f658498d",
          "description": "",
          "isDeleted": false,
          "grants": [
            "authorization_code",
            "implicit",
            "refresh_token"
          ],
          "redirectUris": [
            "http://qq.com"
          ],
          "when": "Mon Aug 19 2019 19:39:39 GMT+0800 (CST)"
        },
        {
          "_id": "5d5e2e8b026f9d145bf89203",
          "name": "oauth1",
          "domain": "oauth1",
          "clientId": "5d5921ffaa016518f658498d",
          "description": "",
          "isDeleted": false,
          "grants": [
            "authorization_code",
            "implicit",
            "refresh_token"
          ],
          "redirectUris": [
            "http://qq.com"
          ],
          "when": "Thu Aug 22 2019 13:56:27 GMT+0800 (CST)"
        }
      ],
      "OIDCApps": [
        {
          "_id": "5d5a85e258375a32d1133d45",
          "name": "test1",
          "client_id": "5d5a85e258375a32d1133d45",
          "domain": "test1",
          "description": "test1",
          "authorization_code_expire": "600",
          "when": "Mon Aug 19 2019 19:20:02 GMT+0800 (CST)",
          "isDeleted": false,
          "id_token_signed_response_alg": "HS256",
          "response_types": [
            "code"
          ],
          "grant_types": [
            "authorization_code",
            "refresh_token"
          ],
          "token_endpoint_auth_method": "client_secret_post",
          "redirect_uris": [
            "http://qq.com"
          ],
          "image": "https://usercontents.authing.cn/client/logo@2.png",
          "access_token_expire": "3600",
          "id_token_expire": "3600",
          "cas_expire": "3600"
        }
      ],
      "totalCount": 3
    }
    ```

## 撤回用户对 SSO 应用的授权 <a href="#yan-zheng-you-xiang" id="yan-zheng-you-xiang"></a>

### **Authing.revokeAuthedApp(options)**

* **参数:**
  * `{Object} options`
    * **userPoolId**: 用户池 id，必传
    * **userId**：用户 id，必传
    * **appId**：SSO 应用的 id，必传
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id',
      	secret: 'your_userpool_secret'
      });
      
      await authing.revokeAuthedApp({
      	userPoolId: "5d023c7b5642461234b9c62e",
    	userId: "5d765d4013d73a5e90b7857a",
    	appId: "5d5e2e8b026f9d145bf89203"
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "isRevoked": "true",
      "_id": "5d7661e17a9f981da5fa8098",
      "scope": "profile",
      "appId": "5d5e2e8b026f9d145bf89203",
      "userId": "5d765d4013d73a5e90b7857a",
      "type": "oauth"
    }
    ```

## 自定义请求链接

`Authing` 构造函数包含一个名为 `host` 对象，可接收自定义的请求链接（适合私有部署 Authing 的用户使用），使用方法如下：

```javascript
const auth = new Authing({
	userPoolId: 'xxxx',
	secret: 'xxx',
	host: {
		user: 'https://users.authing.cn/graphql',
		oauth: 'https://oauth.authing.cn/graphql'
	}
});
```

`host` 对象中 `user` 和 `oauth` 的默认值是 Authing 官方的请求链接：

* <https://users.authing.cn/graphql>
* <https://oauth.authing.cn/graphql>

<br>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://authing.gitbook.io/authing/sdk/sdk-for-node.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
