user_access_token.md 29 KB

获取 user_access_token

OAuth 令牌接口,可用于获取 user_access_token 以及 refresh_tokenuser_access_token 为用户访问凭证,使用该凭证可以以用户身份调用 OpenAPI。refresh_token 为刷新凭证,可以用来获取新的 user_access_token

请求

基本  
HTTP URL https://open.feishu.cn/open-apis/authen/v2/oauth/token
HTTP Method POST
接口频率限制 1000 次/分钟、50 次/秒
支持的应用类型 Custom App、Store App
权限要求
调用该 API 所需的权限。开启其中任意一项权限即可调用
字段权限要求 refresh_token 以及 refresh_token_expires_in 字段仅在具备以下权限时返回:
offline_access(offline_access)

请求头

名称 类型 必填 描述
Content-Type string 请求体类型。
固定值:application/json; charset=utf-8

请求体

名称 类型 必填 描述
grant_type string 授权类型。
固定值:authorization_code
client_id string 应用的 App ID。应用凭证 App ID 和 App Secret 获取方式:
1. 登录飞书开发者后台
2. 进入应用详情页,在左侧导航栏,单击 凭证与基础信息
3. 在 应用凭证 区域,获取并保存 App IDApp Secret
示例值:cli_a5ca35a685b0x26e
client_secret string 应用的 App Secret。应用凭证 App ID 和 App Secret 获取方式:
1. 登录飞书开发者后台
2. 进入应用详情页,在左侧导航栏,单击 凭证与基础信息
3. 在 应用凭证 区域,获取并保存 App IDApp Secret
示例值:baBqE5um9LbFGDy3X7LcfxQX1sqpXlwy
code string 授权码,详见获取授权码
示例值:a61hb967bd094dge949h79bbexd16dfe
redirect_uri string 在构造授权页页面链接时所拼接的应用回调地址。
示例值:https://example.com/api/oauth/callback
code_verifier string 在发起授权前,本地生成的随机字符串,用于 PKCE(Proof Key for Code Exchange)流程。使用 PKCE 时,该值为必填项。
有关 PKCE 的详细介绍,请参阅 RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients
长度限制: 最短 43 字符,最长 128 字符
可用字符集: [A-Z] / [a-z] / [0-9] / "-" / "." / "_" / "~"
示例值:TxYmzM4PHLBlqm5NtnCmwxMH8mFlRWl_ipie3O0aVzo
scope string 该参数用于缩减 user_access_token 的权限范围。
例如:
1. 在获取授权码时通过 scope 参数授权了 contact:user.base:readonly contact:contact.base:readonly contact:user.employee:readonly 三个权限。
2. 在当前接口可通过 scope 参数传入 contact:user.base:readonly,将 user_access_token 的权限缩减为 contact:user.base:readonly 这一个。
注意
- 如果不指定当前参数,生成的 user_access_token 将包含用户授权时的所有权限。
- 当前参数不能传入重复的权限,否则会接口调用会报错,返回错误码 20067。
- 当前参数不能传入未授权的权限(即获取授权码时用户已授权范围外的其他权限),否则接口调用会报错,返回错误码 20068。
- 多次调用当前接口缩减权限的范围不会叠加。例如,用户授予了权限 A 和 B,第一次调用该接口缩减为权限 A,则 user_access_token 只包含权限 A;第二次调用该接口缩减为权限 B,则 user_access_token 只包含权限 B。
- 生效的权限列表可通过本接口返回值 scope 查看。
格式要求: 以空格分隔的 scope 列表
示例值:auth:user.id:read task:task:read

请求体示例

{
    "grant_type": "authorization_code",
    "client_id": "cli_a5ca35a685b0x26e",
    "client_secret": "baBqE5um9LbFGDy3X7LcfxQX1sqpXlwy",
    "code": "a61hb967bd094dge949h79bbexd16dfe",
    "redirect_uri": "https://example.com/api/oauth/callback",
    "code_verifier": "TxYmzM4PHLBlqm5NtnCmwxMH8mFlRWl_ipie3O0aVzo"
}

