T
traeai
登录
返回首页
Stack Overflow Blog

OAuth 2.0 设备授权流详解

8.5Score

TL;DR · AI 摘要

OAuth 2.0 设备授权流详解,尤其适合后端工程师,通过简单流程实现无密码登录。

核心要点

  • 设备授权流适用于 CLI、IoT 设备等场景,无需手动输入密码。
  • 需正确处理五种响应类型,包括授权等待、速率限制、过期等。
  • 用户代码应短而易读,但不可猜测,推荐使用 8-9 个字符。

结构提纲

按章节快速跳转。

  1. 介绍设备授权流的背景及适用场景。

  2. 详细说明设备授权流的五个步骤及其交互过程。

  3. 列出常见的错误类型及应对策略。

  4. 提供设备授权流实现中的注意事项和优化建议。

思维导图

用一张图看清主题之间的关系。

查看大纲文本(无障碍 / 无 JS 友好)
  • OAuth 2.0 设备授权流
    • 适用场景
      • CLI
      • IoT 设备
    • 核心步骤
      • 请求代码
      • 用户验证
      • 获取令牌
    • 错误处理
      • 授权等待
      • 速率限制
      • 过期

金句 / Highlights

值得收藏与分享的关键句。

#OAuth 2.0#设备授权#后端开发#安全性
打开原文

标题:OAuth 2.0 – 设备授权流详解,尤其是面向后端工程师

来源链接:https://stackoverflow.blog/2026/05/11/oauth-2-0-device-flow-explained-for-engineers-especially-for-backend-engineers/

Markdown 内容:

第一次尝试在酒店电视上登录 Netflix 时,我差点放弃了。遥控器只有四个方向键和一个数字键盘。我的密码有18个字符,包含符号。设计登录屏幕的人要么自己从未使用过它,要么认为受苦能塑造性格。

几年后,同样的电视开始做些不同的事情。它们向我们展示了一个短码和一个 URL。我在手机上打开浏览器,输入 URL 和短码,然后就成功登录了。没有遥控器的杂耍,电视上也没有输入密码。

这就是 OAuth 2.0 的设备授权流程。大多数人只是简单地称之为“设备流”。

如果我们运行 aws sso logingh auth login,或者在 Xbox 上登录 Spotify,我们已经用过这个功能。如果你正在为命令行工具、物联网设备、智能电视应用或其他需要输入密码不方便或不安全的场景构建后端,迟早会需要实现它。

以下是逐步说明:

步骤1:假设我们在构建一个名为 mycli 的命令行工具。用户运行:

bash
$ mycli login

下面是在后台发生的事情。

步骤 1:CLI 请求获取验证码

CLI 向授权服务器发送 POST 请求:

code
POST /oauth/device_authorization HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
client_id=mycli-prod&scope=read:repos%20write:repos

服务器响应类似以下内容:

code
{
"device_code": "GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS",
"user_code": "WDJB-MJHT",
"verification_uri": "https://example.com/device",

"verification_uri_complete": "https://example.com/device?user_code=WDJB-
MJHT",

"expires_in": 1800,
"interval": 5

}

实际上有五个字段很重要:

device_code 是一个长且不透明的字符串。CLI 会将其私密保存。

user_code 是一个短且人类友好的字符串。CLI 会在屏幕上显示它。

verification_uri 是用户输入验证码的地方。

expires_in 是交换的有效时间。通常为15到30分钟。

interval 是 CLI 被允许多久轮询一次以获取令牌。稍后我们会提到这一点。

步骤 2:CLI 告诉用户该做什么

你的 CLI 会打印类似以下内容:

code
打开此 URL 在您的浏览器中:
https://example.com/device

输入此验证码:
  WDJB-MJHT
等待确认...

用户会在他们的手机或笔记本电脑上打开 URL,输入验证码,并通过单点登录正常登录并批准请求。

步骤 3:CLI 轮询令牌端点

当我们使用手机时,CLI 会进入循环,每隔五秒尝试联系服务器并获取状态:

code
POST /oauth/token HTTP/1.1
Host: auth.example.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:device_code
&device_code=GmRhmhcxhwAzkoEqiMEg_DnyEysNkuNhszIySk9eS
&client_id=mycli-prod

服务器的响应可能是以下五种情况之一,这是我们第一次实现时最容易出错的部分。

我们需要处理的五种响应:

Authorization_pending – 用户尚未批准

slow_down – 你轮询得太快了。RFC 规定你必须至少增加 5 秒的间隔。

expired_token – 交换超时,停止轮询。

access_denied – 用户点击了“否”或关闭了页面。停止轮询。

success – 令牌在响应体中,就像普通的 OAuth 响应:

code
{
"access_token": "eyJhbGciOi...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "v1.MRn7...",
"scope": "read:repos write:repos"
}

这就是整个协议。如果我们能够处理这五种情况,我们就有了一个可用的设备流客户端。

1. 将 `user_code` 当作秘密对待。 它不是。用户会在他们的手机上输入它。你的工作是让它足够短以便读取但又无法猜测。标准是去掉容易混淆的字符(没有 0、O、I、1),使用 8 到 9 个字母数字字符。GitHub 使用格式为 XXXX XXXX 的 8 个字符。这是一个不错的模板。

2. 验证页面没有速率限制。 用户输入 user_code 的端点是一个暴力破解的目标。即使是从缩减的字母表中生成的 9 位字符代码,也有足够的理论熵,但在任何给定时刻,待验证的代码数量可能达到数千。请加以限制。按 IP 地址、按会话、失败后指数退避。

3. 忽略 `slow_down`。 我见过一些客户端无论服务器说什么,都会永远以相同的间隔休眠。这在开发环境中可以工作。但在生产环境中,这会让你被标记为滥用行为。

4. 不在使用 `user_code` 后立即将其标记为已消费。 用户提交验证码后,立即将其标记为已使用。原子操作。如果你的检查-然后标记逻辑不是事务性的,那么你会遇到一个潜在的严重问题。

5. 将其与 PKCE 混淆。 设备流适用于输入受限的设备。PKCE 适用于无法保守秘密的公开客户端(移动应用、单页应用)。它们表面上看起来相似(没有客户端密钥),但解决的问题不同。有时你需要两者。设备流 + PKCE 是可行的,并且越来越常见。

设备流是一种在 RFC 中看起来复杂但实际上可以写在餐巾纸上的协议。两个端点,五种响应情况。一旦你实现了一次,你会想知道为什么有人曾经在电视上使用密码。

如果你今天正在发布一个 CLI 并仍然要求用户将个人访问令牌粘贴到提示符中,请为他们着想。花一个下午的时间来实现这个功能。你的用户会注意到的。

AI 可能会生成不准确的信息,请核实重要内容