Cách khắc phục lỗi 'rest_forbidden' (401/403) trên WordPress REST API

intermediate📝 WordPress2026-07-15| WordPress 5.6+, Apache/Nginx, PHP 7.4/8.x

Error Message

{"code":"rest_forbidden","message":"Sorry, you are not allowed to do that.","data":{"status":401}}
#rest-api#wordpress-dev#xác-thực#apache#nginx

Vấn đề: Lỗi xác thực trên các Private Route

Việc xây dựng một trang web WordPress headless hoặc ứng dụng di động thường diễn ra suôn sẻ cho đến khi bạn thực hiện các yêu cầu phức tạp hơn thay vì chỉ dùng GET đơn giản. Mọi thứ hoạt động tốt khi lấy các bài viết công khai. Tuy nhiên, ngay khi bạn cố gắng cập nhật người dùng hoặc tạo bản nháp, bạn sẽ gặp trở ngại. Ngay cả với thông tin xác thực hợp lệ, máy chủ vẫn từ chối yêu cầu với lỗi rest_forbidden.

{"code":"rest_forbidden","message":"Sorry, you are not allowed to do that.","data":{"status":401}}

Lỗi này thường có nghĩa là WordPress không nhận diện được danh tính của bạn hoặc không tin rằng bạn có các quyền cần thiết. Điều này cũng xảy ra với cả quản trị viên. Thông thường, nguyên nhân là do cấu hình máy chủ đã loại bỏ thông tin xác thực của bạn trước khi chúng đến được WordPress.

Quy trình Debug: Xác định điểm nghẽn

Đừng vội thay đổi mã nguồn ứng dụng cho đến khi bạn biết được quá trình giao tiếp bị lỗi ở đâu. Hãy làm theo các bước sau để cô lập vấn đề:

  • Phân tích Status Code: Status 401 là vấn đề về danh tính; máy chủ không biết bạn là ai. Status 403 là vấn đề về quyền hạn; máy chủ biết bạn, nhưng bạn thiếu 'capability' cần thiết (như edit_posts).
  • Cô lập lỗi bằng Postman: Thử thực hiện một yêu cầu POST bằng Basic Auth và Application Password trong Postman. Nếu cách này hoạt động nhưng ứng dụng của bạn thất bại, có khả năng ứng dụng của bạn đang không gửi header Authorization đúng cách.
  • Kiểm tra Header đã đến máy chủ chưa: Tạo một tệp test.php trong thư mục gốc chứa <?php print_r(getallheaders()); ?>. Nếu khóa Authorization bị thiếu trong kết quả trả về khi bạn gọi tệp này, máy chủ web của bạn đang loại bỏ nó.

Giải pháp 1: Sử dụng Application Passwords có sẵn

Kể từ phiên bản 5.6, WordPress đã tích hợp sẵn hệ thống xác thực API. Bạn không còn cần phải cài đặt các plugin Basic Auth của bên thứ ba nữa. Việc sử dụng mật khẩu quản trị thực tế của bạn cho các lệnh gọi API sẽ thất bại theo mặc định vì nó không an toàn và bị chặn.

  • Đi tới mục Users > Profile trong bảng điều khiển của bạn.
  • Tìm phần Application Passwords ở gần cuối trang.
  • Nhập tên như "NextJS Frontend" và nhấp vào Add New Application Password.
  • Lưu chuỗi 24 ký tự này ngay lập tức; bạn sẽ không thấy lại nó lần nữa.

Khi thực hiện các lệnh gọi, hãy sử dụng tên người dùng và chuỗi 24 ký tự này làm thông tin xác thực. Nếu bạn cần tạo các khóa có độ bảo mật cao cho các phần khác trong hệ thống, Password Generator có thể giúp ích, nhưng đối với tác vụ cụ thể này, hãy sử dụng những gì WordPress cung cấp.

Giải pháp 2: Khắc phục việc Apache loại bỏ Header

