PHP SDK 8 - Invalid State After SignUp Redirect

SDK 8
PHP 7.4
WordPress - Custom Plugin

I have a plugin to create the authorisation URL and send users to sign up - the link creation seems to work (and it used to) but now after signing up the user comes back to our callback page - this triggers a function to run to try and complete the exchange.

This used to work when we used $auth0->signup(ROUTE_URL_CALLBACK); to generate the URL, but now we want it to go to signup instead, and so are using this… $auth0->login(ROUTE_URL_CALLBACK, array( “screen_hint” => “signup” ));

Any guidance on this would be a great help.

This is the callback function…

function ****_auth0_exchange() {

global $auth0;

// Have the SDK complete the authentication flow:
$auth0->exchange(ROUTE_URL_CALLBACK);

echo "Authorising...";

}

$auth0->exchange(ROUTE_URL_CALLBACK); - generates below

Fatal error: Uncaught Auth0\SDK\Exception\StateException: Invalid state in
/home//wp-content/plugins//vendor/auth0/auth0-php/src/Exception/StateException.php:24 Stack trace:
#0 /home//wp-content/plugins//vendor/auth0/auth0-php/src/Auth0.php(322): Auth0\SDK\Exception\StateException::invalidState()
#1 /home//wp-content/plugins//src/classes/auth0.php(53): Auth0\SDK\Auth0->exchange()
#2 /home//wp-content/plugins//src/shortcodes.php(17): _auth0_exchange()
#3 /home/
/wp-includes/shortcodes.php(356): _auth_callback()
#4 [internal function]: do_shortcode_tag()
#5 /home/
/wp-includes/shortcodes.php(228): preg_replace_callback()
#6 /home//wp-includes/ in /home//wp-content/plugins/****/vendor/auth0/auth0-php/src/Exception/StateException.php on line 24

Hi @paulrileydnrg :wave:

An InvalidState exception is thrown from the PHP SDK during exchange() when the state parameter returned by Auth0 doesn’t match the temporary cookie stored on the client when login() is fired before the redirect. This means there is either an issue with the cookie getting stored properly on the client before getting redirected, being retrieved from the client during callback, or an issue with pulling the state response from the callback request.

  • Check your Auth0 logs for anything out of the ordinary with the request
  • Ensure you have both code and state parameters the URI of your application’s callback; if there is an error parameter something is going wrong with the request, and should be in your Auth0 logs
  • Use your browser dev tools to ensure the transient cookie is being set properly before the redirect
  • Unrelated, but we have an Auth0::signup() helper method for issuing the ?screen_hint requests, so you don’t have to craft it yourself :slight_smile:
2 Likes

Hi,

Thanks for your response.

The log seems OK, just Successful Signup and then Successful login immediately after.

Here’s the URL for our signup button…

https://XXXXXXX/authorize?
state=f237b83b2bf5b074d8c9b4fbbf2e09ea&
client_id=XXXXXXX&
redirect_uri=XXXXXXX%2Fauthorising&
scope=openid%20profile%20email&
response_mode=query&
response_type=code&
screen_hint=signup&
nonce=c7831266aef58629587ad4728d96243f&
code_challenge=Pyzcgdj9wWPE8uc4xorUzq9WRDGtVkNRxvNd2N1NtYc&
code_challenge_method=S256

I can see a cookie being created on the page, it’s not named as I’ve seen online as auth_state or similar, but a long alphanumeric name, I assume this is the cookie you mentioned?

image

And the callback URL seems to have the code and state

https://XXXXXXX/authorising/?
code=O2hFjjwW96fwvZ_z&
state=f237b83b2bf5b074d8c9b4fbbf2e09ea

There is no cookie when on the callback URL - is that right?

THanks again for your help

Hey again @paulrileydnrg,

Hmm, curious! That would appear to be the encrypted session cookie created by the SDK, and it appears you’re being returned the same state we’re sending to Auth0 during authorization.

Some troubleshooting that comes to mind:

  • Are you certain Auth0::login() is only being fired once? If it’s inadvertently called twice, the state on the client would be getting overwritten and would result in this error. (Would be unusual, but I’ve seen it come up before, and I’d be remissed if I didn’t mention it!)
  • Assuming you’re using Chrome, try using the Network tab to review “doc” requests, and check the Cookies tab. You should be able to observe request and response events occurring on the cookies. Is this encrypted cookie showing in the “request” section, and being cleared in the “response”?

Beyond this, the next step I’d try is modifying the exchange() method in the SDK in your dependencies. In your /home/wp-content/plugins/vendor/auth0/auth0-php/src/Auth0.php file, I would temporarily change this code block:

        if ($state === null || ! $this->getTransientStore()->verify('state', $state)) {
            $this->clear();
            throw \Auth0\SDK\Exception\StateException::invalidState();
        }

to:

        $tempStateLookup = $this->getTransientStore()->getStore()->get('state', '[NOT SET ON CLIENT]');

        if ($state === null || ! $this->getTransientStore()->verify('state', $state)) {
            $this->clear();
            throw new \Auth0\SDK\Exception\StateException('Expected state to be ' . $state . '; client had ' . $tempStateLookup);
        }

Obviously, you want to avoid running this in production, but this would let you know (1) if the assigned state is, in fact, available from the client during exchange() and (2) help figure out what the discrepancy is between what was assigned to the client and returned to your endpoint.

1 Like

Hi - thanks for this - turned out be firing twice so the state was wrong.

Appreciate the help

1 Like

No problem, glad we got it sorted! :+1:

2 Likes

Teamwork makes the dreamwork!

2 Likes