
OpenClaw 认证凭证语义从资格判定、解析路由到故障排障的权威指南【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw本文以 OpenClaw 仓库中的权威文档 auth-credential-semantics.md 为骨架系统讲解认证 Profile 的资格判定eligibility与运行时解析resolution语义覆盖openclaw models status --probe的稳定 reason code、Token / API Key / OAuth 三类凭证的规则、auth.order显式排序过滤、模型目录发现、外部 CLI 凭证发现以及 Gateway 集成等实战场景。读完本文你将能准确诊断模型认证失败的原因、理解 Setup 替换凭证与 Agent 复制可移植性的边界并在自己的插件或 Agent 中正确使用resolveApiKeyForProfile与 OAuth 校验回调。这些语义的设计目标是让选择期selection-time与运行期runtime的认证行为保持一致避免探测时可用、真正调用时却失败的偏差。它们被以下核心模块共享resolveAuthProfileOrderProfile 排序实现在 src/agents/auth-profiles/order.tsresolveApiKeyForProfile运行时凭证解析见 src/agents/auth-profiles/oauth.ts 及相关调用链openclaw models status --probe探测命令openclaw doctor的认证检查doctor-auth稳定的探测原因码Stable Probe Reason Codes探测结果携带一个status桶ok、auth、rate_limit、billing、timeout、format、unknown、no_model以及一个当探测从未到达模型调用时稳定输出的reasonCode。这些 reason code 是机器可读的脚本与 UI 都可以依赖其稳定性reasonCode含义excluded_by_auth_orderProfile 被该 Provider 的显式认证顺序auth order排除在外。missing_credential未配置内联凭证也未配置 SecretRef。expiredToken 的expires时间已过去。invalid_expiresexpires不是有效的正 Unix 毫秒时间戳。unresolved_ref配置的 SecretRef 无法解析。ineligible_profileProfile 与 Provider 配置不兼容包含格式错误的 Key 输入。no_model凭证存在但没有解析出可探测的模型候选。资格检查对可用凭证返回ok作为 reason code。源码印证reason code 的判定源头这些 reason code 并非分散在各处硬编码而是集中在 src/agents/auth-profiles/credential-state.ts 的AuthCredentialReasonCode类型中由evaluateStoredCredentialEligibility统一产出export type AuthCredentialReasonCode | ok | setup_inactive | missing_credential | invalid_expires | expired | unresolved_ref | malformed_api_key;而 order.ts 在它之上扩展了profile_missing、provider_mismatch、mode_mismatch三个排序期原因码最终形成AuthProfileEligibilityReasonCode。这意味着ineligible_profile在排序层面对应一组更细粒度的判定结果探测输出时再归并到文档所述的稳定桶位。Token 凭证type: tokenToken 凭证支持内联token和/或tokenRef两种取料方式。资格规则Eligibility Rules当token与tokenRef同时缺失时Profile 不合格reason code 为missing_credential。expires为可选字段。若存在必须是有限数的 Unix 纪元毫秒值大于0且不超过 JavaScriptDate的最大时间戳8640000000000000。若expires无效类型错误、NaN、0、负数、非有限数、超出上述最大值Profile 不合格reason code 为invalid_expires。若expires已过去Profile 不合格reason code 为expired。tokenRef不能绕过expires校验——即使 token 来自 SecretRef过期校验照常执行。解析规则Resolution Rules解析器的语义与资格语义在expires上完全一致。对合格 Profiletoken 材料可以从内联值或tokenRef解析。无法解析的引用在models status --probe输出中产生unresolved_ref。源码印证resolveTokenExpiryState的判定边界credential-state.ts 精确实现了上述边界if (expires undefined) return missing; if (typeof expires ! number) return invalid_expires; if (!Number.isFinite(expires) || expires 0 || expires MAX_DATE_TIMESTAMP_MS) { return invalid_expires; }其中MAX_DATE_TIMESTAMP_MS 8_640_000_000_000_000定义于 packages/normalization-core/src/number-coercion.ts与文档中的最大 JavaScript Date 时间戳完全对应。同一文件还提供了expiring中间态与默认 5 分钟 OAuth 刷新余量DEFAULT_OAUTH_REFRESH_MARGIN_MScredential-state.ts供刷新调度使用。手动 API KeyManual API Keys在 Models 界面保存手动 API Key 时行为取决于Provider 绑定是否发生变化绑定发生变化保存操作会等待 Gateway 应用变更后的 Provider 绑定再刷新模型认证。绑定未变化替换 Key 只需要认证刷新即可。Gateway 无法确认应用成功Key 仍会被保存但响应中包含重启警告restart warning。这保留了对已配置重载策略包括禁用重载的尊重。删除 Key如果绑定或凭证并发发生了变更删除操作仍会拒绝执行。Setup 替换凭证Setup ReplacementsSetup 替换凭证以独立的 Profile ID保存并在既有凭证载荷中带有一个内部setup描述符descriptor。它们有以下严格限制不能进入常规轮换rotation不能通过显式 Profile 固定pin解析不能被复制到另一个 Agent只有发起它的 Setup 操作可以测试所选凭证。激活流程在成功完成一轮无工具tool-free对话之后Setup 会询问是否激活该凭证。拒绝或测试失败都会让已保存的凭证保持非激活状态并保留当前连接。Model Setup 提供同样的已保存登录可在无需再次登录的情况下重新测试。Gateway 激活会等待配置应用若需要重启替换凭证保持非激活直到 Setup 重试。普通登录则保持即时生效。描述符会保留所选模型与连接设置以便重启后重试且不缓存验证结果。这一机制不新增任何数据库 schema 或迁移因此旧版本运行时不会强制执行非激活状态。降级前请先移除已保存的非激活替换凭证或恢复 Setup 前的状态。非交互式noninteractiveSetup保存替换凭证后会打印一条命令供测试与激活openclaw models auth activate profileId --agent id交互式 Setup 默认在测试成功后激活。复用既有凭证与首次运行的非交互式 Setup 保持原有行为不变。Agent 复制可移植性Agent Copy PortabilityAgent 的认证继承是读穿透read-through的当某个 Agent 没有本地 Profile 时它不会把密钥材料复制进自己的凭证库agents/agentId/agent/openclaw-agent.sqlite而是在运行时直接从共享认证存储解析 Profile。共享存储位于state/openclaw.sqlite由openclaw doctor --fix执行一次性搬迁后生效在此之前doctor 会报告旧的agents/main/agent/openclaw-agent.sqlite属主并保持该 Agent 不可删除。显式复制流程如openclaw agents add遵循以下可移植性策略api_key与tokenProfile 默认可移植除非设置copyToAgents: false。oauthProfile默认不可移植因为刷新令牌可能是单次使用或对轮换敏感的。Provider 自有的 OAuth 流程可以显式copyToAgents: true选择加入但仅在复制刷新材料跨 Agent 已知安全时且该选择加入仅在 Profile 携带内联 access/refresh 材料时生效。不可移植的 Profile 仍可通过共享读穿透基座shared read-through base使用除非目标 Agent 单独登录并创建自己的本地 Profile。OAuth 刷新期间的惰性标记inert markerOAuth 刷新期间当前凭证代credential generation会被替换为一个惰性持久标记inert durable marker。挂起的标记默认不合格只允许通过能立即将其交给结算感知解析器settlement-aware resolver的运行时路径参与排序。失败的标记是终态terminal的需要操作者重新认证。Agent 本地对端peer永远收不到复制过来的轮换刷新材料。对端只有在验证共享凭证属于同一账户后才会移除自己的标记并继承共享凭证若身份无法验证对端保持终态隔离terminally fenced而不是继承另一个账户的凭证。Plugin SDK OAuth 校验resolveApiKeyForProfile从openclaw/plugin-sdk/agent-runtime导出接受一个可选的validateOAuthCredential回调。解析器会在以下时机调用它返回 OAuth 凭证之前持久化或采用adopt刷新后的凭证之前当遗留provider:defaultProfile 回退到替换 OAuth Profile 时回调同样生效。回调抛错即拒绝该凭证。被拒绝的回退不会被返回也不会被刷新原始所选 Profile 的刷新失败仍然是对操作者呈现的错误。拒绝一个进行中的刷新或结算代settlement generation会 fail-closed并可能将该代及其对端置于终态隔离操作者必须重新认证。省略回调的调用方保留原有的解析与回退行为。源码印证回调挂载点在 src/agents/auth-profiles/oauth.ts 中回调类型定义为validateOAuthCredential?: (credential: OAuthCredential) void并在刷新约 L312、采用/持久化约 L536以及回退校验约 L610三处挂载与文档描述的调用时机一一对应。配套测试见 oauth.validator-fallback.test.ts。openclaw agent exec的受限凭证作用域openclaw agent exec切换到临时运行状态时会保留原始共享存储根shared-store root。其受限凭证作用域bounded credential scope从该共享存储读取可移植的api_key与tokenProfile不持久化副本已配置 Agent 的本地 Profile 仍然优先。共享 OAuth Profile被排除在该临时作用域之外即使带copyToAgents: true这样临时运行不会成为另一个刷新属主。--auth-env-only则完全禁用存储凭证访问。显式状态目录的写入语义显式选择状态目录的认证写入包括隔离的 QA staging使用该目录的共享存储进行属主判定与 OAuth 去重。其运行时发布与回滚保持同一属主另一个进程本地状态根不是继承基座。不相关的外部数据库可能更旧、更新或不可读但不会阻塞隔离写入而所选目标中不可读或更新的数据库仍然 fail-closed。未显式指定状态目录的写入保持正常的周边状态ambient state与 Agent 目录配置。个人模型账户Personal Model Accounts从Settings → Profile → Connected accounts连接的账户在共享状态数据库中具有身份作用域的属主identity-scoped owner。其凭证与用量状态永不进入共享或 Agent 本地认证存储、外部 CLI 镜像或全局运行时快照。一个运行时最多加载其会话选中的一个个人凭证。未关联unlinked的个人账户仍可被既有会话 pin 使用但不会被新会话自动选择。个人 pin 保持既有的同 Provider 故障转移策略固定账户失败后可以依次尝试有序的共享账户。它们不会让另一个人的个人账户成为回退。重新连接只能替换连接者本人的凭证管理员创建链接所引用的共享凭证不是个人财产。详见 Per-person model accounts。纯配置认证路由Config-only Auth Routesauth.profiles中mode: aws-sdk的条目是路由元数据而非存储的凭证。当目标 Provider 使用models.providers.id.auth: aws-sdk时即插件拥有的 Amazon Bedrock Setup 写入的路由它们即有效。这些 Profile ID 可以出现在auth.order与 session 覆盖中即使凭证库中不存在对应条目。两条硬性规则不要在凭证库中写入type: aws-sdk——存储凭证只有api_key、token、oauth三种类型。若遗留的auth-profiles.json中有此类标记openclaw doctor --fix会将其移动到auth.profiles并从存储中移除该标记。被移除存储凭证后的模型发现当所选存储 Profile 被移除时凭证作用域的模型发现会先报告selected_auth_profile_unavailable再咨询动态模型元数据。恢复凭证或选择另一个已配置 Profile 即可修复注册模型并不能修复缺失的认证。纯配置的 AWS SDK Profile 无需存储凭证仍然有效。聊天准入与 Agent 命令在其凭证消失时保留显式同 Provider 选择以便认证能报告恢复过期的自动选择与不兼容 Provider 的选择仍会被清除。源码印证AWS SDK Profile 的资格特例src/agents/auth-profiles/order.ts 的isConfiguredAwsSdkAuthProfileForProvider检查三项条件配置存在且mode aws-sdk、Profile 声明的 Provider 解析后与目标 Provider 一致、目标 Provider 允许aws-sdk认证providerAllowsAwsSdkAuth见 L120-L123。当凭证库中无对应条目时resolveAuthProfileEligibilityL167-L180会先走这条特例命中则直接返回{ eligible: true, reasonCode: ok }——这正是纯配置路由无需存储凭证的实现依据。显式认证顺序过滤Explicit Auth Order Filtering当某个 Provider 设置了auth.order.provider或认证存储中的顺序覆盖时models status --probe只探测仍留在该 Provider 解析后认证顺序中的 Profile ID。存储中的覆盖优先于auth.order配置源码中resolveExplicitAuthOrderSelection的实现见 order.ts它依次查找存储顺序与配置顺序。被显式顺序排除的存储 Profile不会被静默地稍后重试。探测输出以reasonCode: excluded_by_auth_order报告它detail 为Excluded by auth.order for this provider.会话用户 pin 是显式的按会话例外即使 Profile 被 Provider 顺序排除OpenClaw 也先尝试该 Profile然后将有序的同 Provider Profile 作为重试候选。冷却cooldown或禁用窗口只作用于受影响的 Profile不会抑制其合格的同级 Profile。准备完成的 Agent 请求使用其选定的插件元数据、配置、工作区与环境进行认证 Profile 资格、排序与环境凭证证据的判定。空的选定插件集合仍然具有权威性另一个请求的插件别名不能添加 Profile 或改变凭证属主。源码印证显式顺序为何是硬约束order.ts 表明baseOrder在存在显式顺序时优先取显式顺序若为空则返回空结果hasExplicitOrder: true。L378-L404 进一步说明显式顺序下仅冷却中的 Profile被移到可用项之后按冷却结束时间排序其余保持显式顺序——explicit order remains a hard user/config preference。而无显式顺序时L406-L408则按lastUsed轮询round-robin排序且刻意忽略lastGood以免其饿死其他健康 Profile。类型优先级与冷却排序orderProfilesByModeL425-L484展示了无显式顺序时的完整排序逻辑先按类型分档oauth(0) token(1) api_key(2)再按 OAuth 过期状态已过期的可刷新 OAuth 排后避免轮换一次性刷新令牌时挤掉活跃对端最后按lastUsed升序轮询冷却 Profile 追加在队尾。会话 pin 通过prependAuthProfilePinL256-L266置于队首而不丢弃其余故障转移候选。模型目录发现Model Catalog Discovery存储 Profile 的模型发现选择遵循规范认证顺序与资格规则仅限单个模型的冷却不会抑制账户级目录发现。配置的订阅模式subscription modes仍然挂在直接凭证上成功的 OAuth 准备会把解析出的当前 token交给目录消费者而不是捕获存储中的旧 token。环境背书 Profileenvironment-backed profiles从发现环境包括冷命令与 worker 路径保留可用值。当该材料缺失时只有所选 Profile 的激活快照可以供给它否则发现会在目录 HTTP 之前报告unavailable。引用名reference names绝不会作为凭证发送也不会被替换为另一 Profile 的凭证。在 Gateway 上恢复密钥后需先运行openclaw secrets reload再重试发现。当每个合格 OAuth 候选的准备都失败时发现报告unavailable并携带尝试过的 Profile 身份而不是把 Provider 当作未配置。兼容的既有库存prior inventory仍然可用。可用的回退凭证仍会提供自己的目录结果。目录截止时间deadline到期后迟到的 Provider 结果在最终化之前被丢弃。已经启动的 hook 或 OAuth 刷新可以完成包括持久化轮换后的凭证但不能发布到已过期的目录运行。API-Key 导向与全认证目录回调保留其既有来源优先级。插件必须保证凭证字节与其认证模式来自同一次选择。目录失败与恢复遵循 模型库存契约选择来源与回退严格性且不改变消息执行的 Profile 轮换或会话 pin。Probe 目标解析Probe Target Resolution探测目标可以来自认证 Profile、环境凭证或models.json结果sourceprofile、env、models.json。若 Provider 有凭证但 OpenClaw 无法为其解析可探测模型候选models status --probe报告status: no_model且reasonCode: no_model。外部 CLI 凭证发现External CLI Credential Discovery受支持的外部 CLI 凭证仅当Provider、运行时或认证 Profile 在当前操作范围内、或该外部来源已存在存储的本地 Profile 时才会被发现。认证存储调用方显式选择外部 CLI 发现模式none仅持久化/插件认证、existing刷新已存储的外部 CLI Profile、scoped具体 Provider/Profile 集合。只读/状态路径传入allowKeychainPrompt: false它们只使用基于文件的外部 CLI 凭证不读取也不复用 macOS Keychain 结果。/models复用已随目录准备好的外部登录证据因此这些 Provider 无需二次 OpenClaw 登录即可保持可见。打开默认菜单不会重复外部 CLI 发现显式认证顺序与路由兼容性仍然适用。Codex 登录的导入语义Codex 拥有自己的原生登录。普通状态与模型读取不会将其凭证导入 OpenClaw Profile。要保留配置为 CLI 背书的openai:defaultProfile请显式导入当前 Codex 登录openclaw models auth login --provider openai --method device-code当该 OAuth Profile 声明在auth.profiles中、来源是当前原生 Codex 主目录、且不存在其他受管 OpenAI OAuth Profile 时导入保留 Profile ID 及其既有模型与会话 pin配置的模型与原生凭证文件保持不变。显式隔离的 Agent 主目录通过其隔离运行时继续使用导入的 OpenClaw Profile。新导入保持账户作用域的 Profile ID。匹配的既有账户与用户会复用其存储 Profile。从其他主目录导入、缺失账户/用户身份、或存在既有受管账户时不会认领遗留 pin——这些情况请显式使用报告的导入 Profile。持久化前检测到的来源变更与冲突 Profile 只中止选中的那次导入。OAuth SecretRef 策略守卫OAuth SecretRef Policy GuardSecretRef 输入仅用于静态凭证。OAuth 凭证是运行时可变的刷新流程会持久化轮换后的 token因此 SecretRef 背书的 OAuth 材料会把可变状态分裂到多个存储中。策略如下若 Profile 凭证为type: oauth该 Profile 的任何凭证材料字段都拒绝 SecretRef 对象。若auth.profiles.id.mode为oauth则拒绝该 Profile 的 SecretRef 背书keyRef/tokenRef输入。违反策略是硬失败抛出错误发生在启动/重载密钥准备与 Profile 解析路径中。关于哪些凭证字段接受 SecretRef 而非原始密钥值参见 SecretRef 凭证表面文档。遗留兼容消息Legacy-Compatible Messaging当空的 SQLite 认证存储旁存在已退役的auth-profiles.json时运行时只检查 Provider 元数据而不导入或解析其凭证。AUTH_PROFILE_MIGRATION_REQUIRED只阻断这些 Provider包括其认证别名无关 Provider 的认证仍然可用。不可读或无法识别的遗留数据保留属主级拒绝owner-wide refusal。已填充的 SQLite 存储保持仅警告行为。记录的拒绝一直保留直到生命周期显式清除变更或删除遗留文件不会释放它们。Doctor 会列出受影响的 Provideropenclaw doctor --fix执行受支持的验证导入与归档。更细的规则会话读取者保留其本地与共享认证存储属主并在返回凭证前检查每个属主当前的拒绝状态。共享 Provider 的拒绝不会用环境或配置认证替换无关的本地凭证未解析的本地 SecretRef 仍然 fail-closed。只有可识别的凭证条目能缩小遗留拒绝范围仅元数据对象与未知布局保持属主级。凭证写入只针对其目标数据库进行属主级迁移就绪检查。共享存储拒绝不会阻塞刷新无关的 Agent 本地 OAuth 凭证写入目标上的拒绝仍会阻塞写入。会话迁移守卫使用与模型发现相同的固定运行时配置以及所请求模型的端点来解析端点相关的 Provider 别名。准备的会话视图保留两个属主的规范 Profile 并校验其 SecretRef迁移元数据不过滤这些 Profile。端点感知的请求守卫决定准入。每个所选凭证通过合并与异步解析保留其物理来源属主。该属主持有的拒绝会继续隔离另一进程导入的匹配凭证直到显式生命周期清除/重载另一属主的凭证保持独立。此来源信息仅存在于运行时绝不写入 SQLite。若请求的 Provider 需要端点来识别其凭证领域而上下文缺失任何挂起的迁移拒绝都会阻断它显式配置的不相关端点仍然可用。脚本兼容性保证为保持脚本兼容探测错误的第一行保持不变Auth profile credentials are missing or expired.人类可读的细节与稳定 reason code 在后续行以↳ Auth reason [code]: ...形式输出。调试路径速查现象排查入口对应语义章节探测显示excluded_by_auth_order检查auth.order.provider与存储顺序覆盖显式认证顺序过滤探测显示unresolved_ref检查 SecretRef 目标是否存在Gateway 上运行openclaw secrets reloadToken 凭证 / 模型目录发现探测显示expired/invalid_expires检查expires是否为有限的正 Unix 毫秒且未过期Token 凭证探测显示no_model检查models.json与动态模型元数据Probe 目标解析保存 API Key 后出现重启警告Gateway 未能确认 Provider 绑定应用手动 API Key文档要求使用aws-sdk认证但报错确认auth.profiles.id.mode为aws-sdk且未写入凭证库纯配置认证路由报错涉及 OAuth SecretRef检查是否在 OAuth Profile 上使用了keyRef/tokenRefOAuth SecretRef 策略守卫相关文档Secrets 管理认证存储OAuth 概念SecretRef 凭证表面——哪些凭证字段接受 SecretRef 而非原始密钥值每用户模型账户模型库存契约选择来源与回退严格性核心实现排序与资格判定、凭证状态分类、OAuth 刷新与校验配套测试见 order.test.ts 与 oauth.validator-fallback.test.ts【免费下载链接】openclawThe AI that really does things. Any OS. Any Platform. The lobster way. 项目地址: https://gitcode.com/GitHub_Trending/cl/openclaw创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考