> ## Documentation Index
> Fetch the complete documentation index at: https://docs.profy.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 交换 Token

> Supports both application/json and application/x-www-form-urlencoded. Use `grant_type=authorization_code` to exchange an auth code, or `grant_type=refresh_token` to refresh an expired access token.

<Note>
  `client_id` 和 `client_secret` 必须在请求体中传递，不支持 Basic Auth Header。
</Note>

## 使用场景

### 1. 用授权码换取 Token

用户在授权页面同意后，你的 `redirect_uri` 会收到 `code` 参数。用它换取 access token：

```bash theme={null}
curl --request POST \
  --url https://app.profy.cn/oauth/token \
  --header 'Content-Type: application/json' \
  --data '{
    "grant_type": "authorization_code",
    "code": "从回调 URL 拿到的授权码",
    "redirect_uri": "https://your-app.com/callback",
    "client_id": "你的应用 UUID",
    "client_secret": "你的应用密钥"
  }'
```

### 2. 用 Refresh Token 续期

Access token 有效期 1 小时。过期后用 refresh token 获取新的 token 对：

```bash theme={null}
curl --request POST \
  --url https://app.profy.cn/oauth/token \
  --header 'Content-Type: application/json' \
  --data '{
    "grant_type": "refresh_token",
    "refresh_token": "之前获取的 refresh_token",
    "client_id": "你的应用 UUID",
    "client_secret": "你的应用密钥"
  }'
```

<Warning>
  Refresh token 每次使用后会自动轮换（rotation），旧 token 立即失效。请务必保存响应中返回的新 `refresh_token`。
</Warning>

## 常见错误

| 错误                                      | 原因                                   |
| --------------------------------------- | ------------------------------------ |
| `Missing client credentials`            | 请求体缺少 `client_id` 或 `client_secret`  |
| `Invalid client credentials`            | `client_id` 不存在或 `client_secret` 不匹配 |
| `Invalid or expired authorization code` | 授权码已过期（5 分钟有效）或已被使用                  |
| `redirect_uri mismatch`                 | `redirect_uri` 与授权请求时的不一致            |
| `Invalid or expired refresh token`      | Refresh token 无效、已过期（90 天）或已被轮换      |


## OpenAPI

````yaml POST /oauth/token
openapi: 3.0.0
info:
  title: Profy App API
  version: 1.0.0
  description: OAuth 2.0 and Events API for Profy App integrations.
servers:
  - url: https://app.profy.cn
    description: Production
security: []
paths:
  /oauth/token:
    post:
      tags:
        - OAuth
      summary: Exchange authorization code or refresh token for access token
      description: >-
        Supports both application/json and application/x-www-form-urlencoded.
        Use `grant_type=authorization_code` to exchange an auth code, or
        `grant_type=refresh_token` to refresh an expired access token.
      operationId: postOAuthToken
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                grant_type:
                  type: string
                  enum:
                    - authorization_code
                    - refresh_token
                  description: OAuth grant type
                code:
                  type: string
                  description: >-
                    Authorization code from the callback redirect (required when
                    grant_type=authorization_code)
                redirect_uri:
                  type: string
                  description: >-
                    Must exactly match the redirect_uri used in the
                    authorization request (required when
                    grant_type=authorization_code)
                  example: https://your-app.com/callback
                client_id:
                  type: string
                  description: Your application UUID
                  example: your-app-uuid
                client_secret:
                  type: string
                  description: Your application secret (plaintext)
                refresh_token:
                  type: string
                  description: >-
                    Refresh token from a prior token response (required when
                    grant_type=refresh_token)
              required:
                - grant_type
                - client_id
                - client_secret
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                grant_type:
                  type: string
                  enum:
                    - authorization_code
                    - refresh_token
                code:
                  type: string
                redirect_uri:
                  type: string
                client_id:
                  type: string
                client_secret:
                  type: string
                refresh_token:
                  type: string
              required:
                - grant_type
                - client_id
                - client_secret
      responses:
        '200':
          description: Token pair issued
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                  token_type:
                    type: string
                    example: Bearer
                  expires_in:
                    type: number
                    example: 3600
                  refresh_token:
                    type: string
                  scope:
                    type: string
                required:
                  - access_token
                  - token_type
                  - expires_in
                  - refresh_token
                  - scope
        '400':
          description: Invalid grant or request
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: invalid_client
                  error_description:
                    type: string
                    example: Missing client credentials
                required:
                  - error
        '401':
          description: Invalid client credentials
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                    example: invalid_client
                  error_description:
                    type: string
                    example: Missing client credentials
                required:
                  - error

````