Authentication và Authorization trong API: API Key, JWT, OAuth 2.0

Khi một API được đưa vào sử dụng thực tế, câu hỏi không chỉ nằm ở việc “API có hoạt động hay không”, mà còn là ai được phép gọi API, gọi bằng cách nào và được phép làm những gì. Đây là lý do Authentication và Authorization trở thành hai lớp nền tảng trong quá trình thiết kế API an toàn.

Authentication thường được hiểu là bước xác thực danh tính của bên đang gửi request. Authorization lại quyết định sau khi đã xác thực, đối tượng đó có quyền truy cập tài nguyên hoặc thực hiện hành động cụ thể hay không. Hai khái niệm liên quan chặt chẽ nhưng không thể xem là một.

Trong các hệ thống API hiện nay, API Key, JWT và OAuth 2.0 là những phương thức thường xuyên xuất hiện. Tuy nhiên, mỗi cơ chế giải quyết một bài toán khác nhau. API Key có thể phù hợp với việc nhận diện ứng dụng hoặc một số API đơn giản; JWT hữu ích khi hệ thống cần truyền thông tin xác thực dưới dạng token; còn OAuth 2.0 được thiết kế cho những kịch bản ủy quyền phức tạp, đặc biệt khi có bên thứ ba tham gia.

Với một website hoặc hệ thống được phát triển bằng PHP code tay theo yêu cầu, việc lựa chọn cơ chế xác thực không nên dựa vào việc công nghệ nào đang phổ biến nhất. Cần bắt đầu từ mô hình người dùng, loại dữ liệu, mức độ nhạy cảm của tài nguyên, cách client giao tiếp với server và phạm vi quyền cần cấp.

Authentication và Authorization trong API: API Key, JWT, OAuth 2.0
Authentication và Authorization trong API: API Key, JWT, OAuth 2.0

Authentication và Authorization khác nhau như thế nào?

Điểm dễ gây nhầm lẫn nhất khi xây dựng API là sử dụng Authentication và Authorization như hai thuật ngữ đồng nghĩa. Trên thực tế, chúng trả lời hai câu hỏi hoàn toàn khác nhau.

Authentication xác định “bạn là ai”

Authentication là quá trình xác minh danh tính của client hoặc người dùng. Server cần có cơ sở để tin rằng request đang được gửi bởi đúng đối tượng mà nó tuyên bố.

Ví dụ, một ứng dụng gửi request đến API kèm thông tin xác thực. Server kiểm tra thông tin đó có hợp lệ hay không. Nếu hợp lệ, hệ thống có thể xác định request thuộc về người dùng hoặc ứng dụng nào.

API Key, thông tin đăng nhập, token hoặc một cơ chế xác thực khác đều có thể được sử dụng cho mục đích này tùy kiến trúc hệ thống.

Authorization xác định “bạn được làm gì”

Sau khi biết request thuộc về ai, server vẫn chưa thể mặc nhiên cho phép truy cập mọi tài nguyên. Authorization chịu trách nhiệm kiểm tra quyền.

Chẳng hạn, một người dùng đã đăng nhập có thể được phép xem thông tin tài khoản của chính mình nhưng không được phép xem dữ liệu của người dùng khác. Một tài khoản quản trị có thể được phép xóa dữ liệu, trong khi tài khoản thông thường chỉ được phép đọc.

Do đó, một API được bảo vệ đúng cách thường phải trải qua cả hai lớp:

  1. Authentication: xác định danh tính của client hoặc người dùng.
  2. Authorization: kiểm tra danh tính đó có quyền thực hiện hành động đang yêu cầu hay không.

Nếu chỉ kiểm tra token có tồn tại mà không kiểm tra quyền, API vẫn có thể tồn tại lỗ hổng nghiêm trọng. Ngược lại, nếu xây dựng hệ thống quyền rất chi tiết nhưng cơ chế xác thực không đáng tin cậy, toàn bộ lớp phân quyền phía sau cũng mất ý nghĩa.

API Key phù hợp với trường hợp nào?

API Key là một trong những phương thức đơn giản nhất để nhận diện client khi gọi API. Server cấp cho một ứng dụng hoặc đối tác một chuỗi khóa, sau đó client gửi khóa này cùng request để server kiểm tra.

Cách tiếp cận này đặc biệt dễ triển khai vì server không nhất thiết phải duy trì một phiên đăng nhập phức tạp cho từng request. API Key cũng phù hợp với những hệ thống cần phân biệt các ứng dụng hoặc tích hợp giữa các dịch vụ.

Một request có thể truyền API Key thông qua HTTP header. Ví dụ:

