บทที่ 14 · Part 3 — API & Mobile Security

OAuth, OIDC & Service Authentication

Authorization Code + PKCE, OIDC, JWT/opaque token, BFF, refresh rotation, mTLS/DPoP, workload identity และ FAPI 2.0

mobile application ที่ฝัง client_secret ใน binary ไม่ได้เป็น confidential client เพราะผู้ที่ดาวน์โหลด application สามารถอ่าน secret ได้ หรือ API อาจรับ ID Token เป็น access token แล้วเปิด resource เพราะ claim ดูคล้ายกัน ทั้ง 2 กรณีเกิดจากการใช้ artifact ผิดบทบาทใน protocol

Learning Outcomes

  • แยก OAuth authorization, OIDC authentication และ API authorization ได้
  • ออกแบบ Authorization Code + PKCE พร้อม state/nonce/redirect validation ได้
  • เลือก public/confidential client และ browser BFF ตาม trust boundary ได้
  • validate opaque/JWT access token และ OIDC ID Token ตามชนิดได้
  • ป้องกัน refresh-token theft ด้วย rotation/reuse detection หรือ sender constraint ได้
  • เลือก workload identity, private_key_jwt, mTLS, DPoP และ FAPI profile ตาม use case ได้

OAuth และ OIDC แก้คนละปัญหา

Protocol/artifactหน้าที่
OAuthdelegated authorization เพื่อให้ client ขอ access token ไปเรียก resource server
OpenID Connectauthentication/federation layer บน OAuth ผ่าน ID Token และ UserInfo
Access tokencredential สำหรับ resource server ตาม audience/scope
ID Tokenassertion เกี่ยวกับ authentication event สำหรับ OIDC client
Refresh tokencredential ขอ access token ใหม่จาก authorization server

client ไม่ควรอ่าน access token เพื่อสรุป identity เว้นแต่ profile กำหนด และ resource server ไม่ควรรับ ID Token แทน access token

Actors และ Trust

  • Resource Owner / End User — ผู้อนุญาต access
  • Client — application ที่ขอ token
  • Authorization Server (AS) — authenticate/authorize และออก token
  • Resource Server (RS) — API ที่ตรวจ token และบังคับ resource authorization

OAuth ให้สิทธิ์ตาม delegation ไม่ได้บอกว่า subject ทำธุรกรรมใดก็ได้ Resource server ยังต้องตรวจ subject, scope, audience, object, tenant, state และ policy

Authorization Code + PKCE

RFC 9700 แนะนำ Authorization Code และใช้ PKCE กับทุก client type ที่เหมาะสม; Resource Owner Password Credentials grant ถูกห้าม และ implicit grant ไม่ควรถูกใช้ใน design ใหม่

PKCE:

code_verifier  = high-entropy random value held by client
code_challenge = BASE64URL(SHA256(code_verifier))
method         = S256

authorization server ผูก code กับ challenge และแลก code ได้เมื่อ verifier ตรง PKCE ลด code interception/injection แต่ไม่ authenticate public client, ไม่ sender-constrain access token, ไม่แก้ XSS และไม่แทน redirect/state validation

State, Nonce และ PKCE ไม่แทนกัน

Valueปกป้องหลัก
statebind authorization response กับ client transaction / CSRF defense
OIDC noncebind ID Token กับ authentication request และลด replay
PKCE verifierผู้แลก authorization code ต้องถือ secret ต่อ transaction

ค่าต้องสุ่ม/ผูก transaction, short-lived, single-use และ compare อย่างปลอดภัย อย่าใส่ open redirect, PII หรือ state ทั้งก้อนโดยไม่มี integrity/confidentiality design

Redirect URI ต้อง Exact

  • authorization server ใช้ exact registered redirect URI matching
  • native app ใช้ claimed HTTPS/app link เมื่อ platform รองรับ หรือ loopback/custom scheme ตาม RFC 8252
  • custom scheme อาจถูก application อื่น claim จึงต้องใช้ PKCE และ platform binding
  • native authorization ใช้ external user-agent ไม่ใช้ embedded WebView
  • client ตรวจ issuer/mix-up defenses ตาม protocol/profile

