• Terry L.

    (@terrylin)


    I’ve been building a new plugin with a React-based admin UI, supporting both the Block Editor and Classic Editor. My design relies heavily on the REST API rather than the legacy wp-ajax system.

    Lately, I’ve run into a recurring issue: even though the UI shows I’m clearly logged in, the REST API keeps throwing 403 Forbidden errors.

    Here’s the context of my environment:

    1. Browser storage cache is forced off.
    2. Absolutely no server-side or object caching is active.
    3. I am confirmed logged in; I can navigate the WP Admin dashboard freely without issues.

    In the past, a manual logout and login would “fix” it, but I had a gut feeling this was a fundamental nonce exchange flaw. If I’m hitting this as a developer, there’s a high chance my users will too. So today, I decided to dig into the root cause.

    To rule out my own code, I checked the WordPress Site Health page, even the core Site Health API calls were failing with a 403.

    Upon inspecting the session cookies, I found two identical cookies with the same name but different paths. I traced the logic back to pluggable.php here:

    https://github.com/WordPress/WordPress/blob/59e1…/wp-includes/pluggable.php#L1193-L1195The most important wordpress_logged_in cookie is was completely missing, yet I could still browse the admin pages.

    My dev environment is clean, just WordPress and WooCommerce for testing product features. No other plugins.

    Steps to Reproduce:


    Step 1:

    Log in normally. You’ll typically see three cookies:

    • wordpress_{hash} (Path: /wp-admin)
    • wordpress_{hash} (Path: /wp-content/plugins)
    • wordpress_logged_in_{hash} (Path: /)

    Step 2:

    Manually delete the wordpress_logged_in cookie.


    The Admin UI still works perfectly fine. You can click around and visit different pages. This feels like a security-level bug: the dashboard remains accessible even without the primary login cookie. However, the REST API is now officially broken (403), and Site Health is dead. This is because REST nonces rely on that specific logged_in cookie to validate.

    Step 3:

    Delete the wordpress_{hash} cookie (Path: /wp-admin).
    Only then are you finally kicked out to the login screen.


    I haven’t fully investigated why the wordpress_logged_in cookie disappears in the first place, but I don’t think that’s even the main point. The real issue is that modern WordPress admins rely heavily on the REST API, but the nonce generation is tied to the wordpress_logged_in cookie, while the Admin UI itself is guarded by a completely different set of “admin-only” cookies.

    This is a fundamental design flaw. You have a situation where the system thinks you are “logged in enough” to see the dashboard, but “not logged in enough” to use the APIs that power that very dashboard.

Viewing 3 replies - 1 through 3 (of 3 total)
  • Moderator threadi

    (@threadi)

    Check very carefully which URLs you are using for each call. If a different domain and, above all, a different protocol is used for the REST API, the browser may not be able to use the necessary cookie, which will result in the 403 message.

    • This reply was modified 2 months ago by threadi.
    Thread Starter Terry L.

    (@terrylin)

    Thanks for replying. I checked and tested very carefully, by the way, deleting the wordpress_logged_in cookie while using the Block Editor triggers a ‘retry storm’, the editor enters an endless loop of trying to reload blocks and patterns. I also pushed a PR here: https://github.com/WordPress/WordPress/pull/785

    Moderator threadi

    (@threadi)

    If you see a need for a change to the core here, I would recommend submitting a ticket in Core Trac, including a description of what it’s about (as here in the topic): https://core.trac.ww.wp.xz.cn – this will allow core developers to better evaluate the issue.

Viewing 3 replies - 1 through 3 (of 3 total)

You must be logged in to reply to this topic.