FriendsOfSymfony / FOSOAuthServerBundle

A server side OAuth2 Bundle for Symfony
1.09k stars 450 forks source link

Is it possible to use google oauth token as authorization for rest api #294

Open antonioperic opened 9 years ago

antonioperic commented 9 years ago

Hi, guys... I didn't work with FOSOAuthServerB before. I have one project, SPA + Hybrid mobile application where user are getting authorized with their Google Account. I want to use that login also as authorization for my REST Api. Is that possible with do with FOSOAuth? I suppose that will be some custom grant?

Anybody with similar experience?

stof commented 9 years ago

No it is not. FOSOAuthServerBundle is about implementing the server-side part of OAuth. In your case, this is done by Google. What you need is probably https://github.com/hwi/HWIOAuthBundle/ instead

antonioperic commented 9 years ago

@stof i think HWIO protects rest api after firewall? But my idea is to have complete separeted singlepageapp/mobile app and to do authorization for my api with google access token. I saw some example where this scenario is pulled with custom grant for facebook, but not sure if that is rigth way

antonioperic commented 9 years ago

@stof something like this http://programmingadvises.blogspot.com/2014/07/symfony-fosoauthserverbundle-access-api.html

What do you think about this approach?

rparsi commented 8 years ago

@antonioperic I recommend NOT combining OAuth authentication with your own Rest api. Instead use something like JSON web tokens (jwt), there are Symfony bundles for them or you can use non-framework specific packages.

bblue commented 8 years ago

+1 I am interested in this as well.

Here is another resource touching on the same point by using a custom grant. The comment section does however state this is a security risk. http://blog.tankist.de/blog/2013/08/20/oauth2-explained-part-4-implementing-custom-grant-type-symfony2-fosoauthserverbundle/

There is also a similar question on StackOverflow, but no solution sadly. http://stackoverflow.com/questions/35373319/symfony3-fosoauthserverbundle-and-facebook-or-google-login

Nightbr commented 8 years ago

hey, I implement this for my REST API + Mobile App. Here is how I solved this problem:

Scenario

  1. [Mobile App] use the Facebook SDK to retrieve a Facebook accessToken
  2. [Mobile App] send a request to my [Authorization Server]

    api/oauth/v2/token with parameters:
    
    * client_id
    * client_secret
    * grant_type = https://domain.com/connect/facebook
    * facebook_access_token
  3. [Authorization Server] validates the facebook_access_token and return an access token for our REST API

Implementation

client-side

Implement the OAuth SDK of your 3rd-party service to get an access token from an authorization code (OAuth2.0 classic workflow). I use the official Facebook SDK for example.

Some CoffeeScript code:

$scope.login = ->
        facebookConnectPlugin.login(['email','user_friends','public_profile','user_birthday'], fbLoginSuccess , fbLoginError)

    fbLoginSuccess = (userData) ->
        $ionicLoading.show
            template: '<ion-spinner></ion-spinner>'
            fbLogin(userData.authResponse.accessToken)

    fbLoginError = (error) ->
        $log.error "error facebook login: ", error

    fbLogin = (token) ->
        UserManager.fbLogin(token).then (res) ->
            # Login Success !!
            $rootScope.$broadcast('login:refresh')
            $ionicLoading.hide()
            # go to this after login
            $ionicHistory.nextViewOptions
                disableBack: true
            $state.go 'base.profile.home', {}, {reload: true}
            $ionicHistory.clearCache()
        .catch (error) ->
            # handle server error here
            $ionicLoading.hide()
            $log.debug 'loginFBerrorCtrl:', error
            $scope.error = error

And the UserManager.fbLogin(token)


    # Generate userAccessToken from facebook_access_token
    AccessTokenFactory.facebookAccessToken = (fbToken) ->
        deferred = $q.defer()
        $http
            method: 'GET'
            url: urlBase + 'oauth/v2/token'
            params:
                client_id: config.oauth_client_id
                client_secret: config.oauth_client_secret
                grant_type: 'https://welp.fr/connect/facebook'
                facebook_access_token: fbToken
        .then (response) ->
            if response.data.error
                deferred.reject response.error_description
            else
                # Login successful
                deferred.resolve response.data.access_token