GET /api/products HTTP/1.1
Host: example.com
X-API-Key: your-api-key

Phía server sẽ đọc giá trị khóa, tìm thông tin tương ứng và quyết định request có được tiếp tục hay không.

Ưu điểm của API Key

  • Thiết kế đơn giản, dễ hiểu và dễ triển khai.
  • Phù hợp để nhận diện ứng dụng hoặc một nguồn truy cập cụ thể.
  • Có thể cấp nhiều key cho nhiều hệ thống khác nhau.
  • Dễ thu hồi một key khi phát hiện bị lộ.
  • Có thể kết hợp với giới hạn tốc độ request và các chính sách bảo vệ API.

Đối với một API nội bộ hoặc một dịch vụ có mô hình truy cập đơn giản, API Key có thể là lựa chọn thực dụng thay vì xây dựng một hệ thống token phức tạp không cần thiết.

API Key không nên được xem là cơ chế phân quyền người dùng

Một sai lầm phổ biến là dùng API Key như một “vé thông hành” cho toàn bộ hệ thống. Việc request có key hợp lệ chỉ chứng minh rằng client sở hữu key đó; nó không đồng nghĩa với việc người dùng phía sau client được phép thực hiện mọi thao tác.

Ví dụ, nếu một website bán hàng sử dụng cùng một API Key cho toàn bộ frontend, server không thể dựa riêng vào key đó để xác định người dùng hiện tại là ai hoặc người đó có quyền chỉnh sửa đơn hàng nào.

API Key vì vậy thường phù hợp hơn với việc nhận diện ứng dụng, dịch vụ hoặc đối tác. Khi cần quản lý danh tính người dùng và quyền truy cập chi tiết, nên bổ sung hoặc chuyển sang một cơ chế xác thực phù hợp hơn.

Những nguyên tắc quan trọng khi quản lý API Key

API Key cần được coi là một thông tin bí mật. Nếu khóa bị lộ, bất kỳ ai sở hữu nó đều có thể thử sử dụng API với danh nghĩa của client được cấp khóa.

  • Không đặt API Key trực tiếp trong mã JavaScript chạy trên trình duyệt nếu key được xem là bí mật.
  • Không lưu key trong repository công khai.
  • Không ghi nguyên giá trị key vào log hoặc thông báo lỗi.
  • Nên có khả năng thu hồi và cấp lại key.
  • Nên giới hạn phạm vi sử dụng của key nếu hệ thống có nhu cầu.
  • Kết hợp HTTPS để tránh việc thông tin xác thực bị truyền dưới dạng có thể đọc được trên đường truyền.

Đặc biệt, cần phân biệt API Key công khai với API Key bí mật. Một số dịch vụ có key được thiết kế để xuất hiện ở phía client nhưng vẫn được giới hạn quyền. Không nên áp dụng suy nghĩ này cho mọi loại API Key.

JWT hoạt động ra sao trong API?

JWT, viết tắt của JSON Web Token, là một định dạng token thường được sử dụng để truyền các thông tin đã được ký giữa các bên. Trong kiến trúc API, JWT thường xuất hiện sau khi người dùng xác thực thành công.

Thay vì gửi lại thông tin đăng nhập ở mỗi request, client có thể nhận một access token rồi sử dụng token đó trong những request tiếp theo.

Một request phổ biến có dạng:

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

Server nhận token, kiểm tra chữ ký và các điều kiện liên quan trước khi quyết định request có hợp lệ hay không.

Cấu trúc cơ bản của JWT

Một JWT thường gồm ba phần được ngăn cách bằng dấu chấm:

header.payload.signature

Phần đầu chứa thông tin mô tả token và thuật toán được sử dụng để tạo chữ ký. Payload chứa các claim, chẳng hạn mã định danh người dùng, thời điểm phát hành hoặc thời điểm hết hạn. Phần signature được sử dụng để kiểm tra token có bị thay đổi hay không.

Điểm quan trọng cần nhớ là JWT được mã hóa theo nghĩa biểu diễn dữ liệu chứ không mặc nhiên đồng nghĩa với mã hóa bí mật. Payload của một JWT thông thường có thể được giải mã để đọc nội dung. Chữ ký giúp phát hiện việc thay đổi dữ liệu, chứ không biến dữ liệu thành thông tin bí mật.

Không nên đưa dữ liệu nhạy cảm vào payload

Do payload không nên được xem là nơi lưu trữ bí mật, không nên nhét mật khẩu, khóa bí mật hoặc thông tin nhạy cảm không cần thiết vào JWT.

