Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to maintain CakePHP sessions across multiple AJAX requests?
    primarykey
    data
    text
    <p><strong>Question in a Nutshell</strong></p> <p>I need to be able to maintain sessions across multiple AJAX requests in CakePHP. Currently, the sessions are lost in each AJAX request.</p> <p><strong>Background</strong></p> <p>I'm trying to convert a Facebook app's server-side (PHP-SDK) authentication to utilize client-side (JS-SDK) authentication instead. The app is built with CakePHP and makes use of the Auth component.</p> <p>The user flow I am trying to achieve is as follows:</p> <ol> <li>User enters app.</li> <li>User clicks a "Login with Facebook" button and authorizes the app via the Facebook auth dialog. I obtain the FB access token and pass it to the server via an AJAX call.</li> <li>Using the access token, the server determines whether the current user is a new or existing user and performs the necessary registration and/or login processes.</li> <li>The user may be still on the same page, and may trigger other AJAX functionality which require user authentication (on both CakePHP and Facebook). </li> <li>The server should read the session previously started via the AJAX call, and if the user is authenticated, perform the desired operation.</li> </ol> <p>The issue I have is with step 5 of the above flow. In particular, <code>$this-&gt;Auth-&gt;loggedIn()</code> returns false in the second (and subsequent) AJAX calls, and I get a HTTP 403 error. From my observation, it seems like the sessions are not being maintained as <code>$this-&gt;Session-&gt;id()</code> returns different values for each AJAX call.</p> <p>I have looked through many similar questions on StackOverflow, but have not found a working answer. Some I have viewed:</p> <ul> <li><a href="https://stackoverflow.com/questions/8518517/cakephp-session-component-mysterious-disappearance-of-session-data">CakePHP Session component - mysterious disappearance of session data</a></li> <li><a href="https://stackoverflow.com/questions/13028263/ajax-request-ends-cakephp-session">ajax request ends CakePHP session</a></li> <li><a href="https://stackoverflow.com/questions/5507568/cakephp-403-on-ajax-request">CakePHP 403 on AJAX request</a></li> </ul> <p>Here is my session configuration:</p> <pre><code>Configure::write('Session', array( 'defaults' =&gt; 'database', 'checkAgent' =&gt; false, 'ini' =&gt; array( 'session.cookie_secure' =&gt; false, 'session.referer_check' =&gt; false, 'session.cookie_httponly' =&gt; false ) )); </code></pre> <p>I have also tried <code>Configure::write('Security.level', 'medium')</code> as well to no avail.</p> <p>If it helps, here's the code I have for the AJAX login:</p> <pre><code>public function ajax_login() { $this-&gt;autoRender = false; $data = array(); $accessToken = $this-&gt;request-&gt;data['access_token']; $response = null; $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_URL, 'https://graph.facebook.com/oauth/access_token?client_id=' . FACEBOOK_SECURITY_APP_ID . '&amp;client_secret=' . FACEBOOK_SECURITY_SECRET . '&amp;grant_type=fb_exchange_token&amp;fb_exchange_token=' . $accessToken); parse_str(curl_exec($ch), $response); curl_close($ch); $newAccessToken = $response['access_token']; FB::setAccessToken($newAccessToken); try { $facebookUser = FB::api('/me', 'GET', array('fields' =&gt; 'id,username,first_name,last_name,email')); //Log in user //NOTE:: FB::getUser() returns 0 for some reason if ($facebookUser) { $isLoggedIn = $this-&gt;Auth-&gt;loggedIn(); //Log out app user if Facebook IDs do not match if ($isLoggedIn) { $appUser = $this-&gt;User-&gt;find('first', array( 'conditions' =&gt; array('id' =&gt; $this-&gt;Auth-&gt;user('id')), 'recursive' =&gt; -1 )); if ($appUser &amp;&amp; $appUser['User']['facebook_id'] != $facebookUser['id']) { $this-&gt;Auth-&gt;logout(); } } //Log in Facebook user $user = $this-&gt;User-&gt;findOrCreate($facebookUser); if (!$isLoggedIn) { $this-&gt;Auth-&gt;login($user['User']); } } //Log out app user if Facebook authentication fails else if ($this-&gt;Auth-&gt;loggedIn()) { $this-&gt;Auth-&gt;logout(); } } catch (FacebookApiException $e) { $data['error'] = $e-&gt;getResult(); } $data['status'] = $this-&gt;Auth-&gt;loggedIn() ? 1 : 0; echo json_encode($data); } </code></pre> <p><strong>Other Points</strong></p> <ul> <li>I am using CakePHP 2.4.3 and Nick's CakePHP Facebook plugin (<a href="https://github.com/webtechnick/CakePHP-Facebook-Plugin" rel="nofollow noreferrer">https://github.com/webtechnick/CakePHP-Facebook-Plugin</a>).</li> <li><code>$this-&gt;User-&gt;findOrCreate()</code> is a custom method that adds determines if the supplied Facebook user is an existing user, inserts records to the database if it isn't, and returns the found or created user.</li> <li>Ideally, I should avoid having the re-authenticate the user (on the server side) for each AJAX request. This would be akin to the workaround presented in <a href="https://stackoverflow.com/questions/13635991/an-active-access-token-must-be-used-dec-2012-the-proper-way-to-set-up-fac">&quot;An active access token must be used&quot; (Dec 2012) &amp;&amp; The proper way to set up Facebooks PHP-SDK for Ajax calls to get the user-id</a>.</li> <li>I also want to avoid passing session IDs in each AJAX request to maintain the session. It raises too many security concerns.</li> </ul> <p><strong>Bonus</strong></p> <p>Will be great if anyone can additionally figure why FB::getUser() in the above code returns 0 although FB::api('/me') works.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload