OAuth 2.0 คือ Authorization Framework ที่ใช้สำหรับมอบสิทธิ์ให้แอปพลิเคชันเข้าถึงทรัพยากรหรือ API โดยไม่จำเป็นต้องส่ง username และ password ของผู้ใช้ให้กับแอปพลิเคชันนั้นโดยตรง

ตัวอย่างที่พบได้บ่อย เช่น

  • แอปต้องการอ่านข้อมูลโปรไฟล์จากระบบอื่น
  • Web Application ต้องการเรียก API ในนามของผู้ใช้
  • Mobile Application ต้องการเข้าถึงบริการ Cloud
  • Microservice ต้องการเรียก API ของอีก Service
  • ระบบต้องการรองรับ Login with Google หรือ Login with Microsoft

อย่างไรก็ตาม ต้องแยกให้ชัดเจนว่า

OAuth 2.0 เน้น Authorization หรือการให้สิทธิ์

หากต้องการ Authentication หรือการยืนยันว่า “ผู้ใช้คือใคร” โดยทั่วไปจะใช้ OpenID Connect (OIDC) ซึ่งสร้างอยู่บน OAuth 2.0


#1. ปัญหาที่ OAuth 2.0 เข้ามาแก้

สมมติว่าผู้ใช้มีรูปภาพอยู่ใน Cloud Storage และต้องการอนุญาตให้แอป Photo Printing อ่านรูปบางส่วน

แนวทางที่ไม่เหมาะสมคือ

User
 |
 | username + password
 v
Photo Printing App
 |
 v
Cloud Storage

ปัญหาคือแอป Photo Printing ต้องทราบรหัสผ่านจริงของผู้ใช้

OAuth 2.0 เปลี่ยนแนวคิดเป็น

User
 |
 | Login + Consent
 v
Authorization Server
 |
 | Access Token
 v
Client Application
 |
 | Bearer Token
 v
Resource Server / API

Client ได้รับ Token สำหรับสิทธิ์เฉพาะที่ผู้ใช้อนุญาต โดยไม่ต้องทราบรหัสผ่านจริงของผู้ใช้


#2. บทบาทหลักของ OAuth 2.0

OAuth 2.0 มีองค์ประกอบสำคัญ 4 บทบาท

บทบาท หน้าที่
Resource Owner เจ้าของข้อมูลหรือเจ้าของสิทธิ์ โดยทั่วไปคือผู้ใช้
Client แอปพลิเคชันที่ต้องการขอสิทธิ์
Authorization Server ระบบที่รับผิดชอบการอนุญาตและออก Token
Resource Server API หรือ Server ที่เก็บ Protected Resource

ตัวอย่าง Architecture

flowchart LR
    U[Resource Owner / User]
    C[Client Application]
    AS[Authorization Server]
    API[Resource Server / API]

    U --> C
    C --> AS
    AS --> C
    C --> API

#3. Token ที่ควรรู้จัก

#3.1 Access Token

Access Token คือ Credential ที่ Client ใช้เพื่อเรียก Protected API

ตัวอย่าง

GET /api/profile HTTP/1.1
Host: api.example.com
Authorization: Bearer ACCESS_TOKEN

Access Token ควร

  • มีอายุจำกัด
  • มี Scope เท่าที่จำเป็น
  • ไม่ถูกบันทึกลง Log
  • ไม่ส่งผ่าน URL Query String
  • ส่งผ่าน HTTPS เท่านั้น

#3.2 Refresh Token

Refresh Token ใช้สำหรับขอ Access Token ใหม่เมื่อ Access Token หมดอายุ โดยไม่ต้องให้ผู้ใช้ Login ใหม่ทุกครั้ง

ตัวอย่าง

POST /oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&
refresh_token=REFRESH_TOKEN&
client_id=my-client

Refresh Token มีความอ่อนไหวสูง เพราะสามารถใช้สร้าง Access Token ใหม่ได้