Payload nên chứa lượng thông tin vừa đủ để server thực hiện xác thực và xử lý quyền. Chẳng hạn, hệ thống có thể sử dụng một mã định danh người dùng cùng một số claim phục vụ kiểm tra quyền thay vì đưa toàn bộ hồ sơ người dùng vào token.

JWT stateless nhưng không có nghĩa là không cần quản lý phiên

Một ưu điểm thường được nhắc đến của JWT là server có thể xác thực token mà không cần lưu toàn bộ session của người dùng theo cách truyền thống. Điều này có thể giúp kiến trúc API dễ mở rộng trong một số trường hợp.

Tuy nhiên, stateless không đồng nghĩa với việc mọi vấn đề về phiên đăng nhập tự động biến mất.

Ví dụ, nếu một JWT còn hạn nhưng người dùng vừa bị khóa tài khoản, server phải có chiến lược để ngăn token đó tiếp tục được sử dụng. Tương tự, khi token bị đánh cắp, việc chỉ kiểm tra chữ ký và thời gian hết hạn có thể chưa đủ để xử lý tình huống.

Vì vậy, thiết kế JWT thực tế cần tính đến thời gian sống của token, cơ chế cấp token mới, thu hồi khi cần thiết và cách xử lý các sự kiện bảo mật.

Access Token và Refresh Token nên được thiết kế như thế nào?

Trong một hệ thống sử dụng token, việc để một token có thời gian sống quá dài thường làm tăng hậu quả nếu token bị đánh cắp. Ngược lại, nếu token hết hạn quá nhanh mà không có cơ chế cấp lại thuận tiện, người dùng sẽ liên tục phải đăng nhập. Đây là lý do mô hình Access Token kết hợp Refresh Token thường được sử dụng để cân bằng giữa trải nghiệm và an toàn.

Access Token được dùng trực tiếp khi gọi các API cần bảo vệ. Token này nên có thời gian sống tương đối ngắn để giảm khoảng thời gian kẻ xấu có thể lợi dụng nếu token bị lộ.

Refresh Token có nhiệm vụ hỗ trợ cấp Access Token mới khi Access Token hết hạn. Nó không nên được sử dụng để gọi mọi API nghiệp vụ.

Luồng xử lý có thể hình dung đơn giản như sau:

  1. Người dùng xác thực thành công.
  2. Server cấp Access Token và Refresh Token theo chính sách của hệ thống.
  3. Client sử dụng Access Token để gọi API.
  4. Khi Access Token hết hạn, client gửi yêu cầu hợp lệ để xin Access Token mới.
  5. Server kiểm tra Refresh Token và các điều kiện liên quan.
  6. Nếu hợp lệ, server cấp Access Token mới và có thể đồng thời thay Refresh Token cũ bằng một token mới.

Cách tách hai loại token giúp Access Token không cần tồn tại quá lâu chỉ để duy trì trạng thái đăng nhập của người dùng.

Thời gian sống của token cần phục vụ mục tiêu bảo mật

Không có một con số thời gian sống phù hợp cho mọi API. API chứa dữ liệu ít nhạy cảm có thể có chính sách khác với API xử lý thông tin tài chính, quản trị hệ thống hoặc dữ liệu cá nhân.

Điều quan trọng là xác định rõ hậu quả khi token bị lộ và từ đó lựa chọn thời gian sống phù hợp. Token càng tồn tại lâu thì cửa sổ khai thác khi bị đánh cắp càng lớn.

Đối với Refresh Token, cần đặc biệt chú ý đến khả năng thu hồi. Một hệ thống có thể áp dụng cơ chế lưu trạng thái refresh token phía server, giới hạn thiết bị hoặc phiên sử dụng, đồng thời phát hiện những hành vi bất thường.

Không nên coi Refresh Token là Access Token thứ hai

Refresh Token không nên được gửi đến mọi endpoint. Việc sử dụng nhầm Refresh Token để truy cập API nghiệp vụ làm mất đi mục đích phân tách hai loại credential.

Thiết kế hợp lý nên có endpoint riêng dành cho việc làm mới token. Endpoint này thực hiện các kiểm tra cần thiết trước khi phát hành Access Token mới.

Phân quyền API bằng Role và Scope

Xác thực chỉ cho server biết request thuộc về ai. Để kiểm soát tài nguyên, hệ thống cần một lớp chính sách quyền rõ ràng.

Hai cách tiếp cận thường gặp là RoleScope. Chúng có thể được sử dụng riêng hoặc kết hợp tùy mô hình ứng dụng.

Role phù hợp với quyền theo nhóm người dùng

Role đại diện cho vai trò của một tài khoản trong hệ thống. Ví dụ, một hệ thống có thể có các vai trò như quản trị viên, nhân viên và khách hàng.