การ allow wildcard/subdomain/path กว้างทำให้ authorization code/token ถูกส่งไป endpoint ที่ attacker ควบคุม และ open redirect ใต้ allowlisted domain ยังเป็นความเสี่ยง

Public กับ Confidential Client

Clientรักษา long-lived credential ได้ตัวอย่าง
Publicไม่ได้mobile/native app, code ใน browser
Confidentialได้ภายใต้ server boundarybackend service, server-side web/BFF

secret ที่ฝังใน mobile/browser bundle เป็น public information ใช้ client_id ระบุ application ได้ แต่ห้ามถือ client secret นั้นเป็น authentication proof

Browser-Based Application และ BFF

RFC 10017 อธิบาย 3 pattern และให้ Backend-for-Frontend (BFF) เป็น pattern ที่ปลอดภัยที่สุด ในชุดนั้นสำหรับ application ที่จัดการ sensitive/personal data:

BFF ลด token exposure ต่อ browser JavaScript แต่เพิ่ม server/session/CSRF/scale responsibility และ XSS ยังสั่ง action ผ่าน authenticated BFF ได้ จึงต้องมี output/CSRF/authorization controls

Token Scope, Audience และ Resource

access token ควร:

  • มี audience/resource server ที่เจาะจง
  • scope/authorization details แคบเท่าที่ต้องใช้
  • lifetime สอดคล้องกับ theft/revocation risk
  • ไม่รวมหลาย audience โดยไม่จำเป็น
  • ไม่ใส่ข้อมูลละเอียดที่ consumer ไม่ต้องเห็น

resource server ต้องตรวจ audience ก่อน scope และตรวจ object/action/state ต่อ request scope transfers:write ไม่ได้อนุญาตให้โอนจากทุก account

Opaque Token กับ JWT

Opaque token มัก introspect กับ AS ส่วน JWT อาจ validate local ได้ Trade-off:

ConcernOpaqueJWT
Client visibilityไม่มี claim ให้ตีความpayload อ่านได้
Revocation/statecentral/introspection ง่ายกว่ามัก valid ถึง expiry ถ้าไม่มี state เพิ่ม
Availability/latencyพึ่ง introspection/cachelocal validation
Key/claim complexityอยู่ AS มากกว่าทุก RS ต้อง validate ถูกและ rotate key

OAuth client ควร treat access token เป็น opaque แม้ format เป็น JWT เพื่อไม่ผูกกับ implementation

JWT Access Token Validation

เมื่อ profile กำหนด JWT access token resource server ต้อง:

  • pin algorithm และ key source
  • verify signature/crypto input
  • ตรวจ exact issuer, intended audience และ expiry/not-before
  • ตรวจ token type เช่น typ=at+jwt ตาม RFC 9068 profile
  • ใช้ mutually exclusive validation rules ต่อ token type
  • ไม่ตาม jku/x5u URL อิสระจาก token
  • ตรวจ scope/claim แล้วทำ authorization กับ current resource state

JWT signature ไม่ให้ confidentiality และ token ไม่ได้ revocable โดยธรรมชาติ

OIDC ID Token Validation

OIDC client ตรวจอย่างน้อย:

  • iss ตรง issuer ที่เริ่ม transaction
  • aud มี client ID และจัดการหลาย audience ตาม spec
  • signature/key/algorithm ตาม metadata/policy
  • exp และ time claims
  • nonce ตรงเมื่อถูกส่งใน request
  • authorization code flow binding อื่นตาม OIDC/profile

ID Token ใช้กับ client authentication session ไม่ส่งไป resource API เป็น bearer access token

Refresh Token Theft

สำหรับ public client ที่ได้รับ refresh token RFC 9700 กำหนดให้ sender-constrain หรือใช้ refresh-token rotation เพื่อตรวจ replay

rotation flow:

  1. R1 แลก token สำเร็จ → ออก R2 และ mark R1 used
  2. R1 ถูกใช้อีก → สันนิษฐาน token copy/compromise
  3. revoke active token family/grant ตาม policy
  4. บังคับ authorization ใหม่และสร้าง telemetry