响应

响应体类型为 application/json; charset=utf-8

响应体

注意事项响应体中的 access_tokenrefresh_token 长度较长,一般在 1~2KB 之间,且可能由于 scope 数量的变多或后续变更导致长度进一步增加,建议预留 4KB 的存储容量

名称 类型 描述
code int 错误码,为 0 时表明请求成功,非 0 表示失败,请参照下文错误码一节进行相应处理
access_token string user_access_token,仅在请求成功时返回
expires_in int user_access_token 的有效期,单位为秒,仅在请求成功时返回
注意事项:建议使用该字段以确定 user_access_token 的过期时间,不要硬编码有效期
refresh_token string 用于刷新 user_access_token,详见刷新 user_access_token。该字段仅在请求成功且用户授予 offline_access 权限时返回。
注意事项:如果你在获取 user_access_token 时设置了 scope 请求参数,且需要返回 refresh_token,则需要在 scope 参数中包括 offline_access。另外,refresh_token 仅能被使用一次。
refresh_token_expires_in int refresh_token 的有效期,单位为秒,仅在返回 refresh_token 时返回。
注意事项:建议在到期前调用刷新 user_access_token 接口获取新的 refresh_token
token_type string 值固定为 Bearer,仅在请求成功时返回
scope string 本次请求所获得的 access_token 所具备的权限列表,以空格分隔,仅在请求成功时返回
error string 错误类型,仅在请求失败时返回
error_description string 具体的错误信息,仅在请求失败时返回

响应体示例

成功响应示例:

{
    "code": 0,
    "access_token": "eyJhbGciOiJFUzI1NiIs**********X6wrZHYKDxJkWwhdkrYg",
    "expires_in": 7200, // 非固定值,请务必根据响应体中返回的实际值来确定 access_token 的有效期
    "refresh_token": "eyJhbGciOiJFUzI1NiIs**********XXOYOZz1mfgIYHwM8ZJA",
    "refresh_token_expires_in": 604800, // 非固定值,请务必根据响应体中返回的实际值来确定 refresh_token 的有效期
    "scope": "auth:user.id:read offline_access task:task:read user_profile",
    "token_type": "Bearer"
}

失败响应示例:

{
    "code": 20050,
    "error": "server_error",
    "error_description": "An unexpected server error occurred. Please retry your request."
}

错误码

HTTP 状态码 错误码 描述 排查建议
400 20001 The request is missing a required parameter. 必要参数缺失,请检查请求时传入的参数是否有误
400 20002 The client secret is invalid. 应用认证失败,请检查提供的 client_idclient_secret 是否正确
400 20003 The authorization code is not found. Please note that an authorization code can only be used once. 无效的授权码,请检查授权码是否有效,注意授权码仅能使用一次
400 20004 The authorization code has expired. 授权码已经过期,请在授权码生成后的 5 分钟内使用
400 20008 The user does not exist. 用户不存在,请检查发起授权的用户的当前状态
400 20009 The specified app is not installed. 租户未安装应用,请检查应用状态
400 20010 The user does not have permission to use this app. 用户无应用使用权限,请检查发起授权的用户是否仍具有应用使用权限
400 20024 The provided authorization code or refresh token does not match the provided client ID. 提供的授权码与 client_id 不匹配,请勿混用不同应用的凭证
400 20036 The specified grant_type is not supported. 无效的 grant_type,请检查请求体中 grant_type 字段的取值
400 20048 The specified app does not exist. 应用不存在,请检查应用状态
400 20049 PKCE code challenge failed. PKCE 校验失败,请检查请求体中 code_verifier 字段是否存在且有效
500 20050 An unexpected server error occurred. Please retry your request. 内部服务错误,请稍后重试,如果持续报错请联系技术支持
400 20063 The request is malformed. Please check your request. 请求体中缺少必要字段,请根据具体的错误信息补齐字段
400 20065 The authorization code has been used. Please note that an authorization code can only be used once. 授权码已被使用,授权码仅能使用一次,请检查是否有被重复使用
400 20066 The user status is invalid. 用户状态非法,请检查发起授权的用户的当前状态
400 20067 The provided scope list contains duplicate scopes. Please ensure all scopes are unique. 无效的 scope 列表,其中存在重复项,请确保传入的 scope 列表中没有重复项
400 20068 The provided scope list contains scopes that are not permitted. Please ensure all scopes are allowed. 无效的 scope 列表,其中存在用户未授权的权限。当前接口 scope 参数传入的权限必须是获取授权码scope 参数值的子集。
例如,在获取授权码时,用户授权了权限 A、B,则当前接口 scope 可传入的值只有权限 A、B,若传入权限 C 则会返回当前错误码。
400 20069 The specified app is not enabled. 应用未启用,请检查应用状态
400 20070 Multiple authentication methods were provided. Please only use one to proceed. 请求时同时使用了 Basic Authenticationclient_secret 两种身份验证方式。请仅使用 client_idclient_secret 身份验证方式调用本接口。
400 20071 The provided redirect URI does not match the one used during authorization. 无效的 redirect_uri,请确保 redirect_uri获取授权码时传入的 redirect_uri 保持一致
503 20072 The server is temporarily unavailable. Please retry your request. 服务暂不可用,请稍后重试

