# 授权认证

## 鉴权方式

知晓云开放 API 授权通过 **Access Token** 作为接口调用的凭证，在对开放 API 发起请求时，均需要在 HTTP Header 加入以下授权参数：

```
  Authorization: Bearer <Access Token>
```

若开发者需要在发起 API 请求时进行测试环境的指定，则需要在 HTTP Header 中加入以下环境参数：

```
  X-Hydrogen-Env-ID: <Env ID>
```

在不指定环境参数的情况下，默认调用生产环境的 API。

## 授权流程

```
  +--------+      ID/Secrct      +--------+
  |        | +-----------------> |        |
  |        |                     |        |
  |        |         Code        |        |
  |        | <-----------------+ |        |
  | Client |                     | 知晓云  |
  |        |         Code        |        |
  |        | +-----------------> |        |
  |        |                     |        |
  |        |    Access Token     |        |
  |        | <-----------------+ |        |
  +--------+                     +--------+
```

> **info** ID/Secert 为知晓云应用的 `ClientID`、`ClientSecret`，可通过知晓云管理后台进行获取。

## 获取 Access Token

获取 Access Token 需要经过以下两个步骤

### 获取 code

**接口**

`POST https://cloud.minapp.com/api/oauth2/hydrogen/openapi/authorize/`

**参数说明**

Content-Type: `application/json`

| 参数             | 类型     | 必填 | 说明                  |
| -------------- | ------ | -- | ------------------- |
| client\_id     | String | Y  | 知晓云应用的 ClientID     |
| client\_secret | String | Y  | 知晓云应用的 ClientSecret |

**返回参数**

| 参数          | 类型     | 说明              |
| ----------- | ------ | --------------- |
| code        | String | 授权码             |
| expires\_in | Number | code 的过期时间，单位是秒 |

> **info** 获取 Code 会经过两次的 `HTTP 302 Found` 跳转，开发者在实现时需要允许客户端跟随跳转。

不跟随跳转示例：

```
$ curl ifanr.com
<html>
<head><title>302 Found</title></head>
<body bgcolor="white">
  <center><h1>302 Found</h1></center>
  <hr><center>nginx/1.11.5</center>
</body>
</html>
```

跟随跳转示例：

```
$ curl -L ifanr.com
<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta property="og:site_name" content="爱范儿" />
  <meta property="og:type" content="article" />
  <meta property="og:url" content="http://www.ifanr.com" />
  <meta name="MSSmartTagsPreventParsing" content="true"/>
  <meta http-equiv="imagetoolbar" content="no"/>
  <meta name="robots" content="all"/>
  <title>  爱范儿 · 报道未来，服务新生活引领者</title>
  ....
```

### 使用 code 获取 Access Token

**接口地址**

`POST https://cloud.minapp.com/api/oauth2/access_token/`

**参数说明**

Content-Type: `application/json`

| 参数             | 类型     | 必填 | 说明                                |
| -------------- | ------ | -- | --------------------------------- |
| client\_id     | String | Y  | 知晓云应用的 ClientID                   |
| client\_secret | String | Y  | 知晓云应用的 ClientSecret               |
| code           | String | Y  | 授权码，通过上一步获取到的                     |
| grant\_type    | String | Y  | 授权类型，这里需指定为 "authorization\_code" |

**返回参数**

| 参数             | 类型     | 说明                      |
| -------------- | ------ | ----------------------- |
| access\_token  | String | 用户授权的唯一票据               |
| token\_type    | String | token 类型                |
| expires\_in    | Number | access\_token 过期时间，单位是秒 |
| refresh\_token | String | 用于刷新授权有效期               |
| scope          | String | 权限范围                    |

**代码示例**&#x20;

```js
var request = require('request');

// 获取 code
var opt = {
  uri: 'https://cloud.minapp.com/api/oauth2/hydrogen/openapi/authorize/',
  method: 'POST',
  json: {
    client_id: '[[client_id]]',
    client_secret: '{{client_secret}}'
  },
  jar: true,                // 允许记住 cookie 
  followAllRedirects: true,     // 允许重定向
}

request(opt, function(err, res, body) {
    getToken(body.code)  // 回调调用 getToken 函数
})

// 获取 token
function getToken(code) {
  var opt = {
    uri: 'https://cloud.minapp.com/api/oauth2/access_token/',
    method: 'POST',
    json: {
      client_id: '[[client_id]]',
      client_secret: '{{client_secret}}',
      grant_type: 'authorization_code',
      code,
    }
  }

  request(opt, function(err, res, body) {
    let token = JSON.parse(body).access_token
  })
}
```