สำหรับ Public Client แนวทางสมัยใหม่ควรพิจารณา

  • Refresh Token Rotation
  • Sender-Constrained Refresh Token

#3.3 Authorization Code

Authorization Code เป็น Code อายุสั้นที่ Authorization Server ส่งกลับมายัง Client หลังผู้ใช้อนุญาต

Authorization Server
       |
       | authorization_code
       v
Client
       |
       | code + code_verifier
       v
Token Endpoint
       |
       | access_token
       v
Client

Authorization Code ไม่ใช่ Access Token และไม่ควรนำไปเรียก API โดยตรง


#4. Scope คืออะไร

scope ใช้กำหนดขอบเขตสิทธิ์ของ Token

ตัวอย่าง

profile
email
read:orders
write:orders
admin

ตัวอย่าง Authorization Request

scope=profile email read:orders

หลักการสำคัญคือ Least Privilege

กล่าวคือ Client ควรขอเฉพาะสิทธิ์ที่จำเป็นต่อการทำงานเท่านั้น

ตัวอย่าง

หากแอปต้องการเพียงอ่านรายการสินค้า

ควรใช้

products.read

แทน

products.*

#5. Authorization Code Flow + PKCE

สำหรับ Web Application, SPA, Mobile Application และ Native Application แนวทางสมัยใหม่ควรใช้ Authorization Code Flow ร่วมกับ PKCE

PKCE ย่อมาจาก

Proof Key for Code Exchange

PKCE ช่วยลดความเสี่ยงกรณี Authorization Code ถูกขโมยหรือดักระหว่าง Flow


#5.1 ภาพรวม Authorization Code + PKCE

sequenceDiagram
    participant U as User
    participant C as Client
    participant AS as Authorization Server
    participant API as Resource Server

    C->>C: สร้าง code_verifier
    C->>C: สร้าง code_challenge

    C->>AS: Authorization Request + code_challenge
    AS->>U: Login + Consent
    U->>AS: Approve

    AS-->>C: Authorization Code

    C->>AS: Code + code_verifier
    AS->>AS: Verify PKCE
    AS-->>C: Access Token

    C->>API: Authorization: Bearer Access Token
    API-->>C: Protected Resource

#5.2 สร้าง Code Verifier

Client สร้างค่า Random ที่คาดเดาได้ยาก

ตัวอย่างเชิงแนวคิด

code_verifier =
9sPqgKz8rQ6m1V2nY7jL4wXc0Bf5Da...

#5.3 สร้าง Code Challenge

โดยทั่วไปใช้ Method แบบ S256

code_challenge =
BASE64URL(SHA256(code_verifier))

#5.4 ส่ง Authorization Request

ตัวอย่าง

GET https://auth.example.com/authorize
    ?response_type=code
    &client_id=web-demo
    &redirect_uri=https://app.example.com/callback
    &scope=profile%20email
    &state=random-state
    &code_challenge=CHALLENGE_VALUE
    &code_challenge_method=S256

พารามิเตอร์สำคัญ

Parameter ความหมาย
response_type สำหรับ Authorization Code ใช้ code
client_id รหัส Client
redirect_uri URL ที่รับ Authorization Response
scope สิทธิ์ที่ต้องการ
state ใช้ผูก Request/Response และช่วยลดความเสี่ยง CSRF ในหลายรูปแบบการใช้งาน
code_challenge ค่าที่สร้างจาก code_verifier
code_challenge_method ควรใช้ S256

#5.5 ผู้ใช้ Login และ Consent

Authorization Server จะแสดงหน้า Login และ Consent

ตัวอย่าง

Application ABC ต้องการ:

✓ อ่านข้อมูล Profile
✓ อ่าน Email Address

[Allow] [Cancel]

เมื่อผู้ใช้กด Allow ระบบจะ Redirect กลับไปยัง Client

https://app.example.com/callback
    ?code=AUTHORIZATION_CODE
    &state=random-state

#5.6 แลก Authorization Code เป็น Access Token

Client ส่ง Code และ code_verifier ไปยัง Token Endpoint

curl -X POST https://auth.example.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=web-demo" \
  -d "code=AUTHORIZATION_CODE" \
  -d "redirect_uri=https://app.example.com/callback" \
  -d "code_verifier=ORIGINAL_CODE_VERIFIER"

ตัวอย่าง Response

{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "refresh_token": "def50200...",
  "scope": "profile email"
}

#6. Client Credentials Flow

Client Credentials เหมาะสำหรับ Machine-to-Machine หรือ Service-to-Service

ตัวอย่าง

Order Service
     |
     | client_id + client_secret
     v
Authorization Server
     |
     | access_token
     v
Inventory API

ตัวอย่าง Request

curl -X POST https://auth.example.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=order-service" \
  -d "client_secret=CLIENT_SECRET" \
  -d "scope=inventory.read"

เหมาะกับ

  • Microservices
  • Scheduled Jobs
  • Backend Applications
  • CI/CD Integration
  • Server-to-Server API

ไม่ควรฝัง client_secret ใน SPA หรือ Mobile Application เพราะเป็น Public Client และไม่สามารถเก็บ Secret ให้เป็นความลับได้จริง


#7. Device Authorization Grant

Device Authorization Grant เหมาะสำหรับอุปกรณ์ที่มีข้อจำกัดด้านการป้อนข้อมูล เช่น

  • Smart TV
  • Game Console
  • Printer
  • IoT Device

ภาพรวม

Device
  |
  | ขอ device_code
  v
Authorization Server
  |
  | user_code + verification_uri
  v
Device แสดง Code

User เปิด Browser บน Smartphone
  |
  | เปิด verification_uri
  | กรอก user_code
  v
Authorization Server

Device ตรวจสถานะ
  |
  v
Access Token

#8. OAuth 2.0 กับ OpenID Connect ต่างกันอย่างไร

OAuth 2.0 และ OpenID Connect มีความสัมพันธ์กัน แต่ไม่ได้มีหน้าที่เหมือนกัน

OAuth 2.0 OpenID Connect
เน้น Authorization เน้น Authentication
ใช้สำหรับให้สิทธิ์ API ใช้สำหรับระบุตัวผู้ใช้
มี Access Token เพิ่ม ID Token
ไม่ได้กำหนด Identity Protocol โดยตรง กำหนดข้อมูล Identity ผ่าน Claims

หากต้องการ

Login with Google
Login with Microsoft
Login with Identity Provider

โดยทั่วไปควรใช้ OpenID Connect


#9. OAuth 2.0 กับ JWT เหมือนกันหรือไม่

ไม่เหมือนกัน

OAuth 2.0 เป็น Authorization Framework

JWT เป็นรูปแบบ Token

OAuth 2.0 ไม่ได้กำหนดว่า Access Token ต้องเป็น JWT เสมอไป

Access Token สามารถเป็น Opaque Token

2YotnFZFEjr1zCsicMWpAA

หรือ JWT

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...

ดังนั้น

OAuth Token ≠ JWT เสมอไป

#10. Flow ที่ไม่ควรใช้กับระบบใหม่

#10.1 Resource Owner Password Credentials Grant

Flow นี้ให้ Client รับ username/password ของผู้ใช้โดยตรง

User
 |
 | username/password
 v
Client
 |
 v
Authorization Server

แนวทาง Security ปัจจุบันไม่แนะนำและกำหนดไม่ให้ใช้ Flow นี้กับระบบใหม่

สาเหตุ เช่น

  • Client เห็น Password ของผู้ใช้
  • เพิ่ม Attack Surface
  • ไม่เหมาะกับ MFA
  • ขัดกับแนวคิด Delegated Authorization

#10.2 Implicit Grant

Implicit Grant เคยนิยมใน SPA รุ่นเก่า

ตัวอย่าง

response_type=token

แนวทางระบบใหม่ควรใช้

Authorization Code + PKCE

แทน


#11. Security Best Practices

