โฟลว์ OAuth จากฟรอนต์เอนด์
ใช้โฟลว์ Authorization Code พร้อม PKCE ใน SPA แลกโค้ดเป็นโทเค็น จัดเก็บโทเค็นการเข้าถึงอย่างปลอดภัย และหลีกเลี่ยงโฟลว์แบบ implicit
โฟลว์ OAuth จากฟรอนต์เอนด์ เป็นบทเรียน Frontend Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Frontend Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน
OAuth คืออะไร
OAuth 2.0 เป็นโพรโทคอลสำหรับมอบสิทธิ์ แอปของคุณจะได้รับอนุญาตให้ดำเนินการแทนผู้ใช้กับบริการของบุคคลที่สาม (Google, GitHub และอื่น ๆ) โดยไม่ต้องเห็นรหัสผ่านของผู้ใช้เลย ใช้กับ 'Sign in with Google', แอป OAuth ของ GitHub และระบบยืนยันตัวตนสมัยใหม่ส่วนใหญ่
บทบาทสำคัญ
เจ้าของทรัพยากร: ผู้ใช้ ไคลเอ็นต์: แอปของคุณ เซิร์ฟเวอร์อนุญาต: ผู้ให้บริการ OAuth (Google, Auth0) เซิร์ฟเวอร์ทรัพยากร: API ที่ได้รับการป้องกันด้วยโทเค็นการเข้าถึง
โฟลว์รหัสการอนุญาต
โฟลว์มาตรฐานที่ปลอดภัยสำหรับแอปฝั่งเซิร์ฟเวอร์: 1) เปลี่ยนเส้นทางผู้ใช้ไปยังหน้าเข้าสู่ระบบของผู้ให้บริการ 2) ผู้ใช้เข้าสู่ระบบและให้ความยินยอม 3) ผู้ให้บริการเปลี่ยนเส้นทางกลับมาพร้อม รหัส 4) เซิร์ฟเวอร์แลกรหัสเป็น โทเค็นการเข้าถึง (ความลับที่ใช้เฉพาะบนเซิร์ฟเวอร์)
เหตุใดแอปหน้าเดียวจึงต้องใช้ PKCE
แอปหน้าเดียวไม่สามารถเก็บความลับของไคลเอ็นต์ได้ (เพราะความลับจะอยู่ในชุดไฟล์ของเบราว์เซอร์) PKCE (การพิสูจน์คีย์สำหรับการแลกรหัส) จะแทนที่ความลับด้วยตัวตรวจสอบและ challenge ที่สร้างขึ้นสำหรับแต่ละคำขอ ปัจจุบันนี่เป็นมาตรฐานสำหรับไคลเอ็นต์ OAuth สาธารณะทั้งหมด
โฟลว์ PKCE ทีละขั้นตอน
1) สร้าง code_verifier แบบสุ่ม 2) คำนวณค่า hash SHA-256 ของค่านี้เป็น code_challenge 3) เปลี่ยนเส้นทางไปยัง /authorize พร้อม challenge 4) หลังให้ความยินยอม รับรหัสกลับมา 5) แลกรหัส + ตัวตรวจสอบเป็นโทเค็นการเข้าถึง ผู้ให้บริการจะตรวจสอบว่า challenge = hash(verifier)
การสร้างตัวตรวจสอบและ challenge
ตัวตรวจสอบคือสตริงแบบสุ่ม ส่วน challenge คือค่าของตัวตรวจสอบที่เข้ารหัสเป็น base64-URL ด้วย SHA-256
function base64url(arr) {
return btoa(String.fromCharCode(...arr))
.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
}
async function generatePKCE() {
const arr = new Uint8Array(32);
crypto.getRandomValues(arr);
const verifier = base64url(arr);
const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier));
const challenge = base64url(new Uint8Array(hash));
return { verifier, challenge };
}การเปลี่ยนเส้นทางไปยังผู้ให้บริการ
สร้าง URL สำหรับการอนุญาตพร้อม challenge, state (การป้องกัน CSRF) และขอบเขต
const { verifier, challenge } = await generatePKCE();
const state = crypto.randomUUID();
sessionStorage.setItem('pkce_verifier', verifier);
sessionStorage.setItem('oauth_state', state);
const url = new URL('https://accounts.google.com/o/oauth2/v2/auth');
url.searchParams.set('client_id', CLIENT_ID);
url.searchParams.set('redirect_uri', `${origin}/auth/callback`);
url.searchParams.set('response_type', 'code');
url.searchParams.set('scope', 'openid email profile');
url.searchParams.set('code_challenge', challenge);
url.searchParams.set('code_challenge_method', 'S256');
url.searchParams.set('state', state);
window.location.href = url.toString();การจัดการคำขอย้อนกลับ
ผู้ให้บริการจะเปลี่ยนเส้นทางไปยัง URL สำหรับคำขอย้อนกลับของคุณพร้อม ?code=...&state=... ตรวจสอบ state เพื่อป้องกัน CSRF แล้วจึงแลกรหัส
// /auth/callback page:
const params = new URLSearchParams(window.location.search);
const code = params.get('code');
const returnedState = params.get('state');
const expected = sessionStorage.getItem('oauth_state');
if (returnedState !== expected) throw new Error('Bad state');
const verifier = sessionStorage.getItem('pkce_verifier');
const tokens = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'authorization_code',
code,
client_id: CLIENT_ID,
redirect_uri: `${origin}/auth/callback`,
code_verifier: verifier
})
}).then(r => r.json());
// tokens: { access_token, id_token, refresh_token, expires_in }การจัดเก็บโทเค็นอย่างปลอดภัย
แนวทางปฏิบัติที่ดีที่สุด: อย่าเก็บโทเค็นการเข้าถึงไว้ใน localStorage (เพราะอาจถูกขโมยด้วย XSS) ทางเลือก: 1) เก็บไว้ในหน่วยความจำเท่านั้น (จะถูกล้างเมื่อรีเฟรช จึงต้องยืนยันตัวตนใหม่) 2) คุกกี้ HttpOnly (ตั้งค่าโดยแบ็กเอนด์ของคุณหลังโฟลว์ PKCE และ JS ไม่สามารถขโมยได้)
หลีกเลี่ยงโฟลว์ Implicit
โฟลว์ Implicit แบบเก่าจะส่งโทเค็นการเข้าถึงกลับมาโดยตรงในส่วน fragment ของ URL OAuth 2.0 Security BCP ยกเลิกการแนะนำโฟลว์นี้แล้ว เพราะโทเค็นรั่วไหลไปยังประวัติเบราว์เซอร์และตัวอ้างอิง ให้ใช้โฟลว์รหัสการอนุญาต + PKCE เสมอ
โทเค็นรีเฟรช
โทเค็นการเข้าถึงมีอายุจำกัด (โดยทั่วไป 1 ชั่วโมง) โทเค็นรีเฟรชซึ่งมีอายุยาวกว่าจะใช้รับโทเค็นการเข้าถึงใหม่โดยไม่ต้องแจ้งให้ผู้ใช้ทราบ สำหรับแอปหน้าเดียว ปัจจุบันมักส่งโทเค็นรีเฟชผ่านคุกกี้ HttpOnly และไม่ควรใช้ localStorage เด็ดขาด
โทเค็น ID เทียบกับโทเค็นการเข้าถึง
โทเค็น ID (OpenID Connect): JWT ที่ยืนยันว่าผู้ใช้คือใคร โทเค็นการเข้าถึง: อาจเป็นค่าทึบหรือ JWT ใช้สำหรับเรียก API ตรวจสอบลายเซ็นและข้ออ้างสิทธิ์ของโทเค็น ID (iss, aud, exp, nonce) ก่อนเชื่อถือ
ไลบรารีการยืนยันตัวตน
อย่าเขียนระบบขึ้นเอง ให้ใช้: oidc-client-ts สำหรับ OIDC โดยตรง auth0/spa-js สำหรับ Auth0 @clerk/clerk-react สำหรับ Clerk NextAuth.js/Auth.js สำหรับ Next และ Nuxt-auth สำหรับ Nuxt ไลบรารีเหล่านี้จัดการ PKCE การรีเฟรช และการจัดเก็บให้
ตรวจสอบอย่างรวดเร็ว
เหตุใดแอปหน้าเดียวจึงต้องใช้ PKCE (การพิสูจน์คีย์สำหรับการแลกรหัส) ร่วมกับโฟลว์รหัสการอนุญาต แทนการใช้โฟลว์รหัสการอนุญาตพื้นฐานเพียงอย่างเดียว
สรุป: OAuth ในส่วนหน้า
รหัสการอนุญาต + PKCE เป็นมาตรฐานสมัยใหม่สำหรับแอปหน้าเดียว สร้างตัวตรวจสอบ + challenge แบบ S256 สำหรับแต่ละคำขอ เปลี่ยนเส้นทางไปยัง /authorize พร้อม challenge + state ตรวจสอบ state เมื่อได้รับคำขอย้อนกลับ แลกรหัส + ตัวตรวจสอบเป็นโทเค็น อย่าใช้โฟลว์ Implicit เด็ดขาด ควรใช้คุกกี้ HttpOnly สำหรับจัดเก็บโทเค็น ใช้ไลบรารี (auth0-spa-js, oidc-client-ts, NextAuth) และอย่าเขียนระบบขึ้นเอง
เรียนรู้ HTML ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 41
- บทเรียน
- 163
คำถามที่พบบ่อย
บทเรียน “โฟลว์ OAuth จากฟรอนต์เอนด์” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “โฟลว์ OAuth จากฟรอนต์เอนด์” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Frontend Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Frontend Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “โฟลว์ OAuth จากฟรอนต์เอนด์”
ใช้โฟลว์ Authorization Code พร้อม PKCE ใน SPA แลกโค้ดเป็นโทเค็น จัดเก็บโทเค็นการเข้าถึงอย่างปลอดภัย และหลีกเลี่ยงโฟลว์แบบ implicit คุณปฏิบัติ Frontend Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Frontend Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Frontend Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “โฟลว์ OAuth จากฟรอนต์เอนด์” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Frontend Academy นี้ได้ไหม
ได้ บทเรียน Frontend Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- การป้องกัน XSS: การเข้ารหัสเอาต์พุตและ CSP
- CSRF: คุกกี้และโทเค็น SameSite
- Content Security Policy: nonce และแฮช
- โฟลว์ OAuth จากฟรอนต์เอนด์