代码示例

注意事项:此处提供的代码示例仅供参考,请勿直接在生产环境使用

Golang

运行下面示例程序的步骤:

  1. 点击下方代码块右上角复制按钮,将代码复制到本地文件中,保存为 main.go
  2. 参照注释部分,完成配置;
  3. main.go 所在目录下新建 .env 文件,内容如下:

    APP_ID=cli_xxxxxx # 仅为示例值,请使用你的应用的 App ID,获取方式:开发者后台 -> 基础信息 -> 凭证与基础信息 -> 应用凭证 -> App ID
    APP_SECRET=xxxxxx # 仅为示例值,请使用你的应用的 App Secret,获取方式:开发者后台 -> 基础信息 -> 凭证与基础信息 -> 应用凭证 -> App Secret
    
  4. main.go 所在目录执行以下命令:

    go mod init oauth-test
    go get github.com/gin-gonic/gin
    go get github.com/gin-contrib/sessions
    go get github.com/gin-contrib/sessions/cookie
    go get github.com/joho/godotenv
    go get golang.org/x/oauth2
    go run main.go
    
  5. 浏览器打开 http://localhost:8080 ,按照页面提示完成授权流程;

    package main
    
    import (
    "context"
    "encoding/json"
    "fmt"
    "log"
    "math/rand"
    "net/http"
    "os"
    
    "github.com/gin-contrib/sessions"
    "github.com/gin-contrib/sessions/cookie"
    "github.com/gin-gonic/gin"
    _ "github.com/joho/godotenv/autoload"
    "golang.org/x/oauth2"
    )
    
    var oauthEndpoint = oauth2.Endpoint{
    AuthURL:  "https://accounts.feishu.cn/open-apis/authen/v1/authorize",
    TokenURL: "https://open.feishu.cn/open-apis/authen/v2/oauth/token",
    }
    
    var oauthConfig = &oauth2.Config{
    ClientID:     os.Getenv("APP_ID"),
    ClientSecret: os.Getenv("APP_SECRET"),
    RedirectURL:  "http://localhost:8080/callback", // 请先添加该重定向 URL,配置路径:开发者后台 -> 开发配置 -> 安全设置 -> 重定向 URL -> 添加
    Endpoint:     oauthEndpoint,
    Scopes:       []string{"offline_access"}, // 如果你不需要 refresh_token,请注释掉该行,否则你需要先申请 offline_access 权限方可使用,配置路径:开发者后台 -> 开发配置 -> 权限管理      
    }
    
    func main() {
    r := gin.Default()
    
    // 使用 Cookie 存储 session
    store := cookie.NewStore([]byte("secret")) // 此处仅为示例,务必不要硬编码密钥
    r.Use(sessions.Sessions("mysession", store))
    
    r.GET("/", indexController)
    r.GET("/login", loginController)
    r.GET("/callback", oauthCallbackController)
    
    fmt.Println("Server running on http://localhost:8080")
    log.Fatal(r.Run(":8080"))
    }
    
    func indexController(c *gin.Context) {
    c.Header("Content-Type", "text/html; charset=utf-8")
    var username string
    session := sessions.Default(c)
    if session.Get("user") != nil {
       username = session.Get("user").(string)
    }
    html := fmt.Sprintf(`<html><head><style>body{font-family:Arial,sans-serif;background:#f4f4f4;margin:0;display:flex;justify-content:center;align-items:center;height:100vh}.container{text-align:center;background:#fff;padding:30px;border-radius:10px;box-shadow:0 0 10px rgba(0,0,0,0.1)}a{padding:10px 20px;font-size:16px;color:#fff;background:#007bff;border-radius:5px;text-decoration:none;transition:0.3s}a:hover{background:#0056b3}}</style></head><body>[返回主页](/)
    </body></html>`, user.Data.Name)
    c.String(http.StatusOK, html)
    }
    