ระบบ OAuth 2.0 สมัยใหม่ควรพิจารณาอย่างน้อยดังนี้

  1. ใช้ Authorization Code + PKCE สำหรับ Redirect-Based User Flow
  2. ใช้ code_challenge_method=S256
  3. ใช้ HTTPS/TLS
  4. ลงทะเบียน redirect_uri ล่วงหน้า
  5. ตรวจ redirect_uri แบบ Exact Match
  6. หลีกเลี่ยง Open Redirect
  7. จำกัด Scope ตามหลัก Least Privilege
  8. ให้ Access Token มีอายุสั้น
  9. ไม่เก็บ Client Secret ใน SPA/Mobile App
  10. ไม่ส่ง Token ผ่าน URL Query Parameter
  11. ไม่ Log Access Token หรือ Refresh Token
  12. ใช้ Refresh Token Rotation สำหรับ Public Client เมื่อเหมาะสม
  13. ป้องกัน Authorization Code Injection
  14. ตรวจ State/Transaction Binding ตาม Flow ที่ใช้งาน
  15. รองรับ Token Revocation เมื่อต้องการยกเลิกสิทธิ์
  16. พิจารณา Sender-Constrained Token เช่น DPoP หรือ mTLS สำหรับระบบ Security สูง
  17. ตรวจ Scope ก่อนอนุญาตให้เข้าถึง Resource
  18. หากใช้ JWT Access Token ให้ตรวจ Signature, Issuer, Audience และ Expiration อย่างถูกต้อง

#12. การเรียก API ด้วย Access Token

ตัวอย่าง

curl https://api.example.com/profile \
  -H "Authorization: Bearer ACCESS_TOKEN"

Resource Server ต้องตรวจสอบ Token ก่อนตอบกลับ

ตัวอย่าง Response

{
  "id": 101,
  "name": "Demo User",
  "email": "demo@example.com"
}

#13. Architecture สำหรับ Web Application

flowchart LR
    U[User / Browser]
    C[Web Application]
    AS[Authorization Server]
    API[Resource Server]

    U --> C
    C -->|Authorize + PKCE| AS
    AS -->|Authorization Code| C
    C -->|Code + Verifier| AS
    AS -->|Access Token| C
    C -->|Bearer Token| API
    API -->|Protected Resource| C

#14. OAuth 2.0 สำหรับ SPA และ Browser-Based Application

สำหรับ SPA หรือ Browser-Based Application รุ่นใหม่ แนวทางปัจจุบันให้ความสำคัญกับ Authorization Code + PKCE

SPA
 |
 | Authorization Code + PKCE
 v
Authorization Server
 |
 | Access Token
 v
API

อย่างไรก็ตาม Browser มีความเสี่ยงจาก JavaScript และ Cross-Site Scripting

ระบบที่ต้องการลดการเปิดเผย Token ต่อ JavaScript สามารถใช้รูปแบบ Backend for Frontend (BFF)

flowchart LR
    B[Browser]
    BFF[Backend for Frontend]
    AS[Authorization Server]
    API[Protected API]

    B -->|Secure Session Cookie| BFF
    BFF --> AS
    AS -->|Tokens| BFF
    BFF -->|Access Token| API

ข้อดีคือ Token สามารถเก็บไว้ฝั่ง Backend แทนการเก็บไว้ใน Browser โดยตรง


#15. Workshop: จำลอง OAuth 2.0 Authorization Code + PKCE

สมมติ Configuration

Authorization Endpoint:
https://auth.example.com/authorize

Token Endpoint:
https://auth.example.com/oauth/token

Client ID:
web-demo

Redirect URI:
http://localhost:3000/callback

#Step 1: Authorization Request

GET /authorize
    ?response_type=code
    &client_id=web-demo
    &redirect_uri=http://localhost:3000/callback
    &scope=profile
    &state=abc123
    &code_challenge=XYZ
    &code_challenge_method=S256

#Step 2: Login และ Consent

ผู้ใช้เข้าสู่ระบบและกดอนุญาต