Thay vì kiểm tra từng người dùng riêng lẻ, server xác định role rồi áp dụng chính sách tương ứng.

{
  "user_id": 125,
  "role": "editor"
}

Chẳng hạn, tài khoản có role editor có thể được phép tạo và chỉnh sửa nội dung nhưng không được thay đổi cấu hình hệ thống.

Ưu điểm của Role là dễ hiểu và phù hợp với các hệ thống có cơ cấu quyền tương đối ổn định. Tuy nhiên, nếu số lượng quyền tăng mạnh, việc chỉ dựa vào Role có thể khiến chính sách trở nên khó quản lý.

Scope phù hợp khi quyền cần mô tả chi tiết

Scope thường mô tả những hành động hoặc phạm vi mà access token được phép thực hiện. Ví dụ:

products:read products:write orders:read

Token có scope products:read có thể được phép đọc sản phẩm nhưng không mặc nhiên được phép sửa sản phẩm.

Cách tiếp cận này đặc biệt hữu ích khi API được nhiều ứng dụng hoặc đối tác sử dụng với những mức quyền khác nhau.

Không nên chỉ kiểm tra “đã đăng nhập”

Một lỗi nghiêm trọng trong API là middleware chỉ kiểm tra token hợp lệ rồi cho request đi tiếp. Điều này biến Authentication thành điều kiện duy nhất để truy cập tài nguyên, trong khi Authorization gần như bị bỏ qua.

Ví dụ, endpoint:

DELETE /api/users/125

không nên chỉ kiểm tra người gửi có token hợp lệ. Server còn phải xác định người đó có quyền xóa người dùng hay không và có được phép tác động đến tài nguyên có mã 125 hay không.

Đây là điểm rất quan trọng: quyền thực hiện hành động và quyền truy cập đúng tài nguyên là hai lớp kiểm tra khác nhau.

OAuth 2.0 giải quyết bài toán nào?

OAuth 2.0 thường bị hiểu đơn giản là một phương thức “đăng nhập bằng Google hoặc Facebook”. Cách hiểu này chưa đầy đủ.

Bản chất của OAuth 2.0 là một framework dành cho ủy quyền truy cập. Nó cho phép một ứng dụng được cấp quyền truy cập tài nguyên thay mặt cho một chủ thể mà không nhất thiết phải biết mật khẩu của chủ thể đó.

Điểm mạnh của OAuth 2.0 xuất hiện rõ khi có nhiều thành phần tham gia: người dùng, ứng dụng client, máy chủ cấp quyền và máy chủ chứa tài nguyên.

Các thành phần cơ bản trong OAuth 2.0

  • Resource Owner: chủ thể sở hữu tài nguyên, thường là người dùng.
  • Client: ứng dụng muốn truy cập tài nguyên.
  • Authorization Server: hệ thống xác thực và cấp quyền hoặc token.
  • Resource Server: hệ thống cung cấp API và bảo vệ tài nguyên.

Việc tách các vai trò này giúp hệ thống không phải trao mật khẩu của người dùng cho mọi ứng dụng muốn sử dụng dữ liệu.

Ví dụ, một ứng dụng quản lý lịch có thể xin quyền đọc lịch của người dùng từ một nền tảng khác. Người dùng cấp quyền thông qua máy chủ ủy quyền, sau đó ứng dụng sử dụng access token được cấp để gọi API trong phạm vi cho phép.

Authorization Code là flow quan trọng trong ứng dụng có người dùng

Đối với ứng dụng có người dùng tương tác trực tiếp, Authorization Code là một flow quan trọng của OAuth 2.0. Thay vì để ứng dụng lấy trực tiếp thông tin đăng nhập của người dùng, quy trình được tách thành các bước xác thực và cấp authorization code.

Ở mức khái quát, quy trình diễn ra như sau:

  1. Ứng dụng chuyển người dùng đến Authorization Server.
  2. Người dùng xác thực và đồng ý với phạm vi quyền được yêu cầu.
  3. Authorization Server chuyển người dùng trở lại ứng dụng kèm authorization code.
  4. Ứng dụng dùng code để thực hiện bước trao đổi phù hợp với Authorization Server.
  5. Authorization Server trả về token nếu các điều kiện được đáp ứng.
  6. Ứng dụng sử dụng Access Token để gọi Resource Server.

Trong các ứng dụng hiện đại, PKCE thường được sử dụng cùng Authorization Code để tăng khả năng bảo vệ flow, đặc biệt đối với những client mà việc giữ bí mật client credential không thể thực hiện như với ứng dụng server-side truyền thống.