rotation ต้องเป็น atomic และมี family state ไม่ใช่เพียงออกค่าใหม่ ส่วน confidential/sender-constrained profile อาจมี requirement ต่างกัน ต้องไม่ผสมคำแนะนำต่าง profile โดยไม่ดู assumptions

Sender-Constrained Tokens

MechanismBind token กับจุดระวัง
OAuth mTLSclient certificate/private keycertificate lifecycle, proxy identity, key protection
DPoPapplication key + per-request proofreplay cache/nonce, endpoint normalization, key storage

DPoP proof ผูก key, HTTP method/URI และ token hash ตาม protocol แต่ไม่ sign request body/headers ส่วนใหญ่ จึงไม่ใช่ transaction signing ของ amount/beneficiary และทั้งคู่ไม่แทน TLS/authorization

Service-to-Service Authentication

ลำดับ preference ตาม platform/threat model:

  • workload identity + short-lived token/role
  • OAuth Client Credentials ด้วย asymmetric client auth
  • private_key_jwt หรือ mTLS
  • managed API key/HMAC เมื่อ protocol/partner จำกัด พร้อม rotation/replay controls
  • หลีกเลี่ยง shared long-lived secret ที่กระจายหลาย service

service identity ต้องมี owner, environment/audience, least privilege, rotation/revoke, telemetry และ blast radius แยกจาก end-user delegation อย่าให้ backend service แอบกลายเป็น global admin

FAPI 2.0 สำหรับ High-Value APIs

FAPI 2.0 Security Profile เป็น OpenID Final profile สำหรับ high-security APIs และ confidential clients โดยรวม Authorization Code, PKCE S256, client-authenticated PAR, issuer checks, asymmetric client authentication และ sender-constrained access tokens

ไม่ควรหยิบ requirement บางข้อออกมาโดยไม่ใช้ profile assumptions/interoperability tests ทั้งชุด และการใช้ FAPI ไม่แทน transaction authorization, fraud control, data protection หรือ compliance review

OAuth 2.1 ยังไม่ใช่ Final Standard

ณ baseline ของคอร์ส OAuth 2.1 ยังเป็น IETF Internet-Draft จึงอ้าง RFC 9700 และ RFC ที่ final เป็น normative source พร้อมระบุ draft status เมื่อกล่าวถึง OAuth 2.1

Common Failures

  • ใช้ implicit หรือ password grant ใน design ใหม่
  • mobile/browser ฝัง client secret แล้วถือว่า confidential
  • redirect URI wildcard/open redirect
  • ไม่ผูก state/nonce/PKCE กับ transaction เดียวกัน
  • resource server ไม่ตรวจ audience หรือรับ ID Token
  • JWT เลือก algorithm/key URL จาก untrusted header
  • refresh token ไม่มี rotation/reuse detection หรือ sender constraint
  • token มี scope/audience/expiry กว้างเกิน
  • DPoP/mTLS ถูกอ้างว่า sign transaction body
  • log authorization code/access/refresh/ID token

Testing Checklist

  • OAuth, OIDC, access token และ ID Token ถูกใช้ตามบทบาท
  • Authorization Code + PKCE S256; ไม่มี implicit/ROPC ใน design ใหม่
  • state/nonce/verifier single-use, short-lived และ bind transaction
  • redirect URI exact และ native app ใช้ external user-agent
  • public client ไม่มี embedded secret ที่ใช้เป็น proof
  • browser architecture ประเมิน BFF/session/CSRF/XSS trade-off
  • RS ตรวจ issuer/audience/type/time/scope และ resource authorization
  • refresh token มี rotation+reuse detection หรือ sender constraint ตาม profile
  • mTLS/DPoP มี key/replay lifecycle และไม่ถูกอ้างว่า sign body
  • service credential เป็น short-lived, scoped, revocable และ auditable

สรุป

OAuth/OIDC security ขึ้นกับการใช้ artifact ตามบทบาท, transaction binding และ validation ครบ PKCE ป้องกัน code flow บาง threat, sender constraint ลด bearer theft และ FAPI กำหนด profile สำหรับ high-value API แต่ resource authorization และ transaction integrity ยังต้องออกแบบแยก

Further Reading