Mở đầu — vì sao bài này quan trọng
Hãy tưởng tượng bạn là BA của một startup fintech ở TP.HCM. Đội kỹ thuật vừa gửi cho bạn một spec API tích hợp với đối tác thanh toán, và trong đó có một dòng ghi: "Authentication: Bearer token, expires in 3600s". Khách hàng doanh nghiệp thì hỏi: "Vậy nhân viên của tôi đăng nhập bằng cách nào, và làm sao hệ thống biết ai được xem báo cáo doanh thu?". Nếu bạn lúng túng giữa hai câu hỏi này, bạn đang lẫn lộn hai khái niệm rất khác nhau: xác thực (authentication) và phân quyền (authorization).
Authentication là tầng nền móng của mọi hệ thống có dữ liệu nhạy cảm. Một API không có authentication giống như một ngôi nhà không khóa cửa — ai cũng vào được, lấy gì cũng được. Là BA, bạn không cần tự code phần xác thực, nhưng bạn bắt buộc phải hiểu nó đủ sâu để: viết được yêu cầu (requirement) chính xác, đọc được tài liệu API của đối tác, đánh giá rủi ro bảo mật ở mức nghiệp vụ, và làm cầu nối giữa team kỹ thuật với khách hàng. Khi đối tác nói "chúng tôi dùng API Key", bạn phải biết ngay điều đó kéo theo những hệ quả gì về vận hành, bảo mật và trải nghiệm người dùng.
Bài này tập trung vào bức tranh tổng quan ba phương thức xác thực phổ biến nhất: Basic Authentication, Bearer Token, và API Key. Đây là ba khái niệm bạn sẽ gặp đi gặp lại trong 90% các dự án tích hợp. Các bài sau sẽ đào sâu OAuth 2.0, JWT, và quản lý API Key chi tiết hơn — ở đây ta xây nền vững trước.
Khái niệm cốt lõi
Authentication vs Authorization — phân biệt một lần cho rõ
Đây là cặp khái niệm bị nhầm lẫn nhiều nhất, nên ta giải quyết dứt điểm ngay từ đầu.
- Authentication (AuthN) — "Bạn là ai?": Là quá trình hệ thống xác minh danh tính của bạn. Khi bạn nhập username và password để đăng nhập, đó là authentication. Hệ thống xác nhận: "À, đúng là Khang rồi."
- Authorization (AuthZ) — "Bạn được phép làm gì?": Là quá trình hệ thống quyết định bạn có quyền truy cập tài nguyên hay thực hiện hành động nào đó không. Sau khi biết bạn là Khang, hệ thống kiểm tra: "Khang có phải admin không? Có được xem báo cáo tài chính không?"
Thứ tự luôn là: AuthN trước, AuthZ sau. Bạn không thể quyết định ai đó được làm gì khi chưa biết họ là ai. Trong API, authentication thường thể hiện qua HTTP Header (đặc biệt là header Authorization), còn authorization thể hiện qua logic phía server kiểm tra vai trò (role), quyền (permission). Bài này nói chủ yếu về AuthN — cụ thể là ba cách "trình danh tính" với API.
Phương thức 1: Basic Authentication
Đây là cách cổ điển và đơn giản nhất, được định nghĩa từ thời sơ khai của HTTP. Cơ chế: client gửi kèm username và password trong mỗi request, dưới dạng một chuỗi được mã hóa Base64.
Cụ thể, header sẽ trông như sau:
Authorization: Basic a2hhbmc6bWF0a2hhdTEyMw==
Chuỗi a2hhbmc6bWF0a2hhdTEyMw== chính là khang:matkhau123 được mã hóa Base64. Lưu ý cực kỳ quan trọng mà BA nào cũng phải nắm: Base64 KHÔNG phải là mã hóa bảo mật (encryption). Nó chỉ là một cách biểu diễn dữ liệu, ai cũng giải ngược ra được trong vài giây bằng công cụ online. Điều này nghĩa là Basic Auth chỉ an toàn khi đi kèm HTTPS (kênh truyền được mã hóa). Nếu dùng trên HTTP thường, mật khẩu coi như phơi bày giữa đường truyền.
Ưu điểm: cực kỳ đơn giản, được mọi công cụ hỗ trợ. Nhược điểm: gửi mật khẩu thật trong mỗi request (rủi ro cao), không có cơ chế hết hạn (mật khẩu lộ là lộ vĩnh viễn cho tới khi đổi), và khó thu hồi quyền cho từng phiên. Vì vậy ngày nay Basic Auth chủ yếu dùng cho các API nội bộ, công cụ admin, hoặc server-to-server đơn giản — hiếm khi dùng cho ứng dụng người dùng cuối quy mô lớn.
Phương thức 2: Bearer Token
Đây là phương thức phổ biến nhất trong các API hiện đại. Từ "Bearer" nghĩa là "người mang" — ai cầm (mang) token này thì được coi là có quyền truy cập, giống như vé xem phim: ai cầm vé thì vào được, rạp không hỏi vé đó của ai.
Header trông như sau:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Quy trình điển hình gồm hai bước. Bước một, người dùng đăng nhập một lần bằng username/password (hoặc qua OAuth) và nhận về một token — một chuỗi ký tự dài, có thời hạn (ví dụ 1 giờ). Bước hai, ở mọi request sau đó, client gửi kèm token này trong header Authorization: Bearer <token>, không gửi mật khẩu nữa.
Đây là điểm mạnh lớn nhất: mật khẩu chỉ xuất hiện một lần lúc đăng nhập, sau đó hệ thống chỉ "đi lại" bằng token. Token có thời hạn (expiry), nên nếu lộ thì thiệt hại bị giới hạn theo thời gian. Token cũng có thể bị thu hồi (revoke) mà không cần đổi mật khẩu người dùng. Token thường chứa thông tin về danh tính và quyền hạn — phổ biến nhất là dạng JWT (sẽ học chi tiết ở bài 18).
Nhược điểm: phức tạp hơn Basic Auth, cần cơ chế cấp phát và làm mới token (refresh). Nhưng đổi lại độ an toàn và linh hoạt vượt trội, nên đây là lựa chọn mặc định cho hầu hết ứng dụng web/mobile ngày nay.
Phương thức 3: API Key
API Key là một chuỗi định danh bí mật, thường được cấp cho một ứng dụng hoặc hệ thống (chứ không phải cho từng người dùng cuối). Hãy hình dung nó như chìa khóa riêng cấp cho một đối tác để gọi vào dịch vụ của bạn.
API Key có thể được gửi theo nhiều cách, tùy nhà cung cấp quy định:
Authorization: ApiKey sk_live_a8Hd72hsKx...
hoặc trong header riêng:
X-API-Key: sk_live_a8Hd72hsKx...
hoặc thậm chí trong query string (cách kém an toàn nhất): ?api_key=sk_live_a8Hd72...API Key cực kỳ phổ biến trong bối cảnh server-to-server: cổng thanh toán, dịch vụ gửi SMS/email, bản đồ, AI API... Ví dụ khi bạn tích hợp Google Maps hay một dịch vụ gửi SMS như eSMS, bạn được cấp một API Key. Điểm mạnh: đơn giản, dễ phân biệt từng đối tác/ứng dụng (mỗi key một đối tác), dễ theo dõi lưu lượng và áp dụng giới hạn (rate limit) theo key, dễ thu hồi (revoke) hoặc xoay vòng (rotate) khi cần.
Điểm yếu: bản thân API Key thường không có thời hạn tự động và không gắn với danh tính người dùng cụ thể — nó chỉ nói "request này đến từ ứng dụng X". Nếu key bị lộ (ví dụ lập trình viên vô tình đẩy lên GitHub công khai), kẻ xấu có thể dùng đến khi bị phát hiện và thu hồi. Vì vậy API Key phải được giữ bí mật như mật khẩu, không bao giờ để lộ ở phía client (trình duyệt, app mobile có thể bị dịch ngược).
Bảng so sánh nhanh
| Tiêu chí | Basic Auth | Bearer Token | API Key |
|---|---|---|---|
| Định danh | User (username/password) | User (qua token) | Ứng dụng/hệ thống |
| Có thời hạn? | Không | Có (token expiry) | Thường không |
| Gửi gì mỗi request | Mật khẩu thật | Token | Key |
| Dùng nhiều cho | API nội bộ đơn giản | App web/mobile người dùng | Server-to-server, đối tác |
| Thu hồi | Đổi mật khẩu | Revoke token | Revoke/rotate key |
Tình huống thực tế
Tình huống 1: Sàn TMĐT tích hợp cổng thanh toán VNPAY
Một sàn thương mại điện tử giả định tên MuaNhanh ở Hà Nội cần tích hợp cổng thanh toán. Trong buổi làm việc với đối tác, BA nhận tài liệu ghi rõ: giao tiếp giữa server MuaNhanh và server cổng thanh toán dùng API Key (mã merchant + secret key) để ký request, còn cổng thanh toán không bao giờ tiếp xúc trực tiếp với tài khoản người mua.
Diễn giải: Ở đây có sự phân tầng rõ ràng. Người mua đăng nhập vào MuaNhanh bằng Bearer Token (phiên đăng nhập của họ). Nhưng khi MuaNhanh gọi sang cổng thanh toán để tạo giao dịch, đó là cuộc gọi server-to-server dùng API Key — danh tính ở đây là "ứng dụng MuaNhanh", không phải từng người mua. Secret key này phải được lưu trong môi trường server, tuyệt đối không lộ ra trình duyệt.
Bài học rút ra: Cùng một luồng nghiệp vụ có thể dùng nhiều phương thức xác thực ở các tầng khác nhau. BA phải vẽ được sơ đồ "ai gọi ai, dùng phương thức gì" để viết requirement chính xác và phát hiện lỗ hổng (ví dụ: nếu ai đó đề xuất để API Key thanh toán nằm trong code frontend, bạn phải lập tức cảnh báo đó là rủi ro nghiêm trọng).
Tình huống 2: App giao đồ ăn dùng Bearer Token
Một startup giao đồ ăn ở Đông Nam Á tên FoodGo có app mobile cho khách và app riêng cho tài xế. Khi tài xế đăng nhập, hệ thống cấp một Bearer Token có thời hạn 24 giờ, kèm refresh token thời hạn 30 ngày. Mỗi lần app cập nhật vị trí tài xế (vài giây một lần), nó gửi token trong header.
Có lần một tài xế nghỉ việc và đội vận hành cần chặn ngay quyền truy cập của người này. Nhờ dùng Bearer Token, đội kỹ thuật chỉ cần đưa token (và refresh token) của tài xế đó vào danh sách thu hồi — trong vòng vài phút người đó không còn nhận đơn được nữa, mà không ảnh hưởng tài xế khác.
Diễn giải: Hãy so sánh với kịch bản nếu FoodGo dùng Basic Auth. Với Basic Auth, app sẽ phải lưu mật khẩu tài xế và gửi nó mỗi vài giây — vừa rủi ro lộ mật khẩu, vừa không có cách "ngắt" nhanh ngoài việc bắt tài xế đổi mật khẩu. Token với thời hạn ngắn và khả năng thu hồi giải quyết gọn cả hai vấn đề.
Bài học rút ra: Khi requirement có yêu cầu "phải thu hồi quyền truy cập tức thời" hoặc "phiên đăng nhập phải tự hết hạn", đó là tín hiệu rõ ràng nghiêng về Bearer Token chứ không phải Basic Auth hay API Key. BA nên ghi rõ các yêu cầu phi chức năng (non-functional requirement) này trong spec.
Tình huống 3: Công cụ nội bộ dùng Basic Auth
Một ngân hàng giả định có một dashboard nội bộ cho 5 nhân viên IT theo dõi trạng thái máy chủ, chỉ truy cập được trong mạng nội bộ (VPN), qua HTTPS. Đội kỹ thuật chọn Basic Auth vì nó đơn giản, không cần dựng cả hệ thống cấp token cho một công cụ chỉ 5 người dùng.
Diễn giải: Đây là ví dụ cho thấy Basic Auth không phải lúc nào cũng sai. Trong phạm vi hẹp, có HTTPS, có VPN bảo vệ vòng ngoài, số người dùng ít và là nội bộ tin cậy, Basic Auth là lựa chọn hợp lý vì tiết kiệm công sức. Vấn đề chỉ nảy sinh khi người ta cố dùng Basic Auth cho ứng dụng công khai hàng triệu người dùng.
Bài học rút ra: Chọn phương thức xác thực là bài toán đánh đổi giữa độ an toàn và độ phức tạp, đặt trong bối cảnh cụ thể. BA giỏi không máy móc nói "Basic Auth là tệ", mà hỏi: phạm vi sử dụng là gì, ai dùng, dữ liệu nhạy cảm tới đâu, có HTTPS không.
Hướng dẫn từng bước
Khi bạn nhận một spec API hoặc tham gia thiết kế tích hợp, hãy đi theo quy trình sau để xác định và đánh giá phương thức xác thực:
- Xác định các bên giao tiếp: Vẽ ra ai gọi ai. Người dùng cuối gọi vào app? App gọi vào server của bạn? Server bạn gọi sang đối tác? Mỗi cặp giao tiếp có thể dùng phương thức khác nhau.
- Trả lời câu hỏi "danh tính ở đây là ai": Nếu danh tính là từng người dùng cụ thể → nghiêng về Bearer Token. Nếu danh tính là một ứng dụng/đối tác → nghiêng về API Key. Nếu là công cụ nội bộ đơn giản → có thể Basic Auth.
- Tìm header
Authorizationtrong tài liệu: Đọc xem tài liệu API yêu cầu gửi gì. ThấyBasic→ Basic Auth. ThấyBearer→ Bearer Token. Thấy header lạ nhưX-API-Keyhay tham sốapi_key→ API Key.
- Kiểm tra yêu cầu về thời hạn và thu hồi: Hỏi team: token/key này có hết hạn không? Thu hồi bằng cách nào? Ghi rõ vào requirement.
- Kiểm tra HTTPS bắt buộc: Mọi phương thức trên đều phải đi qua HTTPS. Nếu spec cho phép HTTP, đó là cảnh báo đỏ cần nêu ngay.
- Phân biệt rõ với phần phân quyền (AuthZ): Sau khi xác định AuthN, hỏi tiếp: sau khi biết "ai", hệ thống quyết định "được làm gì" dựa trên đâu (role, permission)? Đừng gộp hai phần này vào một.
Lỗi thường gặp & mẹo
- Nhầm Base64 là mã hóa an toàn: Lỗi phổ biến nhất. Nhớ rằng Base64 chỉ là cách biểu diễn, ai cũng giải ngược được. Bảo mật của Basic Auth đến từ HTTPS, không phải từ Base64.
- Gộp lẫn AuthN và AuthZ trong requirement: Viết "user phải đăng nhập và phải là admin mới xem được" mà không tách rõ phần nào là xác thực, phần nào là phân quyền. Hãy tách thành hai requirement riêng để team xử lý đúng tầng.
- Để API Key/token lộ ở phía client: Một số dự án nhét secret key vào code JavaScript chạy trên trình duyệt hoặc trong app mobile. Bất kỳ thứ gì chạy phía client đều có thể bị xem/dịch ngược. Secret phải ở phía server. Là BA, khi review thiết kế bạn nên hỏi rõ key được lưu ở đâu.
- Quên cơ chế làm mới (refresh) cho Bearer Token: Token hết hạn mà không có refresh thì người dùng bị đăng xuất đột ngột giữa chừng — trải nghiệm tệ. Hãy hỏi và ghi rõ luồng refresh trong spec.
- Mẹo: luôn hỏi "lỡ key/token này lộ thì sao?": Đây là câu hỏi vàng giúp bạn đánh giá rủi ro. Một thiết kế tốt phải có câu trả lời rõ ràng: thiệt hại bị giới hạn (do thời hạn ngắn) và có cách thu hồi nhanh.
- Mẹo: dùng Postman để "nhìn tận mắt": Khi đọc tài liệu chưa rõ, hãy nhờ team hoặc tự thử gọi một request mẫu trong Postman với từng kiểu Authorization. Nhìn thấy header thật giúp hiểu nhanh hơn đọc lý thuyết (bạn sẽ thực hành kỹ ở bài 14).
Bài tập thực hành
- Phân loại tình huống: Với mỗi kịch bản sau, hãy chọn phương thức xác thực phù hợp nhất (Basic / Bearer / API Key) và giải thích lý do trong 2–3 câu:
- Phân biệt AuthN và AuthZ: Viết lại requirement sau bằng cách tách thành hai phần riêng biệt — phần authentication và phần authorization: "Chỉ trưởng phòng đã đăng nhập mới được phê duyệt đơn nghỉ phép trên 5 ngày."
- Phát hiện rủi ro: Một spec ghi rằng app mobile sẽ lưu sẵn API Key của cổng thanh toán trong code app để gọi trực tiếp. Hãy chỉ ra rủi ro và đề xuất hướng xử lý đúng đắn dưới góc nhìn BA.
- Đọc header: Cho header
Authorization: Bearer eyJhbGci..., hãy cho biết đây là phương thức nào, ưu điểm chính so với Basic Auth, và một câu hỏi bạn cần hỏi team kỹ thuật về token này.
Tóm tắt
Authentication (AuthN — "bạn là ai") và Authorization (AuthZ — "bạn được làm gì") là hai khái niệm khác nhau, luôn đi theo thứ tự AuthN trước, AuthZ sau. Bài này tập trung vào ba phương thức xác thực phổ biến nhất với API:
- Basic Auth: gửi username/password (mã hóa Base64) mỗi request. Đơn giản nhưng rủi ro, chỉ an toàn với HTTPS, hợp với công cụ nội bộ nhỏ.
- Bearer Token: đăng nhập một lần lấy token có thời hạn, sau đó đi lại bằng token. Linh hoạt, thu hồi được, hết hạn được — lựa chọn mặc định cho app người dùng hiện đại.
- API Key: chuỗi bí mật cấp cho ứng dụng/đối tác, phổ biến trong giao tiếp server-to-server. Đơn giản, dễ theo dõi theo đối tác, nhưng phải giữ bí mật tuyệt đối.
Authorization, xác định đúng phương thức trong spec, đặt câu hỏi vàng "lỡ lộ thì sao", và viết requirement tách bạch giữa xác thực và phân quyền. Đây là nền móng để bước vào các bài sâu hơn về OAuth 2.0, JWT và quản lý API Key.