OAuth 2.0 không đồng nghĩa với đăng nhập

Đây là điểm cần phân biệt rõ khi xây dựng hệ thống. OAuth 2.0 tập trung vào authorization, tức là cấp quyền truy cập tài nguyên. Nó không tự biến thành một giao thức xác thực danh tính hoàn chỉnh chỉ vì hệ thống có bước người dùng đăng nhập.

Nếu bài toán yêu cầu ứng dụng xác định danh tính người dùng dựa trên một giao thức chuẩn được xây dựng trên OAuth 2.0, OpenID Connect thường là lớp được sử dụng cho mục đích đó.

API Key, JWT và OAuth 2.0 nên được lựa chọn theo nhu cầu nào?

Không có phương thức nào luôn tốt hơn hai phương thức còn lại. Lựa chọn đúng phụ thuộc vào cách API được sử dụng.

Tiêu chí API Key JWT OAuth 2.0
Mô hình chính Nhận diện client hoặc ứng dụng Token mang thông tin và quyền theo thiết kế Ủy quyền truy cập giữa nhiều thành phần
Mức độ triển khai Tương đối đơn giản Trung bình Phức tạp hơn
Phù hợp API nội bộ Có thể, nhưng thường không cần nếu bài toán đơn giản
Quản lý người dùng Hạn chế Phù hợp Phù hợp với hệ thống có nhiều client và quyền ủy quyền
Tích hợp bên thứ ba Có thể Có thể Rất phù hợp
Phân quyền chi tiết Cần xây dựng thêm Có thể dùng role hoặc claim Có thể dùng scope và chính sách quyền

Nếu API chỉ cần xác định một ứng dụng được phép gọi dịch vụ, API Key có thể là phương án đơn giản và hiệu quả.

Nếu hệ thống có tài khoản người dùng và cần xác thực bằng token trong các request, JWT có thể phù hợp, miễn là toàn bộ vòng đời token được thiết kế cẩn thận.

Nếu ứng dụng cần cho phép các client hoặc dịch vụ khác truy cập tài nguyên theo phạm vi được người dùng hoặc hệ thống cấp quyền, OAuth 2.0 thường là lựa chọn đáng cân nhắc hơn.

Điều quan trọng là không chọn công nghệ chỉ vì nó “hiện đại”. Một hệ thống nhỏ có thể trở nên khó bảo trì nếu áp dụng OAuth 2.0 với kiến trúc phức tạp trong khi nhu cầu thực tế chỉ là xác thực một vài service nội bộ.

Những nguyên tắc bảo mật cần có khi triển khai API

Cơ chế xác thực dù được lựa chọn tốt đến đâu cũng không thể bảo vệ API nếu phần triển khai còn nhiều điểm yếu. Trong thực tế, rủi ro thường không nằm ở việc server không biết JWT hay OAuth 2.0, mà nằm ở những chi tiết như truyền token sai cách, thời gian sống quá dài, kiểm tra quyền không đầy đủ hoặc để lộ thông tin xác thực qua log.

Luôn sử dụng HTTPS cho API

Thông tin xác thực cần được truyền qua kết nối được mã hóa. Nếu API hoạt động trên HTTP thông thường, API Key, access token hoặc các dữ liệu nhạy cảm khác có thể bị đánh cắp khi lưu thông trên mạng.

HTTPS không thay thế Authentication hay Authorization. Nó bảo vệ kênh truyền, trong khi Authentication xác minh danh tính và Authorization kiểm soát quyền. Ba lớp này giải quyết những vấn đề khác nhau và nên được nhìn nhận độc lập.

Không đặt thông tin xác thực trong URL

Đưa token hoặc API Key vào query string có thể khiến credential xuất hiện trong lịch sử trình duyệt, log web server, hệ thống phân tích hoặc các lớp trung gian.

Thay vì cách truyền như:

GET /api/orders?api_key=your-secret-key

nên ưu tiên cơ chế header phù hợp với loại credential. Với Bearer Token, cách phổ biến là:

GET /api/orders HTTP/1.1
Host: example.com
Authorization: Bearer access-token

Việc này không có nghĩa header tự động an toàn tuyệt đối. Token vẫn có thể bị ghi log hoặc bị lấy cắp nếu ứng dụng và hệ thống máy chủ được cấu hình không đúng.

Không lưu mật khẩu dưới dạng có thể khôi phục

Nếu API có hệ thống tài khoản riêng, mật khẩu người dùng không nên được lưu dưới dạng plaintext hoặc dưới dạng mã hóa có thể giải mã ngược. Server cần sử dụng cơ chế hash mật khẩu phù hợp và có salt để giảm nguy cơ khi cơ sở dữ liệu bị lộ.

