Php crash issue when reloading link the following day

hello again -

first off, i am extremely impressed with Auth0, which is impressive considering the primary PHP example leaves this out:

‘scope’ => ‘openid profile email name nickname picture’

which is critical for getting facebook/msn/yahoo to authorize. (many people i know would have given up).

my latest question: when i come to my computer the following morning and just hit a page-refresh on a page that is (was??) logged in successfully, i am getting this error in my log:

PHP Fatal error:  Uncaught exception 'Auth0\SDK\Exception\CoreException' with message 'Invalid state' in /blah/blah/vendor/auth0/auth0-php/src/Auth0.php:558
Stack trace:
#0 /blah/blah/vendor/auth0/auth0-php/src/Auth0.php(480): Auth0\SDK\Auth0->exchange()
#1 /blah/blah/marksProgram.php(643): Auth0\SDK\Auth0->getUser()
#2 {main}
  thrown in /blah/blah/vendor/auth0/auth0-php/src/Auth0.php on line 558

in other words, i have a link that looks like this:

https://fakeDomain.com/marksProgram.php?code=wXXXXM1L&state=5de00c51.50050#

this will do page-refresh just fine for awhile, but the following day its throwing that error.

so this simple block of code works fantastic, but will fail the following day:

    $userInfo = $auth0->getUser();
    if (!$userInfo) {
            $auth0->login();
            exit;
    } else {
          // good login

and doing: try {} catch {} does not seem to catch it:

    $userInfo = $auth0->getUser();
    if (!$userInfo) {
            try {
                    $auth0->login();
                    exit;
            } catch (Exception $e) {
                    echo 'Caught exception: ',  $e->getMessage(), "\n";
            }
  } else {
        // good login

thoughts or suggestions?

Hey @edwardsmarkf,

Refreshing the page is probably causing your PHP app to try to exchange the code for an access_token for a second time.

Due to how OAuth works, code can only be exchanged once for a token. state is used to verify that the recipient of the code is the same client that initiated the auth transaction, and once the code is exchanged for the access_token, the state is discarded. Any subsequent calls to /oauth/token with the same state and an already used code will fail with the Invalid state error.

Basically, refreshing the page would fall into this category.

It would be great if there was some way to “catch” this error, or at least have a PHP function that could give you the state status without actually triggering an error.

in the meantime, i did find this:

<meta http-equiv="refresh" content="900;url=logout.php" />

This is a logout after a specified number of seconds regardless of activity.

This jQ solution will reset the timeout based on user activity:

$(document).idle({
  onIdle: function(){
    alert('You did nothing for 5 seconds');
  },
  idle: 5000
})

Does Auth0 have a built-in logout/timeout option based on user inactivity?

the primary PHP example leaves this out:

Appreciate the feedback here. The scope parameter is only needed when a login link is generated but it’s a little confusing in this context since you might only be instantiating that class once and using it in multiple places. I put through an update to the documentation here:

I’m also adding default scopes to the SDK itself to make the default authentication case work a little better:

It would be great if there was some way to “catch” this error

The getUser method is a bit overloaded but the code exchange is meant to happen only once in a designated callback URL, then a redirect to somewhere else. So, in your apps case, this URL:

https://fakeDomain.com/marksProgram.php?code=wXXXXM1L&state=5de00c51.50050

… should be something like this:

https://fakeDomain.com/callback.php?code=wXXXXM1L&state=5de00c51.50050

… which redirects to:

https://fakeDomain.com/marksProgram.php

In other words, whatever script/route that handles the callback should not leave the user on that route, it should redirect once it’s complete, success or otherwise.

That said, it’s the $auth0->getUser() that’s throwing the exception, not $auth0->login(). If you wrap that with a try/catch, you should be protected from that.

Hope this helps!

3 Likes

this worked fine:

    $userInfo = null;
    try {
            $userInfo = $auth0->getUser();
    } catch (Exception $e) {
            error_log( 'Line: ' . __LINE__ . '  -- Caught Auth0 exception: ' .  $e->getMessage() );
    }

    if (!$userInfo) {
            $auth0->login();
            exit;
    } else {
                     //  successful login

i can appreciate having a separate PHP logout script, but i am attempting to retrofit a number of existing PHP scripts, and so this succinct logic will probably work.

thoughts?

btw, thank you very much, Josh.

Having a separate script file for logout isn’t necessary but I would recommend separating the callback somehow, whether that’s a separate script/route or even just a specific URL parameter so you can keep that logic separate.

What you’ve got here is a good start but if you don’t handle that exception somehow, failing state will fall through, redirect to login, pick up SSO, and might end up in an infinite redirect. So I might recommend stopping the process at the exception catch and maybe prompt the user to login again (might could include a redirect to logout of Auth0 first).

You can see how this could get a bit tangled with all this logic in one place!

1 Like

ok Josh - please dont ever let it be said i am not open-minded:

    $userInfo = null;
    try {
            $userInfo = $auth0->getUser();
    } catch (Exception $e) {
            $auth0->logout();
            error_log( 'Line: ' . __LINE__ . ' -- Caught Auth0 exception: ' .  $e->getMessage() );
            header('Location: ?logout=1' ) ;
            exit;
    }
    if (!$userInfo) {
            $auth0->login();
            exit;
    } else {

and this is code section mainly reached when somebody clicks on logout but is also reached during an exception:

if (isset($_REQUEST['logout']))
{
    $auth0->logout();
    header('Location: ' . constant('Auth0_LogoutUrl'));
    exit;
}

i am hoping this will never lead to and infinite loop.