Xác thực API với Laravel Sanctum: token cho SPA và ứng dụng di động

  • author-image

    Nguyễn Đình Cường

  • blog-tag
  • blog-comment 0 comment
  • created-date 09 Nov, 2026
blog-thumbnail

Bạn xây một API và cần cho ứng dụng di động hoặc trang web đăng nhập vào đó một cách an toàn. Laravel Sanctum là giải pháp nhẹ, có sẵn trong hệ sinh thái Laravel, đủ dùng cho đa số dự án vừa và nhỏ mà không cần đến OAuth phức tạp.

Sanctum giải quyết hai bài toán

Sanctum phục vụ hai kiểu xác thực khác nhau:

  • API token: mỗi người dùng nhận một token, gửi kèm trong header Authorization: Bearer .... Phù hợp với ứng dụng di động và dịch vụ gọi API.
  • Xác thực SPA bằng cookie: trang web một trang (React, Vue) cùng domain gốc với backend dùng session cookie, không cần lưu token ở trình duyệt.

Ở bài này chúng ta tập trung vào API token vì nó phổ biến với app di động.

Cài đặt cơ bản

Các bản Laravel mới có thể cài bằng lệnh:

php artisan install:apiphp artisan migrate

Lệnh này tạo bảng personal_access_tokens. Sau đó thêm trait vào model người dùng:

use Laravel\Sanctum\HasApiTokens;class User extends Authenticatable{    use HasApiTokens;}

Cấp token khi đăng nhập

Route::post('/login', function (Request $request) {    $data = $request->validate([        'email'    => ['required', 'email'],        'password' => ['required'],    ]);    $user = User::where('email', $data['email'])->first();    if (! $user || ! Hash::check($data['password'], $user->password)) {        return response()->json(['message' => 'Sai thông tin đăng nhập'], 422);    }    $token = $user->createToken('mobile-app', ['posts:read'])->plainTextToken;    return ['token' => $token];});

Token dạng văn bản thuần chỉ hiển thị một lần duy nhất ngay lúc tạo; trong cơ sở dữ liệu Sanctum chỉ lưu bản băm. Đối số thứ hai là danh sách abilities (khả năng), giúp bạn giới hạn quyền của từng token.

Bảo vệ route và kiểm tra quyền

Route::middleware('auth:sanctum')->group(function () {    Route::get('/me', fn (Request $request) => $request->user());    Route::get('/posts', function (Request $request) {        abort_unless($request->user()->tokenCan('posts:read'), 403);        return Post::latest()->paginate();    });});

Client gửi yêu cầu với header như sau:

Authorization: Bearer 1|abcdef...

Khi đăng xuất, hãy thu hồi token đang dùng: $request->user()->currentAccessToken()->delete();. Muốn đăng xuất khỏi mọi thiết bị thì dùng $request->user()->tokens()->delete();.

Lưu ý bảo mật khi dùng token

  • Luôn chạy API qua HTTPS, vì token trong header là chìa khóa vào tài khoản.
  • Trên ứng dụng di động, lưu token ở nơi an toàn của hệ điều hành (Keychain, Keystore), đừng lưu ở nơi dễ đọc.
  • Đặt thời hạn hết hạn bằng cấu hình expiration trong config/sanctum.php và cân nhắc cơ chế làm mới.
  • Cấp quyền tối thiểu cần thiết cho mỗi token thay vì cho toàn quyền.
  • Kết hợp giới hạn tần suất đăng nhập để hạn chế dò mật khẩu.

Sanctum hay Passport?

Passport là bản triển khai đầy đủ OAuth2, phù hợp khi bạn cần cấp quyền cho ứng dụng bên thứ ba, giống kiểu "đăng nhập bằng tài khoản của chúng tôi". Nếu chỉ phục vụ ứng dụng của chính mình, Sanctum đơn giản và đủ tốt hơn nhiều. Chọn công cụ nhẹ nhất đáp ứng được yêu cầu là nguyên tắc hay.

Thử nghiệm API bằng công cụ dòng lệnh

Sau khi xây xong, bạn có thể kiểm tra nhanh luồng bằng curl. Đầu tiên đăng nhập để lấy token, sau đó dùng nó gọi endpoint được bảo vệ:

curl -X POST https://api.example.com/login \  -H "Accept: application/json" \  -d "email=a@example.com&password=secret123"curl https://api.example.com/me \  -H "Accept: application/json" \  -H "Authorization: Bearer 1|abcdef..."

Hãy luôn gửi header Accept: application/json. Nếu thiếu, khi lỗi xác thực Laravel có thể chuyển hướng về trang đăng nhập thay vì trả về JSON 401, khiến ứng dụng di động của bạn nhận được một trang HTML khó hiểu.

Xử lý lỗi từ phía client

Ứng dụng khách nên xử lý mã 401 một cách nhất quán: xóa token đã lưu và đưa người dùng về màn hình đăng nhập. Nhờ vậy, khi token hết hạn hoặc bị thu hồi, trải nghiệm vẫn mượt mà, người dùng không bị kẹt ở trạng thái đăng nhập giả. Đây là chi tiết nhỏ nhưng ảnh hưởng nhiều đến cảm nhận về chất lượng ứng dụng.

Gợi ý luyện tập

Hãy thử xây một API ghi chú cá nhân gồm bốn endpoint: đăng ký, đăng nhập, danh sách ghi chú của riêng bạn và đăng xuất. Điểm mấu chốt là đảm bảo người dùng A không thể đọc ghi chú của người dùng B, nghĩa là mọi truy vấn phải lọc theo $request->user(). Làm xong bài này, bạn đã nắm được phần lớn kiến thức xác thực API cần cho một ứng dụng di động thực tế.

Kết luận

Với vài bước ngắn, Sanctum cho bạn hệ thống xác thực token an toàn và dễ quản lý. Hãy thử xây một API nhỏ có đăng nhập, lấy thông tin cá nhân và đăng xuất, bạn sẽ hiểu trọn vòng đời của một token.

Khi cần một lộ trình học có hệ thống, bạn có thể tham khảo khóa học trên codebem.com.

author_photo
Nguyễn Đình Cường

0 comment