Go SDK 提供了 RegisterApp 方法,基于 OAuth 2.0 Device Authorization Grant(RFC 8628)协议实现一键创建应用。

调用该方法会返回一个验证链接,用户在飞书或 Lark 中打开该链接(或扫码)完成授权后,即可自动注册应用并获取凭据(App ID 和 App Secret),无需手动前往开发者后台创建。

查看源码:oapi-sdk-go

前提条件

  • 安装 oapi-sdk-go,且 SDK 版本为最新 v3 版本。
  go get github.com/larksuite/oapi-sdk-go/v3@latest

快速开始示例

package main

import (
    "context"
    "errors"
    "fmt"
    "time"

lark "github.com/larksuite/oapi-sdk-go/v3"
    "github.com/larksuite/oapi-sdk-go/v3/scene/registration"
)

func main() {
    ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute)
    defer cancel()

result, err := registration.RegisterApp(ctx, &registration.Options{
        OnQRCode: func(info *registration.QRCodeInfo) {
            fmt.Printf("open or scan this url: %s\n", info.URL)
            fmt.Printf("the link expires in %d seconds\n", info.ExpireIn)
        },
        OnStatusChange: func(info *registration.StatusChangeInfo) {
            // status: polling | slow_down | domain_switched
            fmt.Printf("registration status: %s", info.Status)
            if info.Interval > 0 {
                fmt.Printf(", next poll after %d seconds", info.Interval)
            }
            fmt.Println()
        },
    })
    if err != nil {
        var regErr *registration.RegisterAppError
        if errors.As(err, &regErr) {
            fmt.Printf("register app failed: code=%s, description=%s\n", regErr.Code, regErr.Description)
            return
        }
        panic(err)
    }

fmt.Println("App ID:", result.ClientID)
    fmt.Println("App Secret:", result.ClientSecret)

client := lark.NewClient(result.ClientID, result.ClientSecret)
    _ = client
}

自定义权限、事件、回调与更新已有应用

创建应用时,可通过 Options.Addons 在平台基础模板上增量申请权限、事件订阅和回调。这些配置会预填到用户扫码后的确认页中,用户确认后生效。Options.CreateOnly=true 时,页面只允许创建新应用;传入 Options.AppID 时,页面会进入更新已有应用配置的确认流程。

_, err := registration.RegisterApp(ctx, &registration.Options{
    Addons: &registration.AppAddons{
        Scopes: registration.AppAddonsScopes{
            Tenant: []string{"im:message:send_as_bot"},
            User:   []string{"calendar:calendar:read"},
        },
        Events: registration.AppAddonsEvents{
            Items: registration.AppAddonsEventItems{
                Tenant: []string{"im.message.receive_v1"},
            },
        },
        Callbacks: registration.AppAddonsCallbacks{
            Items: []string{"card.action.trigger"},
        },
    },
    CreateOnly: true,
    OnQRCode: func(info *registration.QRCodeInfo) {
        fmt.Println(info.URL)
    },
})
if err != nil {
    panic(err)
}

_, err = registration.RegisterApp(ctx, &registration.Options{
    AppID: "cli_xxx",
    Addons: &registration.AppAddons{
        Scopes: registration.AppAddonsScopes{
            Tenant: []string{"drive:drive.metadata:readonly"},
        },
    },
    OnQRCode: func(info *registration.QRCodeInfo) {
        fmt.Println(info.URL)
    },
})
if err != nil {
    panic(err)
}

注意:Addons 仅支持增量叠加,不支持删除基础模板中的配置;SDK 只校验数据形状和非空字符串,不校验权限点、事件或回调名称是否存在。

通过 Preset 选择模板底座

AppAddons.Preset 用于选择应用创建的模板底座(与 Options.AppPreset 无关,后者只预填应用名称、描述和头像):

取值 模板底座 行为
不设置(nil) 平台默认模板 与该字段出现之前完全一致;编码后的 payload 不含 preset 键。
false 最小基础模板 确认页只展示 Addons 中显式声明的权限、事件和回调。
true 平台默认模板 显式声明使用默认底座,效果与不设置相同。