Apache là nguồn gây ra lỗi 401 phổ biến nhất. Nhiều nhà cung cấp shared host và các cấu hình mặc định thường loại bỏ header Authorization để ngăn rò rỉ thông tin xác thực. Hệ quả là WordPress nhận được yêu cầu nhưng không thấy thông tin đăng nhập.

Mở tệp .htaccess của bạn và chèn các dòng sau vào ngay trên cùng, trước khối # BEGIN WordPress block:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{1}]
</IfModule>

Chỉ thị này sẽ bắt lấy header và chuyển nó vào biến $_SERVER['HTTP_AUTHORIZATION']. Sau khi thiết lập xong, WordPress cuối cùng đã có thể thấy được Application Password của bạn.

Giải pháp 3: Điều chỉnh cấu hình Nginx

Nginx thường chuyển tiếp các header một cách đáng tin cậy, nhưng các thiết lập FastCGI cụ thể có thể làm mất chúng. Nếu bạn đang chạy trên Nginx, hãy kiểm tra tệp cấu hình trang web của bạn—thường nằm trong /etc/nginx/sites-available/. Hãy đảm bảo khối PHP của bạn bao gồm dòng sau:

fastcgi_pass_header Authorization;

Sau khi lưu tệp, hãy kiểm tra cấu hình của bạn bằng lệnh sudo nginx -t và tải lại dịch vụ bằng sudo systemctl reload nginx.

Giải pháp 4: Xác thực các yêu cầu AJAX nội bộ

Nếu script của bạn nằm trong hệ sinh thái WordPress—chẳng hạn như một plugin tùy chỉnh hoặc một Gutenberg block—đừng sử dụng Application Passwords. Thay vào đó, hãy sử dụng Nonce. Cách này an toàn hơn cho các script front-end vì nó gắn kết phiên làm việc với người dùng hiện đang đăng nhập.

Đầu tiên, chuyển nonce từ PHP sang JavaScript của bạn:

wp_localize_script( 'my-handle', 'wpSettings', [
    'nonce' => wp_create_nonce( 'wp_rest' )
]);

Sau đó, bao gồm header X-WP-Nonce trong lệnh gọi fetch JavaScript của bạn:

fetch('/wp-json/wp/v2/posts/42', {
    method: 'POST',
    headers: {
        'X-WP-Nonce': wpSettings.nonce,
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({ status: 'publish' })
});

Xác minh kết nối

Kiểm tra bản sửa lỗi của bạn bằng curl. Điều này giúp loại bỏ các vấn đề liên quan đến trình duyệt như CORS hoặc header bị cache. Chạy lệnh này trong terminal của bạn:

curl -X POST https://your-site.com/wp-json/wp/v2/posts \
    -u "username:xxxx-xxxx-xxxx-xxxx-xxxx-xxxx" \
    -H "Content-Type: application/json" \
    -d '{"title":"Connection Test","status":"draft"}'

Một bản sửa lỗi thành công sẽ trả về status code 201 Created. Nếu bạn nhận được lỗi 403, hãy xác minh rằng tài khoản người dùng của bạn có quyền "Edit Posts". Nếu bạn đang quản lý các tệp trên máy chủ và cần kiểm tra quyền của thư mục, một công cụ Unix Permissions Calculator sẽ hữu ích để đảm bảo thư mục wp-content của bạn không bị khóa quá chặt (thường là 755).

Tóm tắt các điểm chính

  • Máy chủ quan trọng hơn Mã nguồn: 90% lỗi 401 của REST API là do Apache hoặc Nginx loại bỏ các header.
  • Kiểm tra các Plugin bảo mật: Các công cụ như Wordfence hoặc 'All In One WP Security' có thể vô hiệu hóa hoàn toàn REST API. Hãy kiểm tra cài đặt của chúng nếu các bản sửa lỗi thủ công không thành công.
  • Quyền hạn (Capabilities) rất quan trọng: Authentication (bạn là ai) không phải là Authorization (bạn có thể làm gì). Đảm bảo người dùng của bạn có WordPress Role chính xác.

Related Error Notes