OAuth 授权码流程

为什么叫「授权码」

Web 应用最常用的是授权码流程(Authorization Code)。它的核心设计是:浏览器只负责「拿一个短期、一次性的 code」,真正的令牌交换发生在服务端——这样 access token 永远不会暴露给浏览器,也绕开了浏览器存储令牌的安全难题。

完整流程

OAuth 授权码流程

用户步骤 1

点击「使用 GitHub 登录」

用户决定用第三方身份登录你的系统
你的系统步骤 2

重定向到第三方授权页

携带 client_id、scope、redirect_uri、state
第三方授权方步骤 3

用户确认授权范围

第三方展示「允许应用获取哪些信息」
第三方授权方步骤 4

第三方带 code 跳回你的系统

code 短期有效、一次性使用
你的系统步骤 5

校验 state 与 redirect_uri

防止 CSRF 与开放重定向
你的系统步骤 6

用 code 换取 access token

在服务端调用,不暴露给浏览器
你的系统步骤 7

获取用户信息并绑定本地账号

创建 / 关联本地用户,建立本地会话
安全要点: state 防 CSRF、redirect_uri 白名单校验、code 一次性短期有效、换 token 必须在服务端完成。

几个容易被忽略的细节

state:防 CSRF

state 是一个随机值,发起时带上,回调时校验是否一致。攻击者可以伪造一个「授权完成」的回调,但拿不到 state,就无法冒充流程完成。

redirect_uri:白名单

回跳地址必须严格匹配你预先注册的白名单。否则攻击者构造一个「授权成功 → 跳到钓鱼站」的链接(开放重定向),就能诱导用户授权后踩进陷阱。

code:短期、一次性

授权码是「换令牌的凭证」,必须短期有效、一次性使用。拿到 code 只换一次 token,换完作废。泄露的 code 即使被截获,也很快过期、无法重放。

换 token 必须在服务端

用 code 换 access token 的请求,要带着你的 client_secret,只能在服务端发,绝不能在前端代码里做(否则 secret 泄露,任何人都能冒充你的应用)。

为什么要分两步

有人会问:为什么不直接在回调里带 access token?

两步(code → token)的价值在于:

  1. access token 只出现在服务端到服务端的通道里,浏览器全程接触不到。
  2. 服务端可以在换 token 时校验 client_secret,确认「确实是我的应用在请求」。

这就是授权码流程比「隐式流程」更安全的原因——隐式流程把 token 直接给浏览器,通常不推荐用于敏感场景。

完成授权之后

拿到 access token 后:

  • 调用第三方的用户信息接口获取身份。
  • 在本地绑定或创建账号(下一节展开)。
  • 建立你自己的本地会话,用户就算「登录成功」了。

下一节看第三方账号怎么和本地账号绑定,以及 scope 最小权限。

发现内容有问题?

告诉我们哪里需要改进。