User
 |
 | Login
 | Consent
 v
Authorization Server

#Step 3: Callback

http://localhost:3000/callback
    ?code=AUTH_CODE
    &state=abc123

Client ตรวจสอบ state ก่อนดำเนินการต่อ


#Step 4: Token Exchange

curl -X POST https://auth.example.com/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "client_id=web-demo" \
  -d "code=AUTH_CODE" \
  -d "redirect_uri=http://localhost:3000/callback" \
  -d "code_verifier=VERIFIER"

#Step 5: เรียก Protected API

curl https://api.example.com/me \
  -H "Authorization: Bearer ACCESS_TOKEN"

#16. Checklist ก่อนนำขึ้น Production

[ ] ใช้ HTTPS
[ ] ใช้ Authorization Code + PKCE
[ ] ใช้ PKCE แบบ S256
[ ] redirect_uri ถูกลงทะเบียน
[ ] redirect_uri ตรวจแบบ exact match
[ ] ไม่มี open redirect
[ ] scope ไม่กว้างเกินจำเป็น
[ ] access token มีอายุเหมาะสม
[ ] refresh token ถูกเก็บอย่างปลอดภัย
[ ] public client มี refresh-token replay protection
[ ] token ไม่ปรากฏใน log
[ ] ไม่ส่ง token ผ่าน query string
[ ] มี CSRF/transaction protection
[ ] มี revoke/logout strategy
[ ] API ตรวจ scope
[ ] JWT validation ตรวจ signature/issuer/audience/expiry

#17. เลือก Flow แบบไหนดี

กรณีใช้งาน Flow / Protocol ที่แนะนำ
Web Application Authorization Code + PKCE
SPA Authorization Code + PKCE
Mobile Application Authorization Code + PKCE
Native Desktop App Authorization Code + PKCE
Service-to-Service Client Credentials
Smart TV / Console Device Authorization Grant
Login / SSO OpenID Connect
Public Client ห้ามพึ่ง Client Secret เป็นหลักฐานความลับ
ระบบใหม่ หลีกเลี่ยง Implicit และ Password Grant

#18. สรุป

OAuth 2.0 เป็นกลไกมาตรฐานสำหรับ Delegated Authorization ที่ช่วยให้ Client เข้าถึง API โดยไม่ต้องได้รับรหัสผ่านของผู้ใช้

แนวคิดหลักสามารถสรุปได้ดังนี้

User
 |
 | Authorization
 v
Authorization Server
 |
 | Authorization Code
 v
Client
 |
 | Code + PKCE
 v
Authorization Server
 |
 | Access Token
 v
Protected API

สิ่งที่ควรจำสำหรับระบบสมัยใหม่คือ

  • Web / SPA / Mobile → Authorization Code + PKCE
  • Machine-to-Machine → Client Credentials
  • Input-Constrained Device → Device Authorization Grant
  • Authentication / Login → OpenID Connect
  • Access Token ไม่จำเป็นต้องเป็น JWT
  • ใช้ Scope ตามหลัก Least Privilege
  • Access Token ควรมีอายุสั้น
  • ปกป้อง Refresh Token
  • หลีกเลี่ยง Implicit Grant และ Password Grant สำหรับระบบใหม่
  • ให้ความสำคัญกับ Redirect URI, PKCE, Token Storage และ Token Validation

#เอกสารอ้างอิง

  • RFC 6749 — The OAuth 2.0 Authorization Framework
  • RFC 6750 — The OAuth 2.0 Authorization Framework: Bearer Token Usage
  • RFC 7009 — OAuth 2.0 Token Revocation
  • RFC 7636 — Proof Key for Code Exchange by OAuth Public Clients
  • RFC 8252 — OAuth 2.0 for Native Apps
  • RFC 8628 — OAuth 2.0 Device Authorization Grant
  • RFC 9700 — Best Current Practice for OAuth 2.0 Security
  • RFC 10017 — OAuth 2.0 for Browser-Based Applications