Đồng thời, API đăng nhập cũng cần có giới hạn tốc độ và cơ chế phát hiện hành vi bất thường để giảm khả năng bị thử mật khẩu hàng loạt.

Chỉ trả về lượng dữ liệu API thực sự cần

Bảo mật API không chỉ là bảo vệ endpoint. Dữ liệu trả về cũng phải được kiểm soát.

Ví dụ, API lấy thông tin người dùng không nên trả về toàn bộ bản ghi cơ sở dữ liệu chỉ vì server có thể lấy được bản ghi đó. Các trường nội bộ, thông tin xác thực, token, dữ liệu quản trị hoặc thông tin không phục vụ client nên được loại bỏ khỏi response.

Nguyên tắc này giúp giảm thiệt hại ngay cả khi một endpoint bị khai thác.

Những lỗi thường gặp khi triển khai JWT và API Authentication

Một hệ thống có thể sử dụng đúng định dạng JWT nhưng vẫn không an toàn. Vấn đề nằm ở cách server tạo, kiểm tra và quản lý token.

Chấp nhận JWT mà không kiểm tra đầy đủ

Server không nên chỉ kiểm tra token có thể đọc được hay có đúng cấu trúc hay không. Cần xác minh chữ ký và các claim cần thiết theo chính sách của hệ thống.

Tùy kiến trúc, server có thể cần kiểm tra thời gian hết hạn, issuer, audience và những thông tin khác trước khi coi token là hợp lệ.

Việc kiểm tra phải được thực hiện bằng thư viện hoặc cơ chế đã được kiểm chứng thay vì tự viết thuật toán xử lý JWT từ đầu.

Thời gian sống của token quá dài

Access Token tồn tại trong thời gian dài làm tăng rủi ro khi token bị đánh cắp. Một token bị lộ ngay sau khi được cấp có thể tiếp tục hoạt động trong suốt thời gian còn hiệu lực.

Thời gian sống cần được xác định dựa trên mức độ nhạy cảm của API, trải nghiệm người dùng và khả năng xử lý việc cấp token mới.

Đưa quá nhiều thông tin vào JWT

JWT không nên biến thành một bản sao của hồ sơ người dùng. Token càng chứa nhiều dữ liệu, kích thước request càng lớn và việc quản lý thay đổi thông tin càng phức tạp.

Thông thường, token nên chứa những claim cần thiết cho việc xác định chủ thể, phạm vi hoặc thời hạn sử dụng. Những dữ liệu có thể thay đổi thường xuyên nên được lấy từ nguồn dữ liệu phù hợp thay vì cố nhồi tất cả vào token.

Chỉ kiểm tra Role nhưng bỏ qua quyền trên tài nguyên

Đây là lỗi có thể dẫn đến truy cập trái phép nghiêm trọng.

Giả sử người dùng A có quyền chỉnh sửa đơn hàng. Điều đó không có nghĩa người dùng A được chỉnh sửa mọi đơn hàng trong hệ thống.

API cần kiểm tra cả hai điều kiện:

  • Người dùng có quyền thực hiện hành động hay không.
  • Tài nguyên đang được yêu cầu có thuộc phạm vi mà người dùng được phép truy cập hay không.

Ví dụ, endpoint:

PUT /api/orders/785

không nên chỉ kiểm tra người dùng đã đăng nhập và có role phù hợp. Server còn phải xác định đơn hàng 785 có thuộc quyền quản lý của người dùng đó hay không.

Thiết kế Middleware Authentication và Authorization

Đối với API được xây dựng bằng PHP, việc tách Authentication và Authorization thành các lớp xử lý riêng giúp mã nguồn dễ kiểm soát và hạn chế việc lặp lại logic bảo mật ở từng controller.

Một request có thể đi qua quy trình khái quát:

  1. Nhận request.
  2. Xác định credential hoặc access token.
  3. Kiểm tra Authentication.
  4. Xác định user hoặc client tương ứng.
  5. Kiểm tra Authorization.
  6. Kiểm tra quyền đối với tài nguyên cụ thể.
  7. Cho phép controller xử lý nghiệp vụ.

Việc tách lớp giúp controller tập trung vào nghiệp vụ thay vì phải lặp lại các đoạn kiểm tra token ở hàng chục endpoint.

Một kiến trúc có thể hình dung:

Request
  |
  v
Authentication
  |
  v
Identify User / Client
  |
  v
Authorization
  |
  v
Resource Permission
  |
  v
Controller
  |
  v
Response

