news 2026/9/12 6:45:15

Activepieces Piece 认证模式全解析:SecretText、OAuth2、Basic、CustomAuth 与连接标识符实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Activepieces Piece 认证模式全解析:SecretText、OAuth2、Basic、CustomAuth 与连接标识符实战指南

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的六种认证形态——SecretTextOAuth2BasicAuthCustomAuth(含 Token 刷新)、连接标识符getConnectionIdentifierNone,并结合仓库内真实 Piece 源码与框架底层实现,说明每种模式在validate校验、action/trigger 运行时读取凭据的具体写法,帮助你在构建 Piece 时选出正确模式并写出可上线的认证代码。


一、认证体系概览:PieceAuth提供的六种形态

从框架源码 packages/pieces/framework/src/lib/property/authentication/index.ts 可以看到,PieceAuth暴露了五个构造器(SecretTextOAuth2BasicAuthCustomAuthOIDC)以及返回undefinedNone(),它们分别对应PropertyType中的不同枚举值,最终在连接(App Connection)层映射为AppConnectionType中的SECRET_TEXTOAUTH2BASIC_AUTHCUSTOM_AUTHOIDCNO_AUTH

本指南覆盖其中六种最常用的模式,核心差异在于用户需要输入什么、凭据以什么形态出现在validate与 action/trigger 上下文中

认证模式适用场景validate回调中的auth形态action/trigger 中的读取方式
SecretText单一 API Key / Token普通字符串context.auth.secret_text
OAuth2授权码流程(Google、Slack、GitHub 等)完整连接对象context.auth.access_tokencontext.auth.propscontext.auth.data
BasicAuth用户名 + 密码扁平对象context.auth.usernamecontext.auth.password
CustomAuth多字段组合(URL + Key、区域 + 凭据等)扁平 props 对象context.auth.props.<field>
CustomAuth + refresh短时 Token(登录换 JWT)扁平 props 对象context.auth.access_token(服务端缓存)
None公共 API / 工具类 Piececontext.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取值为plainS256,S256 是更安全的推荐值;
  • prompt:授权页提示行为,取值noneconsentloginomitomit表示不发送 prompt 参数);
  • grantType:授权类型,来自@activepieces/core-piece-typesOAuth2GrantType枚举(如AUTHORIZATION_CODECLIENT_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.teamdata.authed_user都来自这里。

3.4 自定义 API 调用动作中的类型推断

createCustomApiCallAction中,只要把auth声明为myAppAuthauthMapping回调的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中做真实校验时,推荐使用httpClientauthentication字段并指定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_urlauth.api_key
  • 在 action/trigger 中,字段挂在props下——必须用context.auth.props.base_urlcontext.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 同时导出了selfHostedAuthcloudAuth(SecretText),并以数组形式[selfHostedAuth, cloudAuth]传给createPiece——这样同一个 Piece 可以让用户二选一(自托管账号密码 或 云端 API Key),配合AppConnectionType判别(见同文件getBaseUrl/getAuthHeaders)实现按连接类型分流。这也解释了框架中PieceAuthProperty[]数组形态的存在意义。


七、连接标识符 getConnectionIdentifier:让连接列表一目了然

7.1 作用与语法

getConnectionIdentifier每种认证类型(SecretTextBasicAuthOAuth2CustomAuth)都可选的回调,用于为一条连接解析出人类可读的标签(例如账号邮箱,或 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:字段
  • runcontext.auth不可用
  • Dropdown 等动态属性收不到auth参数(因为根本没有连接对象可传)。

真实案例:packages/pieces/core/qrcode/src/index.ts(QR 码生成工具 Piece)——纯工具属性,无任何网络凭据需求。


九、模式选择决策速查

综合全文,为你的 Piece 选择认证模式时可遵循以下决策链:

  1. 完全不需要凭据(公共 API、纯工具)→PieceAuth.None()
  2. 单一 Key/Token 即可PieceAuth.SecretText(),配合validate调一次轻量接口验证;
  3. 标准 OAuth2 授权码流程(Google、Slack、GitHub 类)→PieceAuth.OAuth2(),按需配置pkcegrantTypeauthorizationMethod、额外propsextra
  4. 用户名 + 密码PieceAuth.BasicAuth()
  5. 多字段组合(URL + Key、区域 + 凭据、账号 + Token)→PieceAuth.CustomAuth(),牢记「validate 扁平、action 走props」;
  6. 多字段 + 短时 Token→ 在 CustomAuth 上追加refresh,用defaultExpiresIn兜底,避免每个 action 触发登录造成 429;
  7. 连接列表需要区分账号→ 为上述任意认证类型追加getConnectionIdentifier,遵守 best-effort 规则;
  8. 一个 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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 6:43:41

Flink核心架构:Window、State与Checkpoint实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 6:42:29

5 分钟把摄像头搬进浏览器:go2rtc 低延迟推流入门指南

5 分钟把摄像头搬进浏览器&#xff1a;go2rtc 低延迟推流入门指南 【免费下载链接】go2rtc Ultimate camera streaming application 项目地址: https://gitcode.com/GitHub_Trending/go/go2rtc go2rtc 是一款零依赖的摄像头流媒体应用&#xff08;camera streaming appl…

作者头像 李华
网站建设 2026/9/12 6:41:02

3步修复LSP启动命令cmd:nvim-lspconfig实战指南

3步修复LSP启动命令cmd&#xff1a;nvim-lspconfig实战指南 【免费下载链接】nvim-lspconfig Quickstart configs for Nvim LSP 项目地址: https://gitcode.com/GitHub_Trending/nv/nvim-lspconfig 这篇文章解决配置 nvim-lspconfig 时最常见的一类问题&#xff1a;语言…

作者头像 李华
网站建设 2026/9/12 6:37:03

Midscene.js 浏览器自动化完整指南:3 步让 Chrome 听懂你的话

Midscene.js 浏览器自动化完整指南&#xff1a;3 步让 Chrome 听懂你的话 【免费下载链接】midscene GUI Agent for E2E Testing 项目地址: https://gitcode.com/GitHub_Trending/mid/midscene 你有没有遇到过这种场景&#xff1a;想在页面上自动点按钮、抓数据、验证流…

作者头像 李华
网站建设 2026/9/12 6:36:41

Python lambda函数详解:从入门到高阶应用

1. 什么是Python lambda函数&#xff1f;第一次接触Python lambda函数时&#xff0c;我完全被这个奇怪的语法搞懵了。为什么要在Python中使用这种看起来像"残废"的函数&#xff1f;直到我在处理一个数据清洗任务时&#xff0c;才真正体会到它的威力。lambda函数是Pyt…

作者头像 李华