oauth-implementation

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OAuth Implementation

OAuth 实现

Implement OAuth 2.0 and OpenID Connect for secure authentication.
实现OAuth 2.0和OpenID Connect以保障安全认证。

OAuth 2.0 Flows

OAuth 2.0 流程

FlowUse Case
Authorization CodeWeb apps (most secure)
Authorization Code + PKCESPAs, mobile apps
Client CredentialsService-to-service
Refresh TokenSession renewal
流程使用场景
授权码流程Web应用(安全性最高)
授权码流程 + PKCE单页应用(SPA)、移动应用
客户端凭证流程服务间通信
刷新令牌流程会话续期

Authorization Code Flow (Express)

授权码流程(Express 实现)

javascript
const express = require('express');
const jwt = require('jsonwebtoken');

// Step 1: Redirect to authorization
app.get('/auth/login', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex');
  req.session.oauthState = state;

  const params = new URLSearchParams({
    client_id: process.env.CLIENT_ID,
    redirect_uri: process.env.REDIRECT_URI,
    response_type: 'code',
    scope: 'openid profile email',
    state
  });

  res.redirect(`${PROVIDER_URL}/authorize?${params}`);
});

// Step 2: Handle callback
app.get('/auth/callback', async (req, res) => {
  if (req.query.state !== req.session.oauthState) {
    return res.status(400).json({ error: 'Invalid state' });
  }

  const tokenResponse = await fetch(`${PROVIDER_URL}/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: req.query.code,
      redirect_uri: process.env.REDIRECT_URI,
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET
    })
  });

  const tokens = await tokenResponse.json();
  // Store tokens securely and create session
});
javascript
const express = require('express');
const jwt = require('jsonwebtoken');

// Step 1: Redirect to authorization
app.get('/auth/login', (req, res) => {
  const state = crypto.randomBytes(16).toString('hex');
  req.session.oauthState = state;

  const params = new URLSearchParams({
    client_id: process.env.CLIENT_ID,
    redirect_uri: process.env.REDIRECT_URI,
    response_type: 'code',
    scope: 'openid profile email',
    state
  });

  res.redirect(`${PROVIDER_URL}/authorize?${params}`);
});

// Step 2: Handle callback
app.get('/auth/callback', async (req, res) => {
  if (req.query.state !== req.session.oauthState) {
    return res.status(400).json({ error: 'Invalid state' });
  }

  const tokenResponse = await fetch(`${PROVIDER_URL}/token`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: req.query.code,
      redirect_uri: process.env.REDIRECT_URI,
      client_id: process.env.CLIENT_ID,
      client_secret: process.env.CLIENT_SECRET
    })
  });

  const tokens = await tokenResponse.json();
  // Store tokens securely and create session
});

PKCE for Public Clients

面向公开客户端的PKCE实现

javascript
function generatePKCE() {
  const verifier = crypto.randomBytes(32).toString('base64url');
  const challenge = crypto
    .createHash('sha256')
    .update(verifier)
    .digest('base64url');
  return { verifier, challenge };
}
javascript
function generatePKCE() {
  const verifier = crypto.randomBytes(32).toString('base64url');
  const challenge = crypto
    .createHash('sha256')
    .update(verifier)
    .digest('base64url');
  return { verifier, challenge };
}

Security Requirements

安全要求

  • Always use HTTPS
  • Validate redirect URIs strictly
  • Use PKCE for public clients
  • Store tokens in HttpOnly cookies
  • Implement token rotation
  • Use short-lived access tokens (15 min)
  • 始终使用HTTPS
  • 严格验证重定向URI
  • 为公开客户端使用PKCE
  • 将令牌存储在HttpOnly Cookie中
  • 实现令牌轮转机制
  • 使用短期访问令牌(15分钟)

Additional Implementations

更多实现示例

See references/python-java.md for:
  • Python Flask with Authlib OIDC provider
  • OpenID Connect discovery and JWKS endpoints
  • Java Spring Security OAuth2 server
  • Token introspection and revocation
查看 references/python-java.md 获取以下内容:
  • 基于Authlib OIDC提供者的Python Flask实现
  • OpenID Connect 发现与JWKS端点
  • Java Spring Security OAuth2 服务器
  • 令牌内省与吊销

Never Do

禁止操作

  • Store tokens in localStorage
  • Use implicit flow
  • Skip state parameter validation
  • Expose client secrets in frontend
  • Use long-lived access tokens
  • 将令牌存储在localStorage中
  • 使用隐式流程
  • 跳过state参数验证
  • 在前端暴露客户端密钥
  • 使用长期访问令牌