I'm running into the same issue as @whip from last year (Session is reset after redirect from Apple) with my PHP configuration trying to implement "Sign in with Apple" into my website. I fully expect that my issues stem from a lack of understanding around how the browser and PHP handle session cookies. Hopefully, with a more detailed description of my configuration and the events taking place, the underlying issue can be found and help someone else in the future.
Example code and documentation for Sign in with Apple
implementation is coming from this blog post. It is one of the few examples that walks through both the setup of the necessary Apple client and service IDs, but also shows token decoding examples. (https://developer.okta.com/blog/2019/06/04/what-the-heck-is-sign-in-with-apple)
As you can see in the example, there is a temporary random state
variable that is saved into a PHP session. This is used to validate the returning POST from Apple to ensure that the correct response session is being addressed. In my case, however, the redirection POST request from Apple is causing (in most cases, see below) a new PHPSESSID cookie to be created and the previously-saved state
variable is being lost.
Here is what I am currently experiencing in the authentication flow:
state
variable created and saved into session variable:$_SESSION['state'] = bin2hex(random_bytes(5));
Sign in with Apple
button as per documentation
Application
tab, you can see that there is a PHPSESSID
cookie managing the current session. In this case it has ID tk4bh...
appleid.apple.com
to start auth loop
Redirect URL
was provided in the initial Sign in with Apple
link (Note: this URL needs to be added to the Apple Service ID used for the client)State
variable provided by the return POST payload does not match the saved $_SESSION['state']
variable. This is because the $_SESSION['state']
value is not set.Application
tab, you can see that there is a PHPSESSID
cookie present, but that it is a new cookie. The ID for this new cookie is now rf1k5...
Interestingly, however, if you add a step to the previous process and start with a completely fresh cookie, then go through the process, the cookie is retained after the return POST request from Apple and the authentication loop can be completed. So you right click on the website's name from within the browser inspector's Applications
tab and choose Clear
. Then refresh the login page to save the State
session variable, click on the Sign in with Apple
button, complete the process and return to the page to find a successful login.
So the question remains, why is a newly-created cookie able to persist in the browser through the Apple authorization look and redirection, but a cookie that has been created at some other point in the user's browsing (every page shares the same session_start method) and then used for saving the validation state
variable consistently gets "forgotten" and a new cookie has to be created?
Website is running nginx and PHP 8.1.29. Current session INI config as follows:
NOTE:
//---------------------------------------------------------
// safe wrapper around `session_start` to ensure session id is valid, avoiding PHP warnings/errors
function safe_session_start() {
// if session has already started, just return
if ( session_status() != PHP_SESSION_NONE ) {
return true;
}
if ( isset($_COOKIE[session_name()]) AND ! preg_match('/^[-,a-zA-Z0-9]{1,128}$/', $_COOKIE[session_name()]) ) {
unset($_COOKIE[session_name()]);
}
$options = ['cookie_secure' => COOKIE_SSL, 'cookie_httponly' => true, 'cookie_domain' => COOKIE_DOMAIN, 'cookie_path' => COOKIE_PATH];
return session_start($options);
}
//---------------------------------------------------------
You are probably experiencing the new cookies SameSite
security default settings in the browsers.
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value
If the cookie SameSite is not saved as none
, it will not be loaded by the Apple callback, which will be generating a brand new session when hitting the callback endpoint.
When using Laravel, you can change this behaviour in session.php
'secure' => true, //only https
'same_site' => 'none' //allow cross-site cookie requests
so as long as the site is on https
, the original cookie and therefore the existing session will be preserved.
Another option would be caching your session before going to the Apple auth screen like
$sessionData = session()->all();
$token = Str::random(40); //or use a uuid, csrf_token() ...
Cache::put($token, $sessionData, now()->addMinutes(30));
Send $token
as the "nonce" value to Apple, then retrieve it in the callback
$sessionData = Cache::get($token); //from nonce value in Apple callback
if ($sessionData) {
session()->flush();
session()->put($sessionData);
Cache::forget($token);
}
This way, you temporarily store the session data securely and re-establish it after the user logs in with Apple, without relying on cookies.