本页目录

OAuth2 与 OpenID Connect

OAuth2 是授权框架(让应用以你的名义访问你的资源),OIDC 在它之上加了一层认证(让应用确认你是谁)。authorization code + PKCE 是当前最佳实践,implicit flow 已死。

概述

OAuth2(RFC 6749, 2012)是互联网授权的标准框架——"让第三方应用访问我的资源,但不需要我的密码"。核心是 Authorization Code + PKCE 流程:浏览器重定向到授权服务器 → 用户登录 → 浏览器携带 code 返回 → client 用 code 换 access token。OIDC(OpenID Connect, 2014)在 OAuth2 上加入身份认证(id_token),成为"Login with Google/GitHub"的基础。JWT 是 OAuth2 最常用的 access token 格式——自包含、可验证、无状态。

OAuth2: 授权 (不是认证)

四个角色:
  Resource Owner: 用户
  Client: 第三方应用
  Authorization Server: 授权服务器
  Resource Server: API 服务器

Authorization Code + PKCE (唯一推荐的 web flow):
  1. Client: 生成 code_verifier (随机), code_challenge = SHA256(verifier)
  2. Browser redirect:
     GET /authorize?response_type=code
       &client_id=grafana
       &redirect_uri=https://grafana.example.com/login/callback
       &scope=openid profile email
       &state=random123
       &code_challenge=<base64url(challenge)>
       &code_challenge_method=S256
  3. User 登录 + consent
  4. Browser redirect back: https://grafana.example.com/login/callback?code=AUTH_CODE&state=random123
  5. Client → Authorization Server (backchannel):
     POST /token
     grant_type=authorization_code
     &code=AUTH_CODE
     &redirect_uri=...
     &code_verifier=<verifier>  ← server 验证 SHA256(verifier)==challenge
  6. Response: { "access_token", "refresh_token", "id_token", "token_type":"Bearer", "expires_in":3600 }
  7. Client: 用 access_token 请求 API (Authorization: Bearer <token>)

PKCE 为什么需要

传统 flow 中 code 可以被拦截 (mobile app 的 redirect URI 可能被其他 app 注册)。PKCE 保证即使 code 泄露,没有 code_verifier 也换不来 token。

JWT

格式: base64(header).base64(payload).signature

Header: {"alg":"RS256","typ":"JWT","kid":"key-2025"}
Payload (claims):
  iss: 签发者
  sub: 用户 ID (subject)
  aud: 接收方 (audience, 此 token 给谁用)
  exp: 过期时间 (unix)
  iat: 签发时间
  email, name, groups: 自定义 claims

Signature: RSA-SHA256(base64(header)+"."+base64(payload))

验证:
  1. 获取 JWKS (https://auth.example.com/.well-known/jwks.json) → 取 kid 对应公钥
  2. 验证签名
  3. 检查 exp (未过期), aud (此 token 是给我的), iss (来自信任的 issuer)

OpenID Connect (OIDC)

OIDC = OAuth2 + 用户身份 (id_token):

id_token (JWT): 给 client 证明"用户是谁" (不是用来调 API 的)
access_token:   给 API 证明"client 有权访问" (不包含用户信息)

Client Credentials (机器间)

POST /token
  grant_type=client_credentials
  &client_id=my-app
  &client_secret=secret

→ { "access_token":"...", "expires_in":3600 }
→ 没有用户参与

参考

  • jwt.io: debug JWT
  • Keycloak: open source identity provider
  • OIDC playground: openidconnect.net

Keywords: OAuth2, PKCE, JWT, OIDC, id_token, client credentials, JWKS, Keycloak