Question

I am using CakePHP 2.4 and Facebook PHP SDK 3.2.3 to create login form, which has two options: local login and login with facebook. I have been referring to How do I integrate Facebook SDK login with cakephp 2.x? on how to create login actions and view for Facebook login.

Now I have working local login, and when I press to facebook login, I am redirected to Facebook and back again to my login action of plugin Users. However I get no response in $_GET['code'] or $this->request->query['code'].

This is my login action:

    public function login() { 
        if ($this->Auth->user()) {
            $this->Session->setFlash(__('You are already registered and logged in!'),          'flash_info');
        $this->redirect('/');
    }
    if ($this->request->is('post')) {
        if ($_SERVER['HTTP_HOST'] == Configure::read('webakis.touchscreen_host')) {
            $this->request->data['User']['username'] = $this->request->data['User']['name'] . ' ' . $this->request->data['User']['surname'];
        }

        if ($this->Auth->login()) {
            $this->User->id = $this->Auth->user('id');
            $this->User->saveField('last_login', date('Y-m-d H:i:s'));

            if ($this->here == $this->Auth->loginRedirect) {
                $this->Auth->loginRedirect = '/';
            }
            $this->Session->setFlash(sprintf(__('%s you have successfully logged in'), $this->Auth->user('name')), 'flash_success');
            if (!empty($this->request->data)) {
                $data = $this->request->data[$this->modelClass];
                $this->_setCookie(array('name' => 'AKIS'), 'User');
            }

            if (empty($data['return_to'])) {
                $data['return_to'] = null;
            }

            $this->redirect($this->Auth->redirect($data['return_to']));
        } else {
            $this->Session->setFlash(__('Invalid e-mail / password combination.  Please try again'), 'flash_error');
        }
    }
    // When facebook login is used, facebook always returns $_GET['code'].
    if($this->request->query('code')){ //Execution doesn't get in here

        Debugger::log($this->request->query);

        // User login successful
        $fb_user = $this->Facebook->getUser();          # Returns facebook user_id
        if ($fb_user){

            Debugger::log($fb_user);
            $fb_user = $this->Facebook->api('/me');     # Returns user information

            // We will varify if a local user exists first
            $local_user = $this->User->find('first', array(
                'conditions' => array('email' => $fb_user['email'])
            ));

            // If exists, we will log them in
            if ($local_user){
                $this->Auth->login($local_user['User']);            # Manual Login
                $this->redirect($this->Auth->redirectUrl());
            } 

            // Otherwise we ll add a new user (Registration)
            else {
                $data['User'] = array(
                    'username'      => $fb_user['email'],                               # Normally Unique
                    'password'      => AuthComponent::password(uniqid(md5(mt_rand()))), # Set random password
                    'role'          => 'registered'
                );

                // You should change this part to include data validation
                $this->User->save($data, array('validate' => false));

                $this->redirect('/');
                // After registration we will redirect them back here so they will be logged in
                //$this->redirect(Router::url('/users/login?code=true', true));
            }
        }   
    }
    if (isset($this->request->params['named']['return_to'])) {
        $this->set('return_to', urldecode($this->request->params['named']['return_to']));
    } else {
        $this->set('return_to', false);
    }
    $allowRegistration = Configure::read('Users.allowRegistration');
    $this->set('allowRegistration', (is_null($allowRegistration) ? true : $allowRegistration));
    Configure::write('keyboard', 1);
}

Without getting response here, I can't handle my facebook login logic.

These are responses I get then facebook redirects me back to login page: enter image description here

Two interesting requests (with Url params and location shown):

GET oauth?....

client_id=671394586273323
ext=1406709978
hash=AeYXzQgAjCbRdY4g
redirect_uri=http://127.0.0.1.xip.io/users/users/login
ret=login
sdk=php-sdk-3.2.3
state=9d030270aa50f2e52ac4aa66a37cd0fd

Location: http://127.0.0.1.xip.io/users/users/login?code=AQC_UtjKJU8a2leJMFAB4_1qx1mh1ww0-sRWdAD5vCocfKuZPTF4iSdKYwqxQUsm9N-_1tSPGfh3LYQXbXjYeY2onVBD6gTvJ5amvRZm5ZjI1OSYoLkqgjBsdfjWSdXTigCIQLf5d180keXTCf5jRiOXi8pWi0V2UxXqVl4K9QWWq2qGfSGuXlJMr32NZqKYR0Z93LyR1EiRFJPohfo6-j0kZJrNTkljCbY16Nrq1InqQLdYwGCOSg4IrbR0auaMIWTlnUCKFCr4DT3If_5HPFEDM6ZigeUvURM-q8y-CxDrRIctSmT4Bz1UevPqR-hOMbgKGzYUplatRywzjq_-R7bt&state=9d030270aa50f2e52ac4aa66a37cd0fd#_=_

GET login?code....

