> For the complete documentation index, see [llms.txt](https://authing.gitbook.io/authing/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://authing.gitbook.io/authing/sdk/sdk-for-javascript.md).

# SDK for JavaScript

JavaScript SDK 支持 **Angular.js，React.js，Vue.js** 以及**浏览器原生环境**。JavaScript SDK 可用来处理登录、注册等工作。

**请注意** [**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` 进行安装， 它可以与一些模块打包工具很好地配合使用，如 `Webpack`， `Browserify。`

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

**CDN**

```markup
<script src="https://cdn.jsdelivr.net/npm/authing-js-sdk/dist/authing-js-sdk-browser.min.js"></script>
```

## 初始化

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

* **userPoolId**
  * 用户池 ID，可从 [Authing 控制台](https://authing.cn/dashboard)中[获取](/authing/others/faq.md#ru-he-huo-qu-client-id-he-client-secret)。

**示例**

```javascript
const auth = new Authing({
	userPoolId: 'your_userpool_id',
});
// authing.register({...}).then(info => {})
// authing.login({...}).then(info => {})
```

也可以通过用户的 token 初始化，获得此用户的权限，例如获取他的信息。

* accessToken
  * 用户 token

**示例**

```javascript
const auth = new Authing({
	userPoolId: "your_userpool_id",
	accessToken: 'user_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) {}`
  * 错误处理函数，用于处理初始化失败错误、预检错误。
* **cdnHost**: **string**
  * 图片 CDN host，供私有化部署了 Authing 服务的开发者填写。示例： <https://mybucket.yourcdndomain.com，**末尾请不要带> "/"\*\* 。

## 使用

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

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

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

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

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

```javascript
import Authing from 'authing-js-sdk';

const main = async () => {

	let auth = new Authing({
		userPoolId: 'your_client_id',
		secret: 'your_app_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))
  }
```

## 注册

**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'
      });
      
      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.userExist(userPoolId,options)**

* **参数:**
  * `userPoolId`  要查询的用户池 ID
  * `{Objects} options`
    * **email 邮箱**
    * **phone 电话**
    * **username 用户名**
* **使用方法:**

  ```javascript
  (async function() {  
  const authing = new Authing({
      userPoolId: 'your_userpool_id'
    });
    
    const userExist = await authing.userExist( 'your_userpool_id',{
      phone: 'Your Phone',
    }).catch((error) => { ... })
  })(); 
  ```
* **返回数据:**
  * Boolean

## 登录

**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'
      });
      
      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) => { ... })
})();
```

## 使用手机号注册

### 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',
    phoneCode: 'Your Phone Code',
    password: 'Your Password'
  }).catch((error) => { ... })
})();
```

## 使用手机验证码登录

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

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

**短信模版**

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

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

### 2. 调用接口登陆 Authing.**loginByPhoneCode**(options)

* **参数:**
  * `{Object} options`
    * **phone**，必填，手机号
    * **phoneCode**，必填，使用发送短信接口获取
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id'
      });
      
      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.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'
      });
      
      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(options)**

* **参数:**
  * `{Object} options`
    * **user**，必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async () => {
        const authing = new Authing({
            userPoolId: 'your_userpool_id'
        });
        
        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: '登录信息有误'
}
```

## 退出

**Authing.logout(uid)**

* **参数:**
  * `{String} uid`，必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_client_id'
      });
      // 先执行登录
      const userInfo = await authing.login({email: 'test@authing.cn', password: 'authing'})
      
      await authing.logout(userInfo._id)
        .catch((error) => { ... })
    })();
    ```
  * ```javascript
    (async function() {
      // 使用用户信息中的 token 字段初始化 SDK
      const authing = new Authing({
        accessToken: 'userToken'
      });
      
      await authing.logout('用户 ID')
        .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` 是退出后你想要返回的地址。

## 获取单个用户资料

需要先调用登录函数，而且传入的用户 id 参数必须与登录用户的 id 一致才能获取信息。

**Authing.user(options)**

