一位客户向我发送了一封支持电子邮件,说他们在使用 API 密钥时遇到了问题。
Glama API 密钥的第一个版本只是随机的 UUID,特定的 API 密钥是:05e3d22f-640b-4257-9325-8c2a8144639f。但是,我在我们的数据库中找不到有关 API 密钥的任何信息,而且由于这只是一个随机的 UUID,因此没有太多可继续的信息。经过几次反复,我发现他们引用的 API 密钥是一个已删除帐户的密钥。然而,这次互动让我想重新考虑我们的 API 密钥格式。
研究很多大公司密钥发现:
- 许多 API 密钥都有一个前缀,用来表示密钥的类型(例如,sk- 表示 OpenAI 的秘钥,pk_ 表示 Stripe 的公钥,gsk_ 表示 Groq,pplx- 表示 Perplexity)。
- 有些密钥还包括后缀,用来表示环境(例如,Stripe 密钥中的 test)。
- 有些密钥用连字符或下划线分割。 据推测,这样做不仅是为了便于阅读,也是为了在密钥中对数据进行编码,以便对密钥进行分组(例如,Anthropic 密钥中的 api03 描述了 API 版本)。
- 长度差异很大,但大多数都很长(48 个字符以上)。
Sentry API 密钥 引起我注意的一个有趣例外是 Sentry API 密钥。
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 |
该密钥包含一个Base64URL编码的 JSON 对象,其结构如下:
sntrys_<encoded details>_<secret value> |
Base64URL 是 Base64 编码的一种变体,它对 URL 和文件名都是安全的。它分别使用“-”和“_”代替“+”和“/”,并且省略了填充字符。这使得它非常适合用于 URL 和文件名,而无需进行额外的编码。
有效负载是一个 JSON 对象,其结构如下:
{ "iat": 1729278581.081153, "url": "https://sentry.io", "region_url": "https://us.sentry.io", "org": "glama" } |
我喜欢 Sentry 格式的一点是,密钥本身编码了对故障排除有用的信息。
设计完美的 API 密钥 基于上述内容,以下是我对 API 密钥格式的设计:
- 该密钥应该有一个描述拥有该密钥的组织的前缀。
- 该密钥应该有一个稳定的片段,可以用作公钥标识符。
- 密钥本身应该对有助于故障排除的信息进行编码(例如用户 ID)。
具体对于 Glama 来说,其翻译为:
- glama_ 前缀
- 公钥标识符
- user ID
- secret (UUID)
<prefix>_<public key identifier>.<encoded payload> |
例子:
glama_bf0629ac.eyJ1c2VyIjoienQwdjFqcWN4OSIsInNlY3JldCI6ImJmMDYyOWFjLWFkNDgtNGYzMS1iMTFkLWIyMTZmYzMwNzFhMSJ9 |
解码为:
{ "user": "zt0v1jqcx9", "secret": "bf0629ac-ad48-4f31-b11d-b216fc3071a1" } |
这种 API 密钥的好处是:
- 可以识别出它属于 Glama。
- 可以通过 API 密钥的唯一公共标识符进行唯一识别。
- 这将是在仪表板中识别密钥的 ID。
- 可以通过解码 Base64URL 有效载荷来识别用户。
- 随着时间的推移,可以扩展以包含更多信息(例如 API 端点,如 Sentry 的情况)。
结论 API 密钥可以像随机 UUID 一样简单,但添加前缀并对有效负载进行编码可以提高可用性和故障排除能力。