├── src ├── User │ └── UserSocialAccount.php ├── PassportSocialiteServiceProvider.php └── Bridge │ └── UserSocialRepository.php ├── composer.json ├── LICENSE └── README.md /src/User/UserSocialAccount.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright Copyright (c) Anand Siddharth 7 | * @license http://mit-license.org/ 8 | * 9 | * @link https://github.com/schedula/laravel-passport-socialite 10 | */ 11 | namespace Schedula\Laravel\PassportSocialite\User; 12 | 13 | interface UserSocialAccount { 14 | /** 15 | * Get user from social provider and from provider's user's id 16 | * 17 | * @param string $provider Provider name as requested from oauth e.g. facebook 18 | * @param string $id Id used by provider 19 | */ 20 | public static function findForPassportSocialite($provider, $id); 21 | } -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "schedula/laravel-passport-socialite", 3 | "description": "The missing laravel passport feature for social authentication", 4 | "keywords" : [ "laravel", "social-login", "laravel-passport", "passport", "laravel-socialite", "socialite"], 5 | "license": "MIT", 6 | "authors": [ 7 | { 8 | "name": "Anand Siddharth", 9 | "email": "anandsiddharth21@gmail.com" 10 | } 11 | ], 12 | "require": { 13 | "php": "^7.1.3", 14 | "laravel/passport": "^5.0 || ^6.0 || ^7.0", 15 | "laravel/socialite": "^4.0", 16 | "schedula/league-oauth2-social" : "^1.0", 17 | "illuminate/support": "~5.7 || ^6.0 || ^7.0" 18 | }, 19 | "autoload": { 20 | "psr-4": { 21 | "Schedula\\Laravel\\PassportSocialite\\": "src/" 22 | } 23 | }, 24 | "extra": { 25 | "laravel": { 26 | "providers": [ 27 | "Schedula\\Laravel\\PassportSocialite\\PassportSocialiteServiceProvider" 28 | ] 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Anand Siddharth 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/PassportSocialiteServiceProvider.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright Copyright (c) Anand Siddharth 7 | * @license http://mit-license.org/ 8 | * 9 | * @link https://github.com/schedula/laravel-passport-socialite 10 | */ 11 | 12 | namespace Schedula\Laravel\PassportSocialite; 13 | 14 | use Illuminate\Support\ServiceProvider; 15 | use Laravel\Passport\Bridge\RefreshTokenRepository; 16 | use Laravel\Passport\Passport; 17 | use League\OAuth2\Server\AuthorizationServer; 18 | use Schedula\League\OAuth2\Server\Grant\SocialGrant; 19 | class PassportSocialiteServiceProvider extends ServiceProvider { 20 | 21 | public function register () { 22 | app()->afterResolving(AuthorizationServer::class, function(AuthorizationServer $oauthServer) { 23 | $oauthServer->enableGrantType($this->makeSocialGrant(), Passport::tokensExpireIn()); 24 | }); 25 | } 26 | 27 | /** 28 | * Create and configure Social Grant 29 | * 30 | * @return Schedula\League\OAuth2\Server\Grant\SocialGrant 31 | */ 32 | public function makeSocialGrant() { 33 | $grant = new SocialGrant( 34 | $this->app->make(Bridge\UserSocialRepository::class), 35 | $this->app->make(RefreshTokenRepository::class) 36 | ); 37 | $grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn()); 38 | return $grant; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Bridge/UserSocialRepository.php: -------------------------------------------------------------------------------- 1 | 6 | * @copyright Copyright (c) Anand Siddharth 7 | * @license http://mit-license.org/ 8 | * 9 | * @link https://github.com/schedula/laravel-passport-socialite 10 | */ 11 | 12 | namespace Schedula\Laravel\PassportSocialite\Bridge; 13 | 14 | use Schedula\League\OAuth2\Server\Repositories\UserSocialRepositoryInterface; 15 | use League\OAuth2\Server\Entities\ClientEntityInterface; 16 | use Laravel\Passport\Bridge\User; 17 | use Socialite; 18 | use InvalidArgumentException; 19 | use RuntimeException; 20 | use League\OAuth2\Server\Exception\OAuthServerException; 21 | 22 | 23 | class UserSocialRepository implements UserSocialRepositoryInterface { 24 | 25 | /** 26 | * {@inheritdoc} 27 | */ 28 | public function getUserEntityByUserCredentials( 29 | $username, 30 | $password, 31 | $grantType, 32 | ClientEntityInterface $clientEntity 33 | ) { 34 | // no use implemented as UserSocialRepository extends UserRepository Class 35 | return; 36 | } 37 | 38 | /** 39 | * {@inheritdoc} 40 | */ 41 | public function getUserFromSocialProvider($accessToken, $socialProvider, $grantType, ClientEntityInterface $clientEntity){ 42 | try { 43 | $socialite = Socialite::with($socialProvider); 44 | $socialUser = $socialite->userFromToken($accessToken); 45 | 46 | $provider = config('auth.guards.api.provider'); 47 | if (is_null($model = config('auth.providers.'.$provider.'.model'))) { 48 | throw OAuthServerException::serverError('Unable to determine authentication model from configuration.'); 49 | } 50 | if (method_exists($model, 'findForPassportSocialite')) { 51 | $user = $model::findForPassportSocialite($socialProvider, $socialUser->getId()); 52 | if(!$user) { 53 | return; 54 | } 55 | return new User($user->getAuthIdentifier()); 56 | }else{ 57 | throw OAuthServerException::serverError('method "findForPassportSocialite" not implemented in authentication model from configuration.'); 58 | } 59 | } catch (InvalidArgumentException $e) { 60 | throw OAuthServerException::invalidRequest('provider'); 61 | } catch (\Exception $e) { 62 | throw OAuthServerException::serverError($e->getMessage()); 63 | } 64 | 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Laravel Passport Socialite 2 | The missing social authentication plugin (i.e. SocialGrant) for laravel passport. 3 | 4 | ## Description 5 | This package helps integrate social login using laravel's native packages i.e. (passport and socialite). This package allows social login from the providers that is supported in laravel/socialite package. 6 | 7 | ## Getting Started 8 | To get started add the following package to your composer.json file using this command. 9 | 10 | `composer require schedula/laravel-passport-socialite` 11 | 12 | ## Configuration 13 | When composer installs this package successfully, register the `Schedula\Laravel\PassportSocialite\PassportSocialiteServiceProvider::class` in your `config/app.php` configuration file. 14 | 15 | 16 | ```php 17 | 'providers' => [ 18 | // Other service providers... 19 | Schedula\Laravel\PassportSocialite\PassportSocialiteServiceProvider::class, 20 | ], 21 | ``` 22 | 23 | **Note: You need to configure third party social provider keys and secret strings as mentioned in laravel socialite documentation https://laravel.com/docs/5.6/socialite#configuration** 24 | 25 | ## Usage 26 | 27 | ### Step 1 - Setting up the User model 28 | 29 | Implement `UserSocialAccount` on your `User` model and then add method `findForPassportSocialite`. 30 | `findForPassportSocialite` should accept two arguments i.e. `$provider` and `$id` 31 | 32 | **$provider - string - will be the social provider i.e. facebook, google, github etc.** 33 | 34 | **$id - string - is the user id as per social provider for example facebook's user id 1234567890** 35 | 36 | **And the function should find the user which is related to that information and return user object or return null if not found** 37 | 38 | 39 | 40 | Below is how your `User` model should look like after above implementations. 41 | 42 | ```php 43 | namespace App; 44 | 45 | use Schedula\Laravel\PassportSocialite\User\UserSocialAccount; 46 | class User extends Authenticatable implements UserSocialAccount { 47 | 48 | use HasApiTokens, Notifiable; 49 | 50 | /** 51 | * Find user using social provider's id 52 | * 53 | * @param string $provider Provider name as requested from oauth e.g. facebook 54 | * @param string $id User id of social provider 55 | * 56 | * @return User 57 | */ 58 | public static function findForPassportSocialite($provider,$id) { 59 | $account = SocialAccount::where('provider', $provider)->where('provider_user_id', $id)->first(); 60 | if($account) { 61 | if($account->user){ 62 | return $account->user; 63 | } 64 | } 65 | return; 66 | } 67 | } 68 | ``` 69 | **Note: `SocialAccount` here is a laravel model where I am saving provider and provider_user_id and local database user id. Below is the example of `social_accounts` table** 70 | 71 | | id | provider | provider_user_id | user_id | created_at | updated_at | 72 | |----|----------|------------------|---------|-------------------|-------------------| 73 | | 1 | facebook | XXXXXXXXXXXXXX | 1 | XX-XX-XX XX:XX:XX | XX-XX-XX XX:XX:XX | 74 | | 2 | github | XXXXXXXXXXXXXX | 2 | XX-XX-XX XX:XX:XX | XX-XX-XX XX:XX:XX | 75 | | 3 | google | XXXXXXXXXXXXXX | 3 | XX-XX-XX XX:XX:XX | XX-XX-XX XX:XX:XX | 76 | 77 | 78 | ### Step 2 - Getting access token using social provider 79 | 80 | I recommend you to not to request for access token from social grant directly from your app since the logic / concept of social login is you need to create account if it doesn't exists or else login if exists. 81 | 82 | So here in this case we will be making a custom route and a controller that will recieve the Access Token or Authorization Token from your client i.e. Android, iOS etc. application. **Here client fetches access token / authorization token from provider** 83 | 84 | Our route here can be something like this: 85 | 86 | `Route::post('/auth/social/facebook', 'SocialLogin@loginFacebook');` 87 | 88 | And here is how we can write our controller and its method for that : 89 | 90 | ```php 91 | use Illuminate\Http\Request; 92 | use App\Http\Controllers\Controller; 93 | use Route; 94 | class SocialLogin extends Controller { 95 | 96 | public function loginFacebook(Request $request) { 97 | try { 98 | 99 | $facebook = Socialite::driver('facebook')->userFromToken($request->accessToken); 100 | if(!$exist = SocialAccount::where('provider', SocialAccount::SERVICE_FACEBOOK)->where('provider_user_id', $facebook->getId())->first()){ 101 | 102 | // create user account 103 | } 104 | return response()->json($this->issueToken($request, 'facebook', $request->accessToken)); 105 | } 106 | catch(\Exception $e) { 107 | return response()->json([ "error" => $e->getMessage() ]); 108 | } 109 | 110 | } 111 | 112 | public function issueToken($request, $provider, $accessToken) { 113 | 114 | /** 115 | * Here we will request our app to generate access token 116 | * and refresh token for the user using its social identity by providing access token 117 | * and provider name of the provider. (I hope its not confusing) 118 | * and then it goes through social grant and which fetches providers user id then calls 119 | * findForPassportSocialite from your user model if it returns User object then it generates 120 | * oauth tokens or else will throw error message normally like other oauth requests. 121 | */ 122 | $params = [ 123 | 'grant_type' => 'social', 124 | 'client_id' => 'your-client-id', // it should be password grant client 125 | 'client_secret' => 'client-secret', 126 | 'accessToken' => $accessToken, // access token from provider 127 | 'provider' => $provider, // i.e. facebook 128 | ]; 129 | $request->request->add($params); 130 | 131 | $requestToken = Request::create("oauth/token", "POST"); 132 | $response = Route::dispatch($requestToken); 133 | 134 | return json_decode((string) $response->content(), true); 135 | } 136 | } 137 | ``` 138 | 139 | **Note: SocialGrant will only accept access token not authorization token, for example google provides authorization token in android when requested server auth code i.e. offline access, so you need to exchange auth code for an access token. Refer here: https://github.com/google/google-api-php-client** 140 | 141 | **Note: SocialGrant acts similar to PasswordGrant so make sure you use client id and secret of password grant while making oauth request** 142 | 143 | 144 | **That's all folks** 145 | 146 | ## Wait you still here? 147 | 148 | I am working on this cool project called yoheim. It's an all in one collaboration platform to manage and share ssh servers. 149 | **Download now and start using it for free** www.yoheim.com 150 | 151 | 152 | 153 | yoheim log 154 | 155 | 156 | 157 | --------------------------------------------------------------------------------