Nút bấm “Tiếp tục với Google” đã trở thành tiêu chuẩn trên hầu hết website hiện đại. Khách truy cập không cần nhớ mật khẩu mới, bạn không phải lo chuyện mã hóa hay khôi phục mật khẩu, và tỷ lệ chuyển đổi đăng ký tài khoản tăng lên rõ rệt.
Dù vậy, nhiều lập trình viên mới bắt đầu vẫn nhầm lẫn giữa việc “xác thực” (Authentication) với “phân quyền” (Authorization), hoặc lưu trực tiếp token ở phía trình duyệt một cách thiếu an toàn. Bài viết này sẽ hướng dẫn bạn dựng luồng Google OAuth 2.0 chuẩn cho ứng dụng web, kèm cách xử lý session đúng quy cách.
1. Google OAuth 2.0 hoạt động như thế nào?
Thay vì lưu mật khẩu của người dùng vào database, bạn ủy quyền bước kiểm tra danh tính cho Google thông qua 4 bước cơ bản:
- Khách bấm đăng nhập: Website chuyển hướng người dùng đến trang cấp quyền chính thức của Google (
accounts.google.com). - Google xác nhận: Người dùng chọn tài khoản Gmail và đồng ý chia sẻ thông tin cơ bản (email, họ tên, avatar).
- Trả mã xác thực (Authorization Code): Google chuyển hướng ngược lại website của bạn kèm một đoạn mã ngắn dùng một lần (
code). - Đổi mã lấy thông tin: Server của bạn bí mật gửi mã này lên Google API để đổi lấy
id_tokenhoặc thông tin tài khoản đã được ký số an toàn.
2. Tạo dự án và lấy Client ID trên Google Cloud Console
- Truy cập vào Google Cloud Console (
console.cloud.google.com) và tạo một project mới. - Vào mục APIs & Services > Credentials, chọn Create Credentials > OAuth client ID.
- Cấu hình loại ứng dụng là Web application.
- Khai báo Authorized redirect URIs (URI chuyển hướng hợp lệ), ví dụ:
- Môi trường local:
http://localhost:3000/api/auth/callback/google - Môi trường production:
[https://tenmien.com/api/auth/callback/google](https://tenmien.com/api/auth/callback/google)
- Môi trường local:
- Lưu lại hai chuỗi quan trọng: Client ID (công khai) và Client Secret (tuyệt đối giữ bí mật).
3. Dựng Endpoint trao đổi mã tại Backend
Dưới đây là ví dụ xử lý việc nhận Authorization Code và đổi lấy profile người dùng bằng Node.js / Express:
// Endpoint callback nhận redirect từ Google
app.get('/api/auth/callback/google', async (req, res) => {
const { code } = req.query;
if (!code) {
return res.status(400).send('Không tìm thấy mã xác thực');
}
try {
// 1. Gửi code lên Google để đổi lấy Token
const tokenResponse = await fetch('https://oauth2.googleapis.com/token', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
code: String(code),
client_id: process.env.GOOGLE_CLIENT_ID,
client_secret: process.env.GOOGLE_CLIENT_SECRET,
redirect_uri: process.env.GOOGLE_REDIRECT_URI,
grant_type: 'authorization_code',
}),
});
const tokens = await tokenResponse.json();
// 2. Dùng access_token để lấy thông tin hồ sơ
const userResponse = await fetch('https://www.googleapis.com/oauth2/v2/userinfo', {
headers: { Authorization: `Bearer ${tokens.access_token}` },
});
const profile = await userResponse.json();
// 3. Tìm hoặc tạo user trong cơ sở dữ liệu
let user = await db.user.findUnique({ where: { email: profile.email } });
if (!user) {
user = await db.user.create({
data: {
email: profile.email,
name: profile.name,
avatar: profile.picture,
provider: 'google',
},
});
}
// 4. Khởi tạo session nội bộ của hệ thống (HTTP-only Cookie)
setSessionCookie(res, user.id);
return res.redirect('/dashboard');
} catch (error) {
console.error('Lỗi xác thực OAuth:', error);
return res.redirect('/login?error=oauth_failed');
}
});
4. 5 lỗi bảo mật thường gặp khi làm OAuth 2.0
- Quên tham số
state(Nguy cơ CSRF): Luôn gửi kèm một chuỗi ngẫu nhiênstatekhi chuyển hướng sang Google và kiểm tra lại giá trị này lúc nhận callback để tránh tấn công giả mạo yêu cầu. - Lộ
Client Secretở Frontend:Client Secretchỉ được xuất hiện trong code backend hoặc file.envphía server. Tuyệt đối không nhúng vào mã nguồn React hay ứng dụng mobile. - Lưu Access Token vào LocalStorage: Token lưu trong LocalStorage rất dễ bị tấn công qua lỗi XSS. Hãy dùng session cookie gắn cờ
HttpOnly,SecurevàSameSite=Lax. - Tin tưởng dữ liệu chưa xác thực: Nếu bạn decode
id_tokenbằng thư viện JSON thông thường thay vì verify chữ ký thông qua SDK của Google, kẻ tấn công có thể chỉnh sửa nội dung bên trong token. - Không đồng bộ tài khoản trùng email: Nếu user từng đăng ký bằng email/mật khẩu, sau đó bấm đăng nhập bằng Google với cùng email đó, cần kiểm tra cờ
email_verified: truetừ Google trước khi tiến hành gộp tài khoản.