code=AQC_UtjKJU8a2leJMFAB4_1qx1mh1ww0-sRWdAD5vCocfKuZPTF4iSdKYwqxQUsm9N-_1tSPGfh3LYQXbXjYeY2onVBD6gTvJ5amvRZm5ZjI1OSYoLkqgjBsdfjWSdXTigCIQLf5d180keXTCf5jRiOXi8pWi0V2UxXqVl4K9QWWq2qGfSGuXlJMr32NZqKYR0Z93LyR1EiRFJPohfo6-j0kZJrNTkljCbY16Nrq1InqQLdYwGCOSg4IrbR0auaMIWTlnUCKFCr4DT3If_5HPFEDM6ZigeUvURM-q8y-CxDrRIctSmT4Bz1UevPqR-hOMbgKGzYUplatRywzjq_-R7bt
state=9d030270aa50f2e52ac4aa66a37cd0fd

Location:   http://127.0.0.1.xip.io/eng/login

I find it strange with code is not URL parameter in first request, but it is in URL, second response shows inverse situation.

OK, so this might be routing issue.

    $this->set('fb_login_url', $this->Facebook->getLoginUrl(array('redirect_uri' => Router::url(array('plugin'=> 'users', 'controller' => 'users', 'action' => 'login'), true)))); 

Router::url() returns: http://127.0.0.1.xip.io/users/users/login

My Router connects:

    Router::connect('/:language/login', array('plugin' => 'users', 'controller' => 'users', 'action' => 'login'), array('language' => '[a-z]{3}'));
    Router::connect('/:language/logout', array('plugin' => 'users', 'controller' => 'users', 'action' => 'logout'), array('language' => '[a-z]{3}'));
    Router::connect('/:language/register', array('plugin' => 'users', 'controller' => 'users', 'action' => 'add'), array('language' => '[a-z]{3}'));
    Router::connect('/:language/users', array('plugin' => 'users', 'controller' => 'users'), array('language' => '[a-z]{3}'));
    Router::connect('/:language/users/index/*', array('plugin' => 'users', 'controller' => 'users'), array('language' => '[a-z]{3}'));
    Router::connect('/:language/users/:action/*', array('plugin' => 'users', 'controller' => 'users'), array('language' => '[a-z]{3}'));
    Router::connect('/:language/users/users/:action/*', array('plugin' => 'users', 'controller' => 'users'), array('language' => '[a-z]{3}'));

Al these urls redirects to: http://127.0.0.1.xip.io/eng/login . This might be problem, as Facebook SDK have different redirect URL, so then it redirects to http://127.0.0.1.xip.io/users/users/login , there is also request to redirect to http://127.0.0.1.xip.io/eng/login. The query parameter 'code' may get lost after this redirection.

Was it helpful?

Solution

As can be seen in the network console and the from the headers that you've posted, your server is doing an additional redirect, and as already mentioned in my comment this is where the query parameters are being lost.

It looks like the redirect URL that you are passing to Facebook is wrong, it is

http://127.0.0.1.xip.io/users/users/login

which contains most likely at least a surplus users (not sure where this stems from, you'll have to figure that on your own) unless you are using a plugin called Users which contains a controller named UsersController, so maybe it should be more like

http://127.0.0.1.xip.io/users/login

However, considering that your server redirects to /eng/login when accessing /users/users/login, it may be that the redirect URL passed to Facebook is wrong altogether.

So first you'll have to figure out the actual proper URL of your login, and then make sure that Router::url() (assuming you are using the code from the linked question) actually generates that exact URL.

Update

From looking at your updated question, I don't see why any of these routes should cause a redirect, they aren't redirect routes, but just routes. The actual redirect will stem from somewhere else.

In case the redirect to /eng/login is acutally indended, then you'll have to make sure that you pass that URL as the redirect URL to Facebook, that is properly invoke Router::url() with the language key set so that it will match your first route

Router::url(
    array(
        'plugin' => 'users',
        'controller' => 'users',
        'action' => 'login',
        'language' => 'eng'
    ),
    true
);

or use the persist option in your routes so that a call to Router::url() without the language key will match your route in case the current URL contains the language element, something along the lines of

Router::connect(
    '/:language/login',
    array('plugin' => 'users', 'controller' => 'users', 'action' => 'login'),
    array('language' => '[a-z]{3}', 'persist' => array('language'))
);
// ...

// connect all default routes with a persistent language prefix
Router::connect(
    '/:language/:controller/',
    array('action' => 'index'),
    array('language' => '[a-z]{3}', 'persist' => array('language'))
);
Router::connect(
    '/:language/:controller/:action/*',
    array(),
    array('language' => '[a-z]{3}', 'persist' => array('language'))
);

or, as a last option, include the query string in the redirect to /eng/login

array(/* other route params */, '?' => $this->request->query)

OTHER TIPS

Due to Router issues I changed redirect uri parameter in $this->Facebook->getLoginUrl() to 'redirect_uri' => Router::url('/', true).Configure::read('Config.language').'/login' , as it resolves to http://127.0.0.1.xip.io/eng/login .

Now I get $this->request->query('code') param, so my code should work for now.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top