Trong các ứng dụng web hiện đại, việc xác thực và ủy quyền người dùng là yếu tố quan trọng để bảo đảm an ninh. JWT (JSON Web Token) đã trở thành một trong những công nghệ phổ biến nhất để xử lý xác thực, nhờ tính gọn nhẹ và khả năng hoạt động tốt trong các hệ thống phân tán. Bài viết này sẽ giải thích chi tiết và tỉ mỉ về cách JWT hoạt động trong quy trình xác thực người dùng, từ việc đăng nhập, xử lý yêu cầu đến làm mới token.

JWT là gì?

JWT là viết tắt của JSON Web Token, một tiêu chuẩn mở (RFC 7519) để truyền tải dữ liệu an toàn giữa hai bên dưới dạng JSON. Token này được mã hóa và có thể xác thực tính toàn vẹn của nó thông qua chữ ký số. Trong một hệ thống xác thực, JWT được sử dụng để định danh và cấp quyền cho người dùng, giúp duy trì phiên làm việc mà không cần lưu trữ trạng thái trên máy chủ.

Cấu trúc của JWT

JWT có ba phần chính:

  1. Header: Chứa thông tin về loại token và thuật toán mã hóa.
  2. Payload: Chứa thông tin người dùng hoặc các thông tin mà bạn muốn truyền tải.
  3. Signature: Được tạo bằng cách mã hóa header và payload cùng với một khóa bí mật.

Một JWT thường có dạng như sau:

userId

Phần chữ ký (Signature) sẽ được mã hóa bằng cách sử dụng khóa bí mật để bảo đảm tính toàn vẹn của token.

Trả về JWT

JWT sau khi tạo xong sẽ được gửi trả lại cho client trong HTTP response. Người dùng sẽ lưu trữ JWT này để sử dụng cho các yêu cầu tiếp theo.

Ví dụ:

HttpOnly

3. Gửi JWT trong các yêu cầu tiếp theo

Trong các yêu cầu tiếp theo, client cần gửi JWT đã nhận để xác thực. Token này thường được gửi trong HTTP header Authorization dưới dạng Bearer Token.

Ví dụ yêu cầu với JWT:

userId

5. Cấp quyền truy cập (Authorization)

Khi xác thực thành công JWT, server có thể sử dụng thông tin từ payload để xác định quyền truy cập. Nếu người dùng có quyền hợp lệ, server sẽ cho phép truy cập tài nguyên. Nếu không, server trả về mã lỗi như 403 Forbidden.

Ví dụ kiểm tra quyền trong hệ thống:

function authorizeAdmin(req, res, next) {
  if (!req.user.admin) return res.sendStatus(403);
  next();
}

6. Làm mới JWT (Refresh Token)

Sử dụng Refresh Token

JWT thường có thời gian sống ngắn, do đó để tránh việc người dùng phải đăng nhập lại liên tục, ta sử dụng Refresh Token. Refresh Token có thời gian sống lâu hơn JWT và được sử dụng để cấp mới JWT khi nó hết hạn.

Ví dụ luồng xử lý làm mới token:

  1. Client gửi Refresh Token đến server khi JWT hết hạn.
  2. Server xác minh Refresh Token và nếu hợp lệ, tạo một JWT mới.
  3. Client nhận JWT mới và thay thế JWT cũ trong các yêu cầu tiếp theo.
app.post('/token', (req, res) => {
  const refreshToken = req.body.token;
  if (!refreshToken) return res.sendStatus(401);
  if (!refreshTokens.includes(refreshToken)) return res.sendStatus(403);

  jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
    if (err) return res.sendStatus(403);
    const accessToken = generateAccessToken({ name: user.name });
    res.json({ accessToken });
  });
});

Lưu ý: Refresh Token thường được lưu trữ trong Cookies để bảo đảm an toàn.


JWT cung cấp một phương pháp xác thực an toàn, không trạng thái và rất hiệu quả cho các ứng dụng web hiện đại. Tuy nhiên, việc bảo mật JWT rất quan trọng, và bạn cần cân nhắc việc bảo vệ token trước các cuộc tấn công tiềm ẩn như XSS, CSRF. Trong quá trình phát triển, hãy luôn kiểm tra thời hạn và quyền hạn của token để bảo đảm rằng hệ thống của bạn luôn an toàn.