如何构建具有每用户OAuth访问权限的AI代理 [完整手册]

如何构建具有每用户OAuth访问权限的AI代理 [完整手册]

💡 原文英文,约8400词,阅读约需31分钟。
📝

内容提要

本文介绍如何构建一个多用户AI代理,通过OAuth为每个用户单独授权,以用户身份连接Slack和GitHub。核心是使用用户标识符而非共享令牌,令牌加密存储且不进入模型或日志。代理读取Slack消息,判断是否创建GitHub问题并回复。文章涵盖OAuth流程、令牌存储、刷新撤销及多提供商扩展,强调身份隔离和授权安全。

🔎

延伸解读

身份隔离是核心,而非附加功能

文章强调,多用户AI代理的关键在于每次工具调用都要明确“代理代表谁”。共享令牌会导致权限越界、审计混乱和撤销失效。通过为每个用户单独授权,并使用用户标识符而非令牌,可以确保代理始终以正确的用户身份操作。这种设计不仅适用于团队内部,也适用于面向客户的产品,只是标识符来源不同。

令牌安全:模型与日志的双重隔离

令牌绝不能进入模型输入、工具描述或返回值,也不能出现在日志中。文章建议将令牌加密存储,仅在调用时通过标识符获取,并立即用于API调用。这样即使模型被提示注入,也无法泄露令牌。此外,加密存储使用AES-256-GCM,每次加密使用新的IV,并保留认证标签,确保数据完整性和机密性。

OAuth流程中的常见陷阱

文章指出几个容易出错的地方:Slack要求回调URL必须使用HTTPS,且令牌交换失败时返回HTTP 200,需检查json.ok字段;GitHub需要设置Accept: application/json头,否则响应体是表单格式。此外,state参数必须随机生成并验证,防止CSRF攻击。这些细节虽小,但忽略它们会导致安全漏洞或调试困难。

令牌刷新与撤销的处理策略

不同提供商的令牌生命周期不同:GitHub OAuth App令牌不过期,但可能因用户撤销、一年未使用或泄露而被吊销;Slack令牌默认不过期,但启用旋转后12小时过期,且旋转不可逆。文章建议在令牌过期前60秒内刷新,并处理无刷新令牌的情况。对于撤销,正确做法是让用户重新授权,而不是尝试自动恢复。

Q&A

为什么AI代理不能使用共享令牌,而必须为每个用户单独授权?

共享令牌会导致三个问题:所有用户使用相同权限,可能越权访问;审计记录无法区分具体用户;用户离职后令牌失效无法自动停止。因此需要每个用户单独授权,确保代理以正确的用户身份操作。

在构建多用户AI代理时,如何确保OAuth令牌不泄露给模型或日志?

令牌只存储在加密的数据库中,代码中只传递用户标识符(如邮箱),在调用API时才通过标识符获取令牌,且令牌不进入模型输入、工具描述、返回值或日志。

Slack OAuth授权时,如何区分用户令牌和机器人令牌?

Slack的OAuth响应中,顶层access_token是机器人令牌(xoxb-),而authed_user.access_token是用户令牌(xoxp-)。本教程只请求用户令牌,因此将user_scope参数用于用户权限,而不使用scope参数,从而避免获取机器人令牌。

为什么OAuth回调URL必须使用HTTPS,即使是在本地开发?

Slack要求回调URL必须使用HTTPS,且不例外localhost。使用mkcert可以生成本地受信任的证书,使浏览器接受。这虽然看似繁琐,但避免了提供方为localhost开特例带来的安全风险。

如何存储OAuth令牌以确保安全?

使用node:sqlite数据库存储,每个用户和提供商的组合作为主键,令牌使用AES-256-GCM加密,每个令牌对象整体加密,并保存IV和认证标签。加密密钥存储在环境变量中,生产环境应使用密钥管理服务。

当用户的OAuth令牌过期或撤销时,代理应如何处理?

对于过期令牌,如果有刷新令牌则自动刷新;如果没有刷新令牌或令牌被撤销,则抛出错误并提示用户重新授权。GitHub OAuth App令牌不自动过期,但可能被撤销,此时需要用户重新同意。

如何为AI代理添加第二个OAuth提供商(如GitHub)?

将每个提供商的配置(授权URL、令牌URL、作用域等)集中在一个providers对象中,实现统一的exchangeCode和refresh方法。添加新提供商只需增加一个条目,无需修改核心逻辑。

在AI代理中,如何确保工具调用以当前用户身份执行?

在构建工具时,通过闭包捕获用户标识符,在工具执行时使用该标识符获取令牌,并调用API。模型只能控制工具参数,无法指定用户,从而确保身份隔离。

🏷️

标签

➡️

继续阅读