------------------------------------------------------------------------------------

    # Connect with Facebook
    UserManager.fbLogin = (fbToken) ->
        deferred = $q.defer()
        AccessTokenFactory.facebookAccessToken(fbToken)
        .then (token) ->
            $http
                method: 'GET'
                url: urlBase + 'users/me'
            .then (response) ->
                storage.currentUser = JSON.stringify(response.data.entity)
                $rootScope.$broadcast 'loginSuccess', storage.currentUser
                deferred.resolve response.data.entity
        , (error) ->
            # forward error
            deferred.reject error
        deferred.promise

server-side

I use the HWIOAuthBundle and a grant-type extension to validate the Facebook access_token and exchange it against my API access token.

Here it is my OAuth/FacebookGrantExtension.php

<?php
namespace ApiBundle\OAuth;

use Symfony\Component\Security\Core\User\UserProviderInterface;
use FOS\OAuthServerBundle\Storage\GrantExtensionInterface;
use OAuth2\Model\IOAuth2Client;

use HWI\Bundle\OAuthBundle\OAuth\Response\PathUserResponse;

use AppBundle\Entity\User;

class FacebookGrantExtension implements GrantExtensionInterface
{

    protected $userProvider;
    protected $resourceOwner;

    public function __construct(UserProviderInterface $userProvider, $resourceOwner)
    {
        $this->userProvider = $userProvider;
        $this->resourceOwner = $resourceOwner->getResourceOwnerByName('facebook');
    }

    /*
     * {@inheritdoc}
     */
    public function checkGrantExtension(IOAuth2Client $client, array $inputData, array $authHeaders)
    {

        if (!isset($inputData['facebook_access_token'])) {
            return false;
        }

        // loadUser information
        $userInformation = $this->resourceOwner->getUserInformation(array('access_token' => $inputData['facebook_access_token']));

        if (empty($userInformation)) {
            return false;
        }

        // loadUser from user provider
        $user = $this->userProvider->loadUserByOAuthUserResponse($userInformation);

        if (!is_object($user) || !$user instanceof User) {
            return false;
        }

        // Not display registrationCompleted page
        $this->userProvider->notDisplayRegisterCompleted($user);

        return array(
            'data' => $user,
        );
    }
}

Configure properly the HWIOAuthBundle (for Facebook or Google) and it will works like a charm!!

NOTE: Don't forget to add the grant-type to your client!!!! If you use the command line to create a client:

php app/console welp:oauth-server:client:create --name="Mobile app" --redirect-uri="CLIENT_HOST" --grant-type="authorization_code" --grant-type="password" --grant-type="refresh_token" --grant-type="token" --grant-type="client_credentials" --grant-type="https://domain.com/connect/facebook"

I use this in production for Facebook and I will implement Google soon.

If you have any questions, feel free to ask!

Regards,

Titouan

fabrizio5 commented 7 years ago

@Nightbr Hi, i'd like to implement your server-side code but i don't undestand how i have to configure "FacebookGrantExtension" service in service.yml . I tried this configuration:

app.api.oauth.facebook_extension:
    class: AppBundle\OAuth\FacebookGrantExtension
    arguments:
          - '@my.oauth_aware.user_provider.service'
          - '@.....'
    tags:
          - { name: fos_oauth_server.grant_extension, uri: 'http://localhost:8000/connect/facebook' }

What is the value that i have to set in the second argument of "app.api.oauth.facebook_extension" service?

Thank you very much for your help!!

Regards,

Fabrizio

Nightbr commented 7 years ago

Hey, I'm using the HWIO bundle to manage external OAuth connection from config.yml.

So the resources owner services comes from HWIOAuthBundle.

Here is my configuration for Facebook and Google grant:

    welp.api.oauth.facebook_extension:         class: ApiBundle\OAuth\FacebookGrantExtension         tags:             - { name: fos_oauth_server.grant_extension, uri: 'https://welp.fr/connect/facebook' }         arguments:             - "@app.oauth.user_provider"             - "@hwi_oauth.resource_ownermap.main"     welp.api.oauth.google_extension:         class: ApiBundle\OAuth\GoogleGrantExtension         tags:             - { name: fos_oauth_server.grant_extension, uri: 'https://welp.fr/connect/google' }         arguments:             - "@app.oauth.user_provider"             - "@hwi_oauth.resource_ownermap.main"

Look at the HWIOAuthBundle for more information: https://github.com/hwi/HWIOAuthBundle/

fabrizio5 commented 7 years ago

Thank you very much for your help! It works. 👍