Preset 为 false 时,允许 Addons 不携带任何权限、事件或回调——页面仍会进入确认流程,创建仅含最小底座能力的应用:

preset := false
_, err := registration.RegisterApp(ctx, &registration.Options{
    Addons: &registration.AppAddons{
        Preset: &preset,
    },
    OnQRCode: func(info *registration.QRCodeInfo) {
        fmt.Println(info.URL)
    },
})
if err != nil {
    panic(err)
}

registration.RegisterApp 参数

参数 描述 类型 必填 默认值
ctx 控制注册流程的超时与取消;取消 context 会终止轮询。 context.Context 是 -
Options.Source 来源标识,会拼入二维码 URL 的 source 参数,格式为 go-sdk/{source}。 string 否 go-sdk
Options.Domain 自定义飞书认证域名,支持传完整前缀,如 https://accounts.feishu.cn。 string 否 https://accounts.feishu.cn
Options.LarkDomain 自定义 Lark 认证域名;检测到 tenant_brand=lark 时自动切换。 string 否 https://accounts.larksuite.com
Options.AppPreset 预设应用信息,仅用于初始化创建页;用户仍可在页面修改,最终以页面提交为准。 *registration.AppPreset 否 -
Options.AppPreset.Avatar 应用头像 URL,支持 1-6 个;第一个默认选中。传原始 URL,SDK 会编码。头像展示、图片可访问性、GIF 取帧等由创建页处理。 []string 否 -
Options.AppPreset.Name 应用名称,支持 {user} 占位符;传原始值,SDK 会编码。 string 否 -
Options.AppPreset.Desc 应用描述,支持 {user} 占位符;传原始值,SDK 会编码。 string 否 -
Options.Addons 增量权限、事件、回调配置,预填到扫码后的确认页,用户确认后生效。 *registration.AppAddons 否 -
Options.Addons.Preset 模板底座选择:不设置为平台默认模板;false 为最小基础模板(此时允许增量为空);true 为显式声明默认底座。 *bool 否 -
Options.Addons.Scopes.Tenant 应用身份权限列表,如 im:message:send_as_bot。 []string 否 -
Options.Addons.Scopes.User 用户身份权限列表,如 calendar:calendar:read。 []string 否 -
Options.Addons.Events.Items.Tenant 应用身份事件列表,如 im.message.receive_v1。 []string 否 -
Options.Addons.Events.Items.User 用户身份事件列表,如 calendar.calendar.event.changed_v4。 []string 否 -
Options.Addons.Callbacks.Items 回调列表,如 card.action.trigger。 []string 否 -
Options.CreateOnly 为 true 时落地页仅允许创建新应用;与 Options.AppID 同时传入时,页面侧优先走新建流程。 bool 否 false
Options.AppID 已有应用的 App ID;传入后会作为二维码 URL 的 clientID 参数,用于更新已有应用配置。 string 否 -
Options.OnQRCode 验证链接就绪时的回调,参数为 { URL, ExpireIn }。可直接展示链接,或将其渲染为二维码供用户扫码。 func(info *registration.QRCodeInfo) 是 -
Options.OnStatusChange 轮询状态变化回调,参数为 { Status, Interval }。Status 可能为 polling、slow_down、domain_switched。 func(info *registration.StatusChangeInfo) 否 -

返回值

字段 类型 描述
ClientID string 应用的 App ID
ClientSecret string 应用的 App Secret
UserInfo *registration.UserInfo 扫码用户信息
UserInfo.OpenID string 扫码用户的 open_id
UserInfo.TenantBrand string "feishu" 或 "lark"

错误处理

返回的错误通常可以通过 errors.As(err, &registration.RegisterAppError) 获取 Code 与 Description 字段。更具体的错误类型还包括 registration.AccessDeniedError 和 registration.ExpiredError。

Code 描述
access_denied 用户拒绝授权
expired_token 二维码过期或轮询超时
invalid_response 接口返回缺少必要字段或响应为空