**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.