Activepieces Piece 认证模式全解析:SecretText、OAuth2、Basic、CustomAuth 与连接标识符实战指南
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
导读
在 Activepieces 中开发一个 Piece(集成组件)时,认证(Authentication)定义是决定连接体验与安全性的第一道关卡。无论是对接只签发单个 API Key 的简单服务,还是需要 OAuth2 授权码流程的 Google、Slack,抑或是需要「实例 URL + 账号密码」组合登录的企业自托管系统,Piece 框架都提供了对应的认证类型。本文基于仓库中的认证模式指南(.agents/skills/piece-builder/auth-patterns.md),逐一讲解PieceAuth的六种认证形态——SecretText、OAuth2、BasicAuth、CustomAuth(含 Token 刷新)、连接标识符getConnectionIdentifier与None,并结合仓库内真实 Piece 源码与框架底层实现,说明每种模式在validate校验、action/trigger 运行时读取凭据的具体写法,帮助你在构建 Piece 时选出正确模式并写出可上线的认证代码。
一、认证体系概览:PieceAuth提供的六种形态
从框架源码 packages/pieces/framework/src/lib/property/authentication/index.ts 可以看到,PieceAuth暴露了五个构造器(SecretText、OAuth2、BasicAuth、CustomAuth、OIDC)以及返回undefined的None(),它们分别对应PropertyType中的不同枚举值,最终在连接(App Connection)层映射为AppConnectionType中的SECRET_TEXT、OAUTH2、BASIC_AUTH、CUSTOM_AUTH、OIDC、NO_AUTH。
本指南覆盖其中六种最常用的模式,核心差异在于用户需要输入什么、凭据以什么形态出现在validate与 action/trigger 上下文中:
| 认证模式 | 适用场景 | validate回调中的auth形态 | action/trigger 中的读取方式 |
|---|---|---|---|
SecretText | 单一 API Key / Token | 普通字符串 | context.auth.secret_text |
OAuth2 | 授权码流程(Google、Slack、GitHub 等) | 完整连接对象 | context.auth.access_token、context.auth.props、context.auth.data |
BasicAuth | 用户名 + 密码 | 扁平对象 | context.auth.username、context.auth.password |
CustomAuth | 多字段组合(URL + Key、区域 + 凭据等) | 扁平 props 对象 | context.auth.props.<field> |
| CustomAuth + refresh | 短时 Token(登录换 JWT) | 扁平 props 对象 | context.auth.access_token(服务端缓存) |
None | 公共 API / 工具类 Piece | 无 | context.auth不可用 |
说明:
OIDC也是框架内置的认证类型(见 oidc-prop.ts),本指南聚焦认证模式文档主讲的六种常用形态。
二、SecretText:最常见的单 Key 认证
2.1 定义与校验
SecretText是最常用的认证类型,适用于签发单个 API Key 或 Token 的简单 API。在validate回调中,auth就是一个普通字符串;而在 action/trigger 中,它是完整的连接对象,需要通过context.auth.secret_text读取密钥。
import { PieceAuth } from '@activepieces/pieces-framework'; import { httpClient, HttpMethod } from '@activepieces/pieces-common'; export const myAppAuth = PieceAuth.SecretText({ displayName: 'API Key', description: 'Get your API key from https://app.example.com/settings/api', required: true, validate: async ({ auth }) => { try { await httpClient.sendRequest({ method: HttpMethod.GET, url: 'https://api.example.com/v1/me', headers: { Authorization: `Bearer ${auth}` }, }); return { valid: true }; } catch (e) { return { valid: false, error: 'Invalid API Key' }; } }, });action/trigger 中读取密钥:
async run(context) { const apiKey = context.auth.secret_text; // ... }2.2 底层类型与框架行为
从框架源码 secret-text-property.ts 看,SecretTextProperty的值结构被定义为{ auth: z.string() },PieceAuth.SecretText仅补充type: PropertyType.SECRET_TEXT后返回。required泛型参数会直接决定SecretTextProperty<true>/SecretTextProperty<false>的类型,从而影响context.auth.secret_text是否可能为undefined。
2.3 真实案例:Stripe
仓库内 Stripe Piece 的认证正是这一模式的代表(packages/pieces/community/stripe/src/index.ts):用户在 Stripe 控制台获取Secret API Key后填入连接,validate通过请求https://api.stripe.com/v1/customers验证密钥有效性,失败时返回Invalid API Key. Please check the key and try again.。而其自定义 API 调用动作(createCustomApiCallAction)的authMapping中,读取的正是auth.secret_text:
createCustomApiCallAction({ baseUrl: () => 'https://api.stripe.com/v1', auth: stripeAuth, authMapping: async (auth) => ({ Authorization: `Bearer ${auth.secret_text}`, }), })这条真实代码同时印证了本指南的核心规则:validate里是裸字符串,action 里是完整连接对象。
三、OAuth2:标准授权码流程
3.1 基础配置
对于 Google、Slack、GitHub 这类走 OAuth2 授权流程的服务,使用PieceAuth.OAuth2:
import { PieceAuth } from '@activepieces/pieces-framework'; export const myAppAuth = PieceAuth.OAuth2({ required: true, authUrl: 'https://app.example.com/oauth/authorize', tokenUrl: 'https://app.example.com/oauth/token', scope: ['read', 'write'], // 可选配置: // pkce: true, // pkceMethod: 'S256', // prompt: 'consent', // grantType: OAuth2GrantType.AUTHORIZATION_CODE, // authorizationMethod: OAuth2AuthorizationMethod.HEADER, // extra: { audience: 'https://api.example.com' }, });3.2 可选参数详解
对照框架源码 oauth2-prop.ts,OAuth2支持以下可选参数:
pkce/pkceMethod:是否启用 PKCE(Proof Key for Code Exchange),pkceMethod取值为plain或S256,S256 是更安全的推荐值;prompt:授权页提示行为,取值none、consent、login、omit(omit表示不发送 prompt 参数);grantType:授权类型,来自@activepieces/core-piece-types的OAuth2GrantType枚举(如AUTHORIZATION_CODE、CLIENT_CREDENTIALS),还支持BOTH_CLIENT_CREDENTIALS_AND_AUTHORIZATION_CODE这种「两种都允许」的组合值;authorizationMethod:client_id/client_secret 的传递方式,OAuth2AuthorizationMethod.HEADER(放进请求头)或BODY(放进请求体),枚举定义见同一文件的第 11-14 行;extra:需要额外传给 token 端点的键值对(如某些服务要求的audience)。
3.3 在 action/trigger 中读取
OAuth2 连接对象包含三部分:
context.auth.access_token—— OAuth2 access token;context.auth.props?.['<key>']—— 当认证定义了额外props(如数据中心、区域、子域)时的取值;context.auth.data—— 提供商返回的原始 token 响应(含 refresh token、scope 等)。
async run(context) { const token = context.auth.access_token; const region = context.auth.props?.['region'] as string; // ... }这三部分的类型定义见 oauth2-prop.ts 中的OAuth2PropertyValue:{ access_token: string; props?: ...; data: Record<string, any> }。注意data是「原始响应」——例如 Slack 的data.team、data.authed_user都来自这里。
3.4 自定义 API 调用动作中的类型推断
在createCustomApiCallAction中,只要把auth声明为myAppAuth,authMapping回调的auth参数就已经具备正确类型,无需任何类型断言,直接读取auth.access_token即可:
createCustomApiCallAction({ baseUrl: () => 'https://api.example.com', auth: myAppAuth, authMapping: async (auth) => ({ Authorization: `Bearer ${auth.access_token}`, }), })3.5 真实案例:GitHub 与 Zoho Campaigns
- GitHub(packages/pieces/community/github/src/index.ts):标准 OAuth2 授权码流程的典型实现;
- Zoho Campaigns(packages/pieces/community/zoho-campaigns/):OAuth2配合额外
props的案例——用户需要选择数据中心/区域,代码通过context.auth.props读取。
四、BasicAuth:用户名 + 密码
适用于使用 username/password 认证的 API:
import { PieceAuth } from '@activepieces/pieces-framework'; import { httpClient, HttpMethod, AuthenticationType } from '@activepieces/pieces-common'; export const myAppAuth = PieceAuth.BasicAuth({ displayName: 'Connection', required: true, username: { displayName: 'Username', description: 'Your account username', }, password: { displayName: 'Password', description: 'Your account password', }, validate: async ({ auth }) => { try { await httpClient.sendRequest({ method: HttpMethod.GET, url: 'https://api.example.com/v1/me', authentication: { type: AuthenticationType.BASIC, username: auth.username, password: auth.password, }, }); return { valid: true }; } catch (e) { return { valid: false, error: 'Invalid credentials' }; } }, });action/trigger 中读取:
const username = context.auth.username; const password = context.auth.password;框架源码 basic-auth-prop.ts 中,BasicAuthProperty的值结构为{ username: string; password: string }。注意PieceAuth.BasicAuth在 index.ts 中强制required: true——BasicAuth 不允许可选,连接必须同时提供用户名和密码。
在validate中做真实校验时,推荐使用httpClient的authentication字段并指定AuthenticationType.BASIC,由 HTTP 客户端负责生成Authorization: Basic <base64>头,避免手写编码出错。
五、CustomAuth:多字段组合认证
5.1 基本形态
当 API 需要多个字段才能完成认证——例如「实例 URL + API Key」或「区域 + 凭据」——使用PieceAuth.CustomAuth:
import { PieceAuth, Property } from '@activepieces/pieces-framework'; export const myAppAuth = PieceAuth.CustomAuth({ displayName: 'Connection', required: true, props: { base_url: Property.ShortText({ displayName: 'Instance URL', description: 'e.g. https://mycompany.example.com', required: true, }), api_key: PieceAuth.SecretText({ displayName: 'API Key', required: true, }), }, validate: async ({ auth }) => { try { await httpClient.sendRequest({ method: HttpMethod.GET, url: `${auth.base_url}/api/v1/me`, headers: { Authorization: `Bearer ${auth.api_key}` }, }); return { valid: true }; } catch (e) { return { valid: false, error: 'Invalid connection details' }; } }, });5.2 关键差异:validate扁平、action 嵌套
CustomAuth 最容易踩坑的点是两处auth形态不同:
- 在
validate回调中,收到的是扁平形状——直接auth.base_url、auth.api_key; - 在 action/trigger 中,字段挂在
props下——必须用context.auth.props.base_url、context.auth.props.api_key。
async run(context) { const baseUrl = context.auth.props.base_url; const apiKey = context.auth.props.api_key; // ... }5.3 允许的 props 类型
从框架源码 custom-auth-prop.ts 的CustomAuthProps联合类型可见,CustomAuth 的 props 支持:
ShortText、LongText、SecretText、Number、Checkbox、StaticDropdown、StaticMultiSelectDropdown、MarkDown
其中SecretText用于密码/密钥类字段(输入框会打码),StaticDropdown/StaticMultiSelectDropdown用于固定选项,MarkDown可用于在连接表单里插入说明文案。
5.4 真实案例:WordPress 与 Mattermost
- WordPress(packages/pieces/community/wordpress/src/index.ts):实例 URL + 用户名 + 应用密码(Application Password)组合的典型 CustomAuth;
- Mattermost(packages/pieces/community/mattermost/src/index.ts):服务器 URL + 个人访问令牌(PAT)的组合。
这两个例子都体现了 CustomAuth 的价值:把「连接哪个实例」和「用谁的凭据」两个信息封装在同一个连接对象里。
六、CustomAuth + Token 刷新:避免 429 的关键
6.1 为什么需要 refresh
当 API 要求先用「用户名/密码」调用登录接口换取**短时 Token(如 JWT)**时,如果不做缓存,每个 action 执行都会触发一次登录请求——高频率工作流会迅速打爆限流,产生429 Rate Limit 错误。
解决方案是在 CustomAuth 上增加refresh字段,让Activepieces 在服务端缓存 Token 并自动续期:Token 会在过期前 15 分钟自动刷新(对短时 Token,刷新时机被钳制(clamped)在其生命周期的一半以内,避免每次调用都刷新)。
export const myAppAuth = PieceAuth.CustomAuth({ displayName: 'Connection', required: true, props: { baseUrl: Property.ShortText({ displayName: 'Instance URL', required: true }), username: Property.ShortText({ displayName: 'Username', required: true }), password: PieceAuth.SecretText({ displayName: 'Password', required: true }), }, validate: async ({ auth }) => { // validate as usual }, refresh: { generate: async ({ auth }) => { // auth 是扁平 props 形状:auth.baseUrl、auth.username 等 const res = await httpClient.sendRequest<{ token: string }>({ method: HttpMethod.POST, url: `${auth.baseUrl}/api/auth/login`, body: { username: auth.username, password: auth.password }, }); return { access_token: res.body.token, // expires_in: 3600, // 可选,单位秒——API 不返回过期时间时可省略 }; }, defaultExpiresIn: 3300, // 兜底 TTL(秒),默认 3300 = 55 分钟 }, });6.2 运行时读取
在 action/trigger 中,context.auth.access_token保存的是服务端缓存的 Token,此处不会触发登录请求;原始凭据字段仍通过context.auth.props.<field>读取:
async run(context) { const token = context.auth.access_token; // 服务端缓存,不会在这里调用登录接口 const baseUrl = context.auth.props.baseUrl; await httpClient.sendRequest({ method: HttpMethod.GET, url: `${baseUrl}/api/resource`, headers: { Authorization: `Bearer ${token}` }, }); }6.3 refresh 的底层语义
框架类型定义 custom-auth-prop.ts 对CustomAuthRefresh给出了精确语义:
generate接收{ auth: StaticPropsValue<T>; server },auth是扁平的 props 值,返回{ access_token: string; expires_in?: number };expires_in:Token 生命周期(秒)。省略时使用defaultExpiresIn(或框架默认值);设为0表示永不过期,Token 会被无限期缓存、不再刷新;defaultExpiresIn:当generate未返回expires_in时的兜底 TTL(秒),0同样表示永不过期;- 服务端在过期前 15 分钟刷新,且钳制在生命周期一半以内,确保短时 Token 不会被频繁刷新。
6.4 真实案例:Umami
Umami Piece 的自托管认证(packages/pieces/community/umami/src/lib/auth.ts)是这一模式的生产级实现:
const selfHostedAuth = PieceAuth.CustomAuth({ displayName: 'Self-hosted (Username & Password)', props: { baseUrl: Property.ShortText({ displayName: 'Instance URL', ... }), username: Property.ShortText({ displayName: 'Username', ... }), password: PieceAuth.SecretText({ displayName: 'Password', ... }), }, validate: async ({ auth }) => { // POST {baseUrl}/api/auth/login 验证用户名密码 }, refresh: { generate: async ({ auth }) => { const baseUrl = auth.baseUrl.replace(/\/+$/, ''); const response = await httpClient.sendRequest<{ token: string }>({ method: HttpMethod.POST, url: `${baseUrl}/api/auth/login`, body: { username: auth.username, password: auth.password }, }); return { access_token: response.body.token }; }, // Umami 不返回 expires_in;默认 55 分钟,保证在典型的 1 小时 JWT 过期前完成刷新 defaultExpiresIn: 3300, }, });该文件还展示了一个进阶技巧:Umami 同时导出了selfHostedAuth和cloudAuth(SecretText),并以数组形式[selfHostedAuth, cloudAuth]传给createPiece——这样同一个 Piece 可以让用户二选一(自托管账号密码 或 云端 API Key),配合AppConnectionType判别(见同文件getBaseUrl/getAuthHeaders)实现按连接类型分流。这也解释了框架中PieceAuthProperty[]数组形态的存在意义。
七、连接标识符 getConnectionIdentifier:让连接列表一目了然
7.1 作用与语法
getConnectionIdentifier是每种认证类型(SecretText、BasicAuth、OAuth2、CustomAuth)都可选的回调,用于为一条连接解析出人类可读的标签(例如账号邮箱,或 Slack 的「display-name (workspace)」),展示在连接管理 UI 中,帮助用户区分多个账号。
export const myAppAuth = PieceAuth.OAuth2({ required: true, authUrl: 'https://app.example.com/oauth/authorize', tokenUrl: 'https://app.example.com/oauth/token', scope: ['read', 'write'], getConnectionIdentifier: async ({ auth }) => { const response = await httpClient.sendRequest<{ email: string }>({ method: HttpMethod.GET, url: 'https://api.example.com/v1/me', headers: { Authorization: `Bearer ${auth.access_token}` }, }); return response.body.email; }, });7.2 使用规则
- 必须是 best-effort:把有风险的调用包在
try/catch中,无法确定时解析为undefined。回调抛出错误会阻塞连接保存; - OAuth2 优先用通用路径:Activepieces 已能从 token 响应的 OIDC claims 中自动推导标识符。只有通用路径覆盖不了时才需要这个钩子——例如Slack 没有按用户维度的 OIDC claim,所以需要「工作区名 + 追加一次
users.info调用」来拼出标签; - 只在该提供商确实暴露账号/工作区标签时才加:一个没有「who am I」端点的裸 API Key,没有任何可解析的内容,就不需要实现。
7.3 回调形态与框架机制
与validate一致,回调里的auth是扁平形态(SecretText 是字符串、CustomAuth 是扁平 props 对象),不是完整连接对象。框架层面,common.ts 的注释揭示了一个内部机制:由于函数无法通过元数据序列化,框架在Piece.metadata()阶段派生出hasConnectionIdentifier布尔标记,服务端无需支付一次 engine 往返就能判断该认证是否定义了此钩子。
7.4 真实案例:Slack
Slack 的 OAuth2 认证(packages/pieces/community/slack/src/lib/auth.ts)是完整实现:先尝试从 token 响应的data.team/data.enterprise中取工作区名,取不到就返回undefined;再通过users.info拿授权用户的 display name / real name / username,拼成"<user> (<workspace>)";users.info调用失败时降级为只返回工作区名。全程 best-effort,绝不抛错。
八、None:无认证的公共 API 与工具 Piece
对于公开 API 或不需要凭据的工具类 Piece,直接使用PieceAuth.None():
// 在 createPiece() 中: auth: PieceAuth.None(),从框架源码 index.ts 可以看到None()的实现就是返回undefined。使用None时需注意三点行为差异:
- 在
createAction()/createTrigger()中省略auth:字段; run中context.auth不可用;- Dropdown 等动态属性收不到
auth参数(因为根本没有连接对象可传)。
真实案例:packages/pieces/core/qrcode/src/index.ts(QR 码生成工具 Piece)——纯工具属性,无任何网络凭据需求。
九、模式选择决策速查
综合全文,为你的 Piece 选择认证模式时可遵循以下决策链:
- 完全不需要凭据(公共 API、纯工具)→
PieceAuth.None(); - 单一 Key/Token 即可→
PieceAuth.SecretText(),配合validate调一次轻量接口验证; - 标准 OAuth2 授权码流程(Google、Slack、GitHub 类)→
PieceAuth.OAuth2(),按需配置pkce、grantType、authorizationMethod、额外props与extra; - 用户名 + 密码→
PieceAuth.BasicAuth(); - 多字段组合(URL + Key、区域 + 凭据、账号 + Token)→
PieceAuth.CustomAuth(),牢记「validate 扁平、action 走props」; - 多字段 + 短时 Token→ 在 CustomAuth 上追加
refresh,用defaultExpiresIn兜底,避免每个 action 触发登录造成 429; - 连接列表需要区分账号→ 为上述任意认证类型追加
getConnectionIdentifier,遵守 best-effort 规则; - 一个 Piece 支持多种认证方式→ 用数组
[authA, authB]传给createPiece,运行期以AppConnectionType判别(参考 Umami 案例)。
十、总结
认证是 Piece 与外部服务之间的信任边界,Activepieces 的PieceAuth通过六种模式覆盖了从单 Key 到 OAuth2、从扁平账号到多字段组合的绝大多数场景。本文梳理的要点包括:validate回调与 action/trigger 中auth形态的差异、OAuth2 连接对象的三段式结构(access_token/props/data)、CustomAuth 的「validate 扁平 / props 嵌套」规则、refresh机制的 15 分钟提前刷新与生命周期钳制、getConnectionIdentifier的 best-effort 约束,以及无认证 Piece 的None约定。结合 Stripe、Umami、Slack、GitHub、Zoho Campaigns、WordPress、Mattermost 等仓库内真实实现,你可以对照.agents/skills/piece-builder/auth-patterns.md快速为自己的 Piece 选定认证方案,并直接复用上述代码骨架完成可校验、可读、可长期维护的连接定义。
【免费下载链接】activepiecesAI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents项目地址: https://gitcode.com/GitHub_Trending/ac/activepieces
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考