```php
<?php
$param = array(
  'client_id' => "{$client_id}",
  'client_secret' => "{$client_secret}"
);

// 获取 code
$code_url = 'https://cloud.minapp.com/api/oauth2/hydrogen/openapi/authorize/';
$code_data = postData($code_url, json_encode($param));

$code_data = json_decode($code_data, true);// 使用 code 获取 Access Token
$param['code'] = $code_data['code'];
$param['grant_type'] = 'authorization_code';

$access_token_url = 'https://cloud.minapp.com/api/oauth2/access_token/';
$access_token = postData($access_token_url, $param, 'application/json'); // 获取到的 Access Token

// 封装请求函数
function postData($url, $param, $content_type = 'application/json') {
  $ch = curl_init();

  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);  // 设置允许重定向
  curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
  curl_setopt($ch, CURLOPT_COOKIEFILE, '');
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_COOKIESESSION, true);
  curl_setopt($ch, CURLINFO_CONTENT_TYPE,  $content_type);  // 设置 Content-Type，默认 application/json
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

  $response = curl_exec($ch);
  curl_close($ch);
  return $response;
}
```

### 使用 Refresh Token 刷新 Access Token

> **danger** 调用此接口会将之前申请的 Access Token（包括 Refresh Token）强制失效，请开发者谨慎操作。

**接口地址**

`POST https://cloud.minapp.com/api/oauth2/access_token/`

**参数说明**

Content-Type: `application/json`

| 参数             | 类型     | 必填 | 说明                           |
| -------------- | ------ | -- | ---------------------------- |
| client\_id     | String | Y  | 知晓云应用的 ClientID              |
| client\_secret | String | Y  | 知晓云应用的 ClientSecret          |
| refresh\_token | String | Y  | 刷新凭证，从申请 Access Token 接口获得   |
| grant\_type    | String | Y  | 授权类型，这里需指定为 "refresh\_token" |

**返回参数**

| 参数             | 类型     | 说明                 |
| -------------- | ------ | ------------------ |
| access\_token  | String | 用户授权的唯一票据          |
| token\_type    | String | token 类型           |
| expires\_in    | Number | access\_token 过期时间 |
| refresh\_token | String | 用于刷新授权有效期          |
| scope          | String | 权限范围               |

**代码示例**&#x20;

```js
var request = require('request');

// 刷新 Access Token
function refreshAccessToken(refreshToken) {
  var opt = {
    uri: 'https://cloud.minapp.com/api/oauth2/access_token/',
    method: 'POST',
    json: {
      client_id: '[[client_id]]',
      client_secret: '{{client_secret}}',
      grant_type: 'refresh_token',
      refresh_token: refreshToken,
    }
  }
  request(opt, function(err, res, body) {
    let token = JSON.parse(body).access_token
  })
}
```

```php
<?php
$param = array(
  'client_id' => "{$client_id}",
  'client_secret' => "{$client_secret}",
  'grant_type' => "refresh_token",
  'refresh_token' => "{$refresh_token}"
);

$access_token_url = 'https://cloud.minapp.com/api/oauth2/access_token/';
$access_token = postData($access_token_url, $param, 'application/json'); // 获取到的 Access Token

// 封装请求函数
function postData($url, $param, $content_type = 'application/json') {
  $ch = curl_init();

  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_POST, true);
  curl_setopt($ch, CURLOPT_POSTFIELDS, $param);
  curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);  // 设置允许重定向
  curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
  curl_setopt($ch, CURLOPT_COOKIEFILE, '');
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  curl_setopt($ch, CURLOPT_COOKIESESSION, true);
  curl_setopt($ch, CURLINFO_CONTENT_TYPE,  $content_type);  // 设置 Content-Type
  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);

  $response = curl_exec($ch);
  curl_close($ch);
  return $response;
}
```

> **danger** 开发者需要保证 **Access Token** 的安全性


---

# 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://ifanr.gitbook.io/baas-js-sdk/open-api/authentication.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.