* **参数:**
  * `{Object} options`
    * **id**，必填，用户的 \_id
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id'
      });
      // 先以用户身份登录，login 变量中保存的也是用户信息
      const login = await authing.login({
        email: 'test@test.com',
        password: '123456'
      })
      // 以后可以通过登录用户的 id 获取他的信息
      const userInfo = await authing.user({
        id: login._id
      })
        .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, 
        "__typename": "ExtendUser"
    }
    ```

## 上传头像 <a href="#shang-chuan-tou-xiang" id="shang-chuan-tou-xiang"></a>

**Authing.selectAvatarFile(cb)**

* **参数:**
  * `{function} cb`
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id'
      });
      
      authing.selectAvatarFile((avatarURL) => {
        // avatarURL 即为头像地址（公网 URL）
      })
    })();
    ```
* **结果:**
  * 此 API 会打开文件选择窗口供用户选择文件，用户选取文件后，系统会自动上传，上传成功后会调用 cb，并把头像 URL 作为参数传入 cb 函数，开发者可将回调函数中的 avatarURL 作为 photo 参数传入 [update](https://authing.gitbook.io/authing/sdk/pages/-LdsyyphaBreKun8cXvJ#修改用户设置) 方法中修改用户头像。

## 修改密码

**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,
        oldPassword: 'abcdefg',
        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 %}

**Authing.update(options)**

此接口可以用来修改密码、昵称、头像等各种用户信息，调用前需要先调用登录函数，以用户身份登录，传入的用户 id 必须与登录用户的 id 一致。

* **参数:**
  * `{Object} options`
    * \_id `{String} 必填`
    * username: `{String}，选填`
    * nickname: `{String}，选填`
    * company: `{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'
      });
      // 以用户身份登录
      const login = await authing.login({
        email: 'test@test.com',
        password: '123456'
      })
      // 修改邮箱
      await authing.update({
        _id: login._id,
        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"
  });
})();
```

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

## 重置密码 <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'
      });
      
      // 发送验证码到指定邮箱
      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'
      });
      
      // 验证验证码
      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'
      });
      
      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'
      });
      
      await authing.sendVerifyEmail({
        email: 'xxx@xxx.com',
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
         message: "发送验证邮件成功", 
         __typename: "CommonMessage"
    }
    ```

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

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

**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'
      });
      // 以用户身份登录
      const login = await authing.login({
        email: 'test@test.com',
        password: '123456'
      })
      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.getAuthedAppList(options)**

* **参数:**
  * `{Object} options`
    * **userId**：用户 id，必传
    * **page**：页数，可选，默认 1
    * **count**：每页数目，可选，默认 10
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id'
      });
      // 以用户身份登录
      const login = await authing.login({
        email: 'test@test.com',
        password: '123456'
      })
      await authing.getAuthedAppList({
    	userId: login._id,
    	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`
    * **userId**：用户 id，必传
    * **appId**：SSO 应用的 id，必传
* **使用方法:**
  * ```javascript
    (async function() {
      const authing = new Authing({
        userPoolId: 'your_userpool_id'
      });
      // 以用户身份登录
      const login = await authing.login({
        email: 'test@test.com',
        password: '123456'
      })
      await authing.revokeAuthedApp({
    	userId: login._id,
    	appId: "5d5e2e8b026f9d145bf89203"
      });
    })();
    ```
* **返回数据:**
  * ```javascript
    {
      "isRevoked": "true",
      "_id": "5d7661e17a9f981da5fa8098",
      "scope": "profile",
      "appId": "5d5e2e8b026f9d145bf89203",
      "userId": "5d765d4013d73a5e90b7857a",
      "type": "oauth"
    }
    ```

## 小程序扫码登录

小程序扫码登录指使用 Authing 小程序 `身份管家` 执行微信登录。 示例：[小程序扫码登录](http://sample.authing.cn/)

[![扫码 demo](https://camo.githubusercontent.com/1cc34581f6a1b0749f820282d685734f55a57993/68747470733a2f2f75736572636f6e74656e74732e61757468696e672e636e2f77786170702d7363616e696e672d64656d6f2e676966)](https://camo.githubusercontent.com/1cc34581f6a1b0749f820282d685734f55a57993/68747470733a2f2f75736572636f6e74656e74732e61757468696e672e636e2f77786170702d7363616e696e672d64656d6f2e676966)

#### &#x20;使用方法请参考：

{% content-ref url="/pages/-Ldt90DKQ-BpPuGgc5wk" %}
[小程序扫码登录](/authing/scan-qrcode/wxapp-qrcode.md)
{% endcontent-ref %}

## 自定义请求链接

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

```javascript
const auth = new Authing({
	userPoolId: 'xxxx',
	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>