Cách tổ chức này cũng thuận lợi khi sau này hệ thống thay đổi cơ chế xác thực. Chẳng hạn, một nhóm API có thể sử dụng API Key trong khi nhóm API dành cho người dùng sử dụng Bearer Token mà phần xử lý nghiệp vụ không phải thay đổi quá nhiều.

Không để controller tự quyết định mọi quyền

Nếu mỗi controller tự viết một kiểu kiểm tra quyền, theo thời gian hệ thống rất dễ xuất hiện những endpoint có chính sách khác nhau dù đáng lẽ phải giống nhau.

Những quy tắc chung nên được tập trung ở lớp middleware hoặc service chuyên trách. Controller chỉ nên xử lý những điều kiện quyền đặc thù của nghiệp vụ khi thật sự cần thiết.

Rate Limiting và kiểm soát hành vi truy cập

Authentication giúp xác định client nhưng không có nghĩa client được phép gửi request không giới hạn. Một API công khai hoặc API có khả năng bị truy cập từ Internet nên có cơ chế giới hạn tốc độ.

Rate Limiting có thể được áp dụng theo API Key, tài khoản, IP, client hoặc một kết hợp tùy kiến trúc.

Ví dụ, endpoint đăng nhập có thể có giới hạn chặt hơn endpoint đọc danh sách sản phẩm. Endpoint gửi mã xác thực hoặc thực hiện thao tác nhạy cảm cũng nên có chính sách riêng thay vì dùng một giới hạn chung cho toàn bộ API.

Rate Limiting mang lại hai lợi ích quan trọng:

  • Giảm khả năng lạm dụng API.
  • Hạn chế tác động của các request tự động hoặc hành vi bất thường.

Tuy nhiên, Rate Limiting không thay thế Authorization. Một người dùng có quyền vẫn phải bị từ chối khi vượt giới hạn; một người không có quyền cũng không thể trở thành người có quyền chỉ vì gửi request với tốc độ thấp.

Nên chọn API Key, JWT hay OAuth 2.0 cho dự án?

Thay vì bắt đầu bằng câu hỏi “công nghệ nào tốt nhất?”, nên bắt đầu bằng câu hỏi “API đang cần bảo vệ trước tình huống nào?”. Đây là cách lựa chọn giúp tránh việc áp dụng kiến trúc quá phức tạp.

API nội bộ giữa các dịch vụ

Nếu một service cần gọi một service khác và chỉ cần nhận diện nguồn gọi, API Key hoặc một cơ chế credential dành cho service có thể đáp ứng bài toán đơn giản.

Trong hệ thống lớn, yêu cầu có thể cao hơn và cần thêm cơ chế quản lý secret, xoay vòng credential, giới hạn quyền và theo dõi từng service. Không nên dùng một key duy nhất cho toàn bộ hệ thống nếu các service có mức độ tin cậy hoặc quyền hạn khác nhau.

Website có hệ thống tài khoản người dùng

Với website có đăng nhập, API thường cần biết người dùng hiện tại là ai và người đó có quyền gì. Mô hình Access Token kết hợp cơ chế cấp mới token có thể phù hợp.

JWT có thể được sử dụng làm định dạng access token nếu kiến trúc hệ thống phù hợp. Tuy nhiên, JWT không phải lựa chọn bắt buộc chỉ vì API có đăng nhập. Một hệ thống hoàn toàn có thể sử dụng session hoặc opaque token nếu điều đó phù hợp với yêu cầu.

Ứng dụng kết nối với hệ thống bên thứ ba

Khi một ứng dụng cần truy cập tài nguyên thuộc một hệ thống khác với sự cho phép của người dùng, OAuth 2.0 thường phù hợp hơn việc yêu cầu người dùng cung cấp mật khẩu cho ứng dụng.

Đây là trường hợp mà khái niệm ủy quyền trở nên quan trọng: ứng dụng chỉ nên nhận phạm vi quyền cần thiết thay vì được cấp toàn bộ quyền trên tài khoản.

API dành cho đối tác

Với API dành cho đối tác, việc cấp credential nên đi cùng chính sách quản lý rõ ràng. Mỗi đối tác nên có định danh riêng để hệ thống có thể theo dõi, giới hạn và thu hồi quyền khi cần.

Nếu nhu cầu chỉ là xác định đối tác và giới hạn truy cập, API Key có thể đủ. Nếu cần phân quyền chi tiết, thời hạn truy cập hoặc mô hình ủy quyền phức tạp, có thể cân nhắc token hoặc OAuth 2.0.

Best Practices khi xây dựng lớp bảo mật cho API

