关于 adding-project-secret-api-key-auth
指导开发者在 PostHog API 端点接入项目密钥 API 密钥(PSAK)的技能文档。内容涵盖作用域授权、认证配置、限流和合成用户处理,并列出相关测试要求。
主要功能
- 01项目级无用户服务凭据说明
- 02作用域白名单配置
- 03端点认证与操作授权
- 04密钥级及团队级限流
- 05合成用户与权限处理
适用场景
- 01为 API 操作启用 PSAK 认证
- 02设置可授予的密钥作用域
- 03避免合成用户触发错误权限逻辑
- 04测试授权、团队绑定和限流
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ posthog/ posthog --skill adding-project-secret-api-key-auth安装后在 Claude Code 中输入/adding-project-secret-api-key-auth确认已加载。
详细介绍
为端点添加项目密钥 API key (PSAK) 认证
什么是 PSAK
ProjectSecretAPIKey 是一种项目范围内、无用户的服务凭证(posthog/models/project_secret_api_key.py)。它的行为类似个人 API key,但在用户离开项目后仍然有效,自带作用域,并以合成用户身份进行认证——而非真实的 User 行。
- Token 格式:
phs_...(仅限 Bearer 请求头——不像旧版 token 那样支持请求体回退)。 - 作用域在其资源类型内是项目级的,并有意忽略对象级访问控制(按资源的 RBAC)。
- 不要与
TeamSecretTokenAuthentication混淆——后者验证的是旧版按团队的Team.secret_api_token(同样以phs_为前缀),仅用于功能开关本地评估及类似的 PSAK 之前的接口。它被计划在某个时候迁移到 PSAK。
Key 通过 POST /api/environments/:id/project_secret_api_keys 进行管理(label + scopes;明文值仅返回一次;roll 操作用于轮换;每个项目最多 50 个;不允许通配符 * 作用域)。
为 viewset action 接线——检查清单
相关机制已经就绪,但尚未有任何东西接入它——第一个计划的消费者是 endpoints(该产品)的 run action。四件事,全都必需:
1. 将作用域/操作对加入白名单
可分配给 PSAK 的作用域是 posthog/scopes.py 中的全局允许列表:
PROJECT_SECRET_API_KEY_ALLOWED_API_SCOPE_ACTION: list[tuple[APIScopeObject, APIScopeActions]] = [("endpoint", "read")]
如果你的产品未列出,key 创建会在认证尚未尝试之前就拒绝该作用域。请先在此处添加你的 (scope_object, action) 元组。
将同样的作用域添加到 frontend/src/lib/scopes.tsx 中的 PROJECT_SECRET_API_KEY_ALLOWED_API_SCOPE_ACTION。项目设置中的作用域选择器根据该列表构建其复选框,因此仅修改后端会让用户无法授予该作用域。posthog/test/test_scopes.py 会比较这两个列表。
2. 添加认证器并让 action 选择启用
class MyViewSet(TeamAndOrgViewSetMixin, viewsets.ModelViewSet):
scope_object = "endpoint"
authentication_classes = [ProjectSecretAPIKeyAuthentication] # extends, TeamAndOrgViewSetMixin keeps session/PAK auth
psak_allowed_actions = ["run"]
psak_allowed_actions 是默认拒绝的:APIScopePermission 会拒绝任何 action 未列出的 PSAK 请求(“This action does not support project secret API key access”)。只列出程序化 action——绝不要列出应保持人工驱动的 CRUD。
APIScopePermission 还会自动强制执行团队绑定:PSAK 仅对 view.team == key.team 生效,因此 PSAK 认证只在项目范围(/api/environments/:id/...)的路由上才有意义。
3. 使用可感知 PSAK 的限流器
PersonalApiKeyRateThrottle 的子类会静默地绕过 PSAK 请求(没有个人 key → 没有限流)。请使用 posthog/rate_limit.py 中可感知 PSAK 的一对:
PersonalOrProjectSecretApiKeyRateThrottle——按 key 的预算(以psak:{key_id}为键),同时也仍然对个人 key 限流。ProjectSecretApiKeyTeamRateThrottle——按团队的聚合(以psak-team:{team_id}为键),无论项目铸造多少 key,都限制 PSAK 总负载。将其与按 key 的限流器叠加使用。
将它们子类化以设置产品特定的 scope/rate;请记住每个限流器会按 scope 字符串保留各自的缓存桶。
4. 处理合成用户
request.user 是 ProjectSecretAPIKeyUser(一个 SyntheticUser,posthog/synthetic_user.py),而不是 User:
-
user.id为None—— 绝不要将其用作外键。请使用user.current_team_id。 -
has_perm()始终返回False—— Django 权限检查会静默拒绝。 -
对它跳过按对象的访问控制检查(PSAK 作用域按设计是项目级的):
if is_authenticated_via_project_secret_api_key(request): return # PSAK bypasses object-level RBAC deliberately仅在没有 request 可用时使用
isinstance(user, ProjectSecretAPIKeyUser)。 -
report_user_action会丢弃合成用户 —— 如果你需要针对 PSAK 认证调用的分析数据,请用posthoganalytics.capture(distinct_id=user.distinct_id, ...)显式捕获,并包含一个auth_method属性,以便两条路径发出相同形状的事件。 -
HogQL 系统表:
Database.create_for会隐藏该密钥作用域未覆盖的 RBAC 作用域系统表(通过readable_system_table_access_scopes())。
当你需要分支时,可使用 posthog/permissions.py 中的辅助函数:is_authenticated_via_project_secret_api_key(request) 和 is_service_auth(request)(涵盖 PSAK + 旧版团队令牌)。
免费获得的功能
- 查询标记:认证器会调用
tag_authentication(access_method=AccessMethod.PROJECT_SECRET_API_KEY, api_key_mask=..., api_key_label=...),因此 ClickHousequery_log归因无需任何按端点的代码即可生效。如果你添加新的认证器,请通过tag_authentication(posthog/clickhouse/query_tagging.py中的唯一入口)进行标记 —— 而不是用临时的tag_queries调用。 last_used_at跟踪:最多每小时通过.update()更新一次(绕过ModelActivityMixin,这样常规认证不会刷爆活动日志)。- 密钥创建/更新/轮换/删除时的活动日志记录。
调用受 PSAK 保护的端点
curl -s https://us.posthog.com/api/environments/<project_id>/<your_action_path>/ \
-H "Authorization: Bearer phs_<key>" \
-H "Content-Type: application/json" \
-d '{...}'
测试
参照 posthog/api/test/test_authentication.py、posthog/test/test_permissions.py 和 posthog/test/test_rate_limit.py 中的 PSAK 部分。至少覆盖:
- 具有正确作用域的允许操作 → 200
- 操作不在
psak_allowed_actions中 → 403 - 缺失/错误的作用域 → 403
- 来自另一个团队项目的密钥 → 403
- 同一操作上的非 PSAK 认证仍然有效