构建 Auth 验证:关于让错误信息真正有帮助的5个教训
Source: Dev.to
为什么你应该在意
你正在构建一个连接多个外部服务的工具——GitHub、AI 代理、各种 API。一切运行良好……直到它出错。
用户运行一个任务,任务失败。他们查看日志,滚动输出,30 分钟后才发现:“哦,认证令牌过期了。”
我为 DevLoop Runner(一个使用 AI 代理自动化 PR 的工具)实现了认证校验功能。以下是我在让校验真正有用方面学到的经验。
教训 1:隐藏用户不需要看到的内容
最初的实现会在校验输出中明文打印 JWT 令牌、电子邮件地址和组织名称——这是个坏主意。
const isJsonString = authJsonPath.startsWith('{') || authJsonPath.startsWith('[');
const displayValue = isJsonString
? '[JSON content - masked for security]'
: authJsonPath;
用户只需要知道 “是否已配置?” 和 “是否能工作?”。请对敏感凭证进行掩码处理。
教训 2:校验实际被使用的内容
校验命令检查的是环境变量,而执行命令使用的是文件。校验通过了,但执行失败,导致用户困惑。
const homeDir = process.env.HOME || os.homedir();
const authFilePath = path.join(homeDir, '.codex', 'auth.json');
if (fs.existsSync(authFilePath)) {
// Validate the file, not the env var
}
请像运行时那样精确校验环境。
教训 3:“失败”并不总是意味着失败
在我的工具中,OpenAI 和 Anthropic 的 API 密钥是可选的。第一版在未配置时报告 status: failed,这会产生误导。我把它改为 status: skipped。
if (isBlank(apiKey)) {
checks.push({
name: 'OPENAI_API_KEY',
status: 'skipped',
message: 'Not configured (optional for follow‑up issue generation)',
});
return { status: 'passed', checks };
}
- 缺少必需的配置 → failed
- 缺少可选的配置 → skipped
这种区分很重要。
教训 4:不要请求超出需求的权限
GitHub 令牌校验最初要求三个作用域:repo、workflow、read:org。代码库从未使用 read:org;仅 workflow 对 GitHub Actions 必要。
const REQUIRED_GITHUB_SCOPES = ['repo'];
过于严格的校验会产生不必要的错误信息,令用户感到沮丧。
教训 5:让你的校验工具易于调试
在 Jenkins 中,连接性检查超时且没有日志,导致问题难以诊断。我添加了详细日志并延长了超时时间。
await codexClient.executeTask({
prompt: 'ping',
maxTurns: 1,
verbose: true, // Now we can see what's happening
});
// Increased timeout from 10 s to 30 s for Docker environments
setTimeout(() => reject(new Error('Timeout after 30 seconds')), 30000);
如果你的校验工具难以调试,你就制造了另一个问题。
模式
构建校验不仅仅是技术上的正确,更是向用户传递的信息:
- 掩码他们不需要看到的内容
- 检查实际被执行的内容
- 区分 failed 与 skipped
- 不要过度要求权限
- 让失败可调试
校验结果是一种沟通方式。它们应帮助用户了解下一步该怎么做,而不是用技术上正确却在实际中误导的消息让他们困惑。
更多关于构建工具和决策的思考,请访问 tielec.blog。