Một hệ thống API an toàn không phụ thuộc vào một kỹ thuật duy nhất. Cần kết hợp nhiều lớp để nếu một lớp gặp vấn đề, các lớp còn lại vẫn hạn chế được mức độ ảnh hưởng.

  • Sử dụng HTTPS cho toàn bộ API có dữ liệu hoặc credential cần bảo vệ.
  • Phân biệt rõ Authentication và Authorization.
  • Không đưa secret vào mã nguồn công khai.
  • Không lưu API Key hoặc token vào log dưới dạng đầy đủ.
  • Thiết kế Access Token với thời gian sống phù hợp.
  • Có chiến lược xử lý Refresh Token nếu hệ thống sử dụng chúng.
  • Kiểm tra chữ ký và các claim cần thiết của JWT.
  • Không đưa mật khẩu hoặc dữ liệu bí mật vào JWT payload.
  • Áp dụng nguyên tắc quyền tối thiểu.
  • Kiểm tra quyền đối với cả hành động và tài nguyên.
  • Giới hạn tốc độ request đối với endpoint phù hợp.
  • Có khả năng thu hồi credential khi phát hiện sự cố.
  • Tách credential theo ứng dụng, đối tác hoặc service thay vì dùng chung một khóa.
  • Không trả về những trường dữ liệu không cần thiết trong API response.
  • Ghi log các sự kiện bảo mật cần thiết nhưng tránh làm lộ credential.
  • Kiểm thử các trường hợp truy cập trái quyền thay vì chỉ kiểm thử request hợp lệ.

Authentication và Authorization cần được thiết kế ngay từ đầu

Authentication và Authorization không nên được xem là phần bổ sung sau khi API đã hoàn thành. Nếu API được xây dựng trước rồi mới tìm cách “gắn bảo mật” vào sau, việc sửa kiến trúc có thể tốn nhiều công sức và dễ tạo ra những ngoại lệ khó kiểm soát.

Ngay từ giai đoạn phân tích, cần xác định API có những loại client nào, người dùng được chia thành những nhóm quyền nào, tài nguyên nào nhạy cảm, endpoint nào cần bảo vệ cao hơn và credential có thể bị thu hồi trong trường hợp nào.

API Key, JWT và OAuth 2.0 đều có vị trí riêng trong kiến trúc API. API Key mạnh ở sự đơn giản và khả năng nhận diện client. JWT cung cấp một định dạng token linh hoạt cho nhiều mô hình xác thực và phân quyền. OAuth 2.0 giải quyết tốt những bài toán ủy quyền giữa nhiều thành phần và ứng dụng.

Điểm quan trọng nhất không phải là chọn công nghệ nhiều tính năng nhất mà là chọn đúng cơ chế cho đúng bài toán. Một API nhỏ không cần thiết phải mang kiến trúc OAuth 2.0 phức tạp, trong khi một nền tảng có nhiều ứng dụng, người dùng và đối tác cũng không nên chỉ dựa vào một API Key dùng chung.

Với Web Mới, khi phát triển website và API bằng PHP code tay theo yêu cầu, lớp Authentication và Authorization có thể được thiết kế ngay từ kiến trúc ban đầu thay vì xử lý chắp vá về sau. Cách tiếp cận này giúp quyền truy cập rõ ràng hơn, mã nguồn dễ bảo trì hơn và thuận lợi khi hệ thống cần mở rộng thêm ứng dụng, đối tác hoặc các nhóm người dùng mới.

Một API tốt không chỉ trả về dữ liệu đúng mà còn phải trả lời chính xác ba câu hỏi trước mỗi thao tác quan trọng: request đến từ đâu, ai đang thực hiện và họ được phép làm đến đâu. Khi ba lớp này được thiết kế rõ ràng, Authentication và Authorization sẽ trở thành một phần tự nhiên của kiến trúc API thay vì một lớp bảo mật được bổ sung sau cùng.

  • 0 Bình luận
CEO Bùi Tấn Lực | Founder Web Mới
Bùi Tấn Lực
Tìm hiểu về CEO Bùi Tấn Lực, Founder Web Mới với nhiều năm kinh nghiệm trong lĩnh vực phát triển website, SEO và chia sẻ kiến thức công nghệ
Đánh giá
Chia sẻ nội dung đánh giá của bạn về Authentication và Authorization trong API: API Key, JWT, OAuth 2.0
Email, Điện thoại của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *
Đánh giá của bạn
Tên *
Email
Số điện thoại *
Bình luận, Hỏi đáp
Yêu Cầu Báo Giá
Gửi trang web mẫu cần làm theo, chúng tôi sẽ báo giá đến bạn từ Email (tanlucit09@gmail.com - Bùi Tấn Lực) hoặc Zalo (Lực IT - 0398259259) !