**TL;DR** - Why is my user account not logged in during an AJAX request which is made inside wp-admin? --- I have the following setup: <?php add_action('wp_ajax_foobar_action', 'foobar_action'); add_action('wp_ajax_nopriv_foobar_action', 'foobar_action'); function foobar_action() { check_ajax_referrer(); wp_send_json((object) ['msg' => 'hello world']); } add_action('admin_print_scripts', function () { printf('<script type="text/javascript">window.custom_nonce = "%s";</script>', wp_create_nonce()); }); And in JS: var msg = ''; // I'm using the whatwg-fetch polyfill and a polyfill for Promises. fetch(ajaxurl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' }, body: 'action=foobar_action&_wpnonce=' + window.custom_nonce }).then(function (res) { msg = res.json().msg; }); This is all run in wp-admin. The issue is that the wp-admin page/JS script itself is loaded as a logged in user, but the AJAX request that ends up into admin-ajax.php is done as a logged out guest user. This leads to the issue of wp-admin using `nopriv` and `check_ajax_referrer` failing 100% of the time. Why does wp-admin make AJAX requests as a guest instead of the logged in user? Currently, the AJAX endpoint returns `403` status with `-1` content, as it should in case there is a nonce mismatch. If I comment out the `check_ajax_referrer()` call then the AJAX request runs through successfully. After some furious `console.log`ging I've determined that the nonce values match in the JS fetch call and the AJAX endpoint that receives it (which means the nonce is properly transferred, but a wrong guest nonce is generated during the AJAX endpoint execution. If I remove the `wp_ajax_nopriv_foobar_action` then WordPress doesn't find the auth-enabled AJAX action because there seemingly is no logged in user available (results in status `200` and body `0`). Steps I've attempted to fix the issue: - Logged out and in again, cleared caches/cookies, used incognito windows, - Restarted PHP-FPM, Nginx, object cache backends, MariaDB, - Disabled all plugins that are not required for operation, - Moved the AJAX hooking code around in my plugin code, all the way to the plugin root file (e.g. `myplugin/myplugin.php`), - Used GET instead of POST.