OAuth 2.0 และ OpenID Connect เบื้องต้น

OAuth 2.0 คือมาตรฐานการมอบสิทธิ์ หรือ Authorization ให้แอปหนึ่งเข้าถึง resource ในนามผู้ใช้ ส่วน OpenID Connect (OIDC) เพิ่มชั้น Authentication เพื่อยืนยันตัวตนผู้ใช้บน OAuth 2.0

Timeline/ประวัติศาสตร์

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
flowchart LR
  subgraph Era1["ยุค Password Sharing / Risky Access"]
    A["ให้รหัสผ่านกับแอปอื่น
เสี่ยงสูง"] end subgraph Era2["ยุค OAuth / Delegated Authorization"] B["OAuth 2.0
มอบสิทธิ์แบบ token"] C["Authorization Code
เหมาะกับเว็บ"] end subgraph Era3["ยุค OIDC / Identity Layer"] D["OpenID Connect
ยืนยันตัวตน"] E["ID Token
ข้อมูลผู้ใช้ใน JWT"] end A --> B --> C --> D --> E

แนวคิดสำคัญ

ตาราง Grant Types

Grant Type เหมาะกับ หมายเหตุ
Authorization Code Web app, SPA with PKCE แนะนำสำหรับ login
Implicit SPA เก่า ไม่แนะนำในระบบใหม่
Client Credentials Server-to-Server ไม่มี user โดยตรง
Refresh Token ต่ออายุ access token ต้องเก็บอย่างปลอดภัย

Mermaid Diagram: Authorization Code Flow

%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#fabd2f", "primaryTextColor": "#282828", "primaryBorderColor": "#b57614", "lineColor": "#7c6f64", "secondaryColor": "#83a598", "tertiaryColor": "#b8bb26", "background": "#fbf1c7", "mainBkg": "#ebdbb2", "fontFamily": "Tahoma, sans-serif"}}}%%
sequenceDiagram
  participant U as User / ผู้ใช้
  participant A as App / แอปเรา
  participant P as Provider / Google GitHub
  U->>A: Click Login
  A->>P: Redirect to authorize
  P->>U: Login and consent
  P-->>A: Authorization Code
  A->>P: Exchange code for tokens
  P-->>A: Access Token + ID Token
  A-->>U: Logged in

Code Example

// passport-google-demo.mjs
// โครงสร้างตัวอย่าง Passport OAuth Strategy
import express from 'express';
import passport from 'passport';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';

const app = express();

passport.use(new GoogleStrategy({
  clientID: process.env.GOOGLE_CLIENT_ID,
  clientSecret: process.env.GOOGLE_CLIENT_SECRET,
  callbackURL: '/auth/google/callback'
}, (accessToken, refreshToken, profile, done) => {
  // ในระบบจริงควร find-or-create user ในฐานข้อมูล
  return done(null, {
    providerId: profile.id,
    name: profile.displayName,
    email: profile.emails?.[0]?.value
  });
}));

app.use(passport.initialize());

app.get('/auth/google',
  passport.authenticate('google', { scope: ['profile', 'email'] })
);

app.get('/auth/google/callback',
  passport.authenticate('google', { session: false }),
  (req, res) => res.json({ user: req.user })
);

app.listen(3000, () => console.log('OAuth demo on http://localhost:3000'));

// ตัวอย่างการใช้งาน:
// npm install express passport passport-google-oauth20
// ตั้งค่า GOOGLE_CLIENT_ID และ GOOGLE_CLIENT_SECRET ก่อนรัน

วิดีโอแนะนำ

กิจกรรมท้ายบท

กลับสัปดาห์ที่ 12