刷新 user_access_token

OAuth 令牌接口,可用于刷新 user_access_token 以及获取新的 refresh_token

  • user_access_token 为用户访问凭证,使用该凭证可以以用户身份调用 OpenAPI,该凭证存在有效期,可通过 refresh_token 进行刷新。
  • 用户授权时,用户必须拥有应用的使用权限,否则调用本接口将会报错误码 20010。
  • refresh_token 用于获取新的 user_access_token,且仅能使用一次。在获取新的 user_access_token 时会返回新的 refresh_token,原 refresh_token 立即失效。

  • 首次获取 refresh_token 的方式参见获取 user_access_token注意事项:本接口实现遵循 RFC 6749 - The OAuth 2.0 Authorization Framework ,你可以使用标准的 OAuth 客户端库进行接入(推荐

前置工作

开通 offline_access 权限

获取 refresh_token 需前往开放平台应用后台的权限管理模块开通 offline_access 权限,并在发起授权时在 scope 参数中声明该权限。

开通 offline_access 权限.png

在开通 offline_access 权限后,如需获取 refresh_token,具体的请求参数设置如下:

  1. 首先在发起授权时,授权链接的scope 参数中必须拼接 offline_access,例如:

    https://accounts.feishu.cn/open-apis/authen/v1/authorize?client_id=cli_a5d611352af9d00b&redirect_uri=https%3A%2F%2Fexample.com%2Fapi%2Foauth%2Fcallback&scope=bitable:app:readonly%20offline_access
    
  2. 获取 user_access_token时,

    • 如果不需要缩减权限,即该接口的 scope 参数为空,则无需做其他操作,即可正常获得 refresh_token
    • 如果需要缩减权限,即该接口的 scope 参数不为空,
      • 且需要获取 refresh_token,则此处的 scope 参数中需要拼接 offline_access
      • 如不需要获取 refresh_token,则无需特殊处理;
  3. 刷新 user_access_token时,同第二步的逻辑。

开启刷新 user_access_token 的安全设置

注意事项:- 如果你看不到此开关则无需关注,其默认处于开启状态。

前往开放平台应用后台的安全设置模块,打开刷新 user_access_token 的开关。

开启刷新 user_access_token 的安全设置.png

请求

注意事项:为了避免刷新 user_access_token 的行为被滥用,在用户授权应用 365 天后,应用必须通过用户重新授权的方式来获取 user_access_tokenrefresh_token。如果 refresh_token 到期后继续刷新user_access_token将报错(错误码为 20037),可参考以下错误码描述信息进行处理。 注意事项:刷新后请更新本地 user_access_tokenrefresh_token,原令牌将无法再使用(user_access_token 会有一分钟的豁免时间以供应用完成令牌轮转)。

基本  
HTTP URL https://open.feishu.cn/open-apis/authen/v2/oauth/token
HTTP Method POST
接口频率限制 1000 次/分钟、50 次/秒
支持的应用类型 Custom App、Store App
权限要求
调用该 API 所需的权限。开启其中任意一项权限即可调用
字段权限要求 refresh_token 以及 refresh_token_expires_in 字段仅在具备以下权限时返回:
offline_access(offline_access)

请求头

名称 类型 必填 描述
Content-Type string 请求体类型。
固定值:application/json; charset=utf-8

请求体

名称 类型 必填 描述
grant_type string 授权类型。
固定值:refresh_token
client_id string 应用的 App ID,可以在开发者后台中的应用详情页面找到该值。
示例值:cli_a5ca35a685b0x26e
client_secret string 应用的 App Secret,可以在开发者后台中的应用详情页面找到该值,详见:如何获取应用的 App ID
示例值:baBqE5um9LbFGDy3X7LcfxQX1sqpXlwy
refresh_token string 刷新令牌,用于刷新 user_access_token 以及 refresh_token
注意事项:请务必注意本接口仅支持获取 user_access_token刷新 user_access_token接口返回的 refresh_token
示例值:eyJhbGciOiJFUzI1NiIs**********XXOYOZz1mfgIYHwM8ZJA
scope string 该参数用于缩减 user_access_token 的权限范围。
例如:
1. 在获取授权码时通过 scope 参数授权了 contact:user.base:readonly contact:contact.base:readonly contact:user.employee:readonly 三个权限。
2. 在当前接口可通过 scope 参数传入 contact:user.base:readonly,将 user_access_token 的权限缩减为 contact:user.base:readonly 这一个。
注意
- 如果不指定当前参数,生成的 user_access_token 将包含用户授权时的所有权限。
- 当前参数不能传入重复的权限,否则会接口调用会报错,返回错误码 20067。
- 当前参数不能传入未授权的权限(即获取授权码时用户已授权范围外的其他权限),否则接口调用会报错,返回错误码 20068。
- 多次调用当前接口缩减权限的范围不会叠加。例如,用户授予了权限 A 和 B,第一次调用该接口缩减为权限 A,则 user_access_token 只包含权限 A;第二次调用该接口缩减为权限 B,则 user_access_token 只包含权限 B。
- 生效的权限列表可通过本接口返回值 scope 查看。
格式要求: 以空格分隔的 scope 列表
示例值:auth:user.id:read task:task:read

请求体示例

{
    "grant_type": "refresh_token",
    "client_id": "cli_a5ca35a685b0x26e",
    "client_secret": "baBqE5um9LbFGDy3X7LcfxQX1sqpXlwy",
    "refresh_token": "eyJhbGciOiJFUzI1NiIs**********XXOYOZz1mfgIYHwM8ZJA"
}

响应

响应体类型为 application/json; charset=utf-8

响应体

名称 类型 描述
code int 错误码,为 0 时表明请求成功,非 0 表示失败,请参照下文错误码一节妥善处理
access_token string user_access_token,仅在请求成功时返回
expires_in int user_access_token 的有效期,单位为秒,仅在请求成功时返回
注意事项:建议使用该字段以确定 user_access_token 的过期时间,不要硬编码有效期
refresh_token string 用于刷新 user_access_token,该字段仅在请求成功且用户授予 offline_access 权限时返回:
offline_access(offline_access)
注意事项:如果你在获取 user_access_token 时设置了 scope 请求参数,且需要返回 refresh_token,则需要在 scope 参数中包括 offline_access。另外,refresh_token 仅能被使用一次。
refresh_token_expires_in int refresh_token 的有效期,单位为秒,仅在返回 refresh_token 时返回。
注意事项:建议在到期前重新调用当前接口获取新的 refresh_token
token_type string 值固定为 Bearer,仅在请求成功时返回
scope string 本次请求所获得的 access_token 所具备的权限列表,以空格分隔,仅在请求成功时返回
error string 错误类型,仅在请求失败时返回
error_description string 具体的错误信息,仅在请求失败时返回

响应体示例

成功响应示例:

{
    "code": 0,
    "access_token": "eyJhbGciOiJFUzI1NiIs**********X6wrZHYKDxJkWwhdkrYg",
    "expires_in": 7200, // 非固定值,请务必根据响应体中返回的实际值来确定 access_token 的有效期
    "refresh_token": "eyJhbGciOiJFUzI1NiIs**********VXOYOZYZmfgIYHWM0ZJA",
    "refresh_token_expires_in": 604800, // 非固定值,请务必根据响应体中返回的实际值来确定 refresh_token 的有效期
    "scope": "auth:user.id:read offline_access task:task:read user_profile",
    "token_type": "Bearer"
}

失败响应示例:

{
    "code": 20050,
    "error": "server_error",
    "error_description": "An unexpected server error occurred. Please retry your request."
}

错误码

HTTP 状态码 错误码 描述 排查建议
400 20001 The request is missing a required parameter. 必要参数缺失,请检查请求时传入的参数是否有误
400 20002 The client secret is invalid. 应用认证失败,请检查提供的 client_idclient_secret 是否正确。获取方式参见 如何获取应用的 App ID
400 20008 The user does not exist. 用户不存在,请检查发起授权的用户的当前状态
400 20009 The specified app is not installed. 租户未安装应用,请检查应用状态
400 20010 The user does not have permission to use this app. 用户无应用使用权限,请检查发起授权的用户是否仍具有应用使用权限
400 20024 The provided authorization code or refresh token does not match the provided client ID. 提供的 refresh_tokenclient_id 不匹配,请勿混用不同应用的凭证
400 20026 The refresh token passed is invalid. Please check the value. 请检查请求体中 refresh_token 字段的取值
请注意本接口仅支持 v2 版本接口下发的 refresh_token
400 20036 The specified grant_type is not supported. 无效的 grant_type,请检查请求体中 grant_type 字段的取值
400 20037 The refresh token passed has expired. Please generate a new one. refresh_token 已过期,请重新发起授权流程以获取新的 refresh_token
400 20048 The specified app does not exist. 应用不存在,请检查应用状态
500 20050 An unexpected server error occurred. Please retry your request. 内部服务错误,请稍后重试,如果持续报错请联系技术支持
400 20063 The request is malformed. Please check your request. 请求体中缺少必要字段,请根据具体的错误信息补齐字段
400 20064 The refresh token has been revoked. Please note that a refresh token can only be used once. refresh_token 已被撤销,请重新发起授权流程以获取新的 refresh_token
400 20066 The user status is invalid. 用户状态非法,请检查发起授权的用户的当前状态
400 20067 The provided scope list contains duplicate scopes. Please ensure all scopes are unique. 无效的 scope 列表,其中存在重复项,请确保传入的 scope 列表中没有重复项
400 20068 The provided scope list contains scopes that are not permitted. Please ensure all scopes are allowed. 无效的 scope 列表,其中存在用户未授权的权限。当前接口 scope 参数传入的权限必须是获取授权码scope 参数值的子集。
例如,在获取授权码时,用户授权了权限 A、B,则当前接口 scope 可传入的值只有权限 A、B,若传入权限 C 则会返回当前错误码。
400 20069 The specified app is not enabled. 应用未启用,请检查应用状态
400 20070 Multiple authentication methods were provided. Please only use one to proceed. 请求时同时使用了 Basic Authenticationclient_secret 两种身份验证方式。请仅使用 client_idclient_secret 身份验证方式调用本接口。
503 20072 The server is temporarily unavailable. Please retry your request. 服务暂不可用,请稍后重试
400 20073 The refresh token has been used. Please note that a refresh token can only be used once. 重新发起授权流程以获取新的 refresh_token
400 20074 The specified app is not allowed to refresh token. 请在应用管理后台检查是否开启了刷新 user_access_token 开关,注意发版后生效