codewiser / socialiteprovider
Zenit OAuth2 Provider for Laravel Socialite
Requires
- php: ^7.4 || ^8.0
- ext-json: *
- laravel/framework: >=10.0
- laravel/sanctum: >=3.0
- league/oauth2-client: ^2.7
- socialiteproviders/manager: ~4.0
Requires (Dev)
- phpunit/phpunit: ^10.0
README
composer require codewiser/socialiteprovider
Installation & Basic Usage
Please see the Base Installation Guide, then follow the provider specific instructions below.
Add configuration to config/services.php
'zenit' => [ 'base_uri' => env('ZENIT_SERVER'), 'client_id' => env('ZENIT_CLIENT_ID'), 'client_secret' => env('ZENIT_CLIENT_SECRET'), 'redirect' => env('ZENIT_REDIRECT_URI'), // optional attributes (with default values): 'auth_endpoint' => 'auth', 'token_endpoint' => 'oauth/token', 'user_endpoint' => 'api/user', 'token_introspect_endpoint' => 'token_info', 'client_manage_endpoint' => 'oauth/client', ],
Add provider event listener
Configure the package's listener to listen for SocialiteWasCalled
events.
Add the event to your listen[]
array in app/Providers/EventServiceProvider
.
See the Base Installation Guide for
detailed instructions.
protected $listen = [ \SocialiteProviders\Manager\SocialiteWasCalled::class => [ // ... other providers \SocialiteProviders\Zenit\ZenitExtendSocialite::class, ], ];
Usage
You should now be able to use the provider like you would regularly use Socialite (assuming you have the facade installed):
return Socialite::driver('zenit')->redirect();
Returned User fields
id
nickname
name
email
avatar
Access Token
Access Token is now an object, not just a string.
$user = Socialite::driver('zenit')->user(); $token = $user->token; // \League\OAuth2\Client\Token\AccessToken
Error Response
Package provides response error handling compliant to rfc6749.
try { $user = Socialite::driver('zenit')->user(); } catch (OAuth2Exception $e) { return match ($e->getError()) { // Show response to the user 'access_denied', 'server_error', 'temporarily_unavailable' => redirect() ->to(route('login')) ->with('error', $e->getMessage()), // Silently 'interaction_required' => redirect()->to('/'), // Unrecoverable default => throw $e, }; }
Token Introspection
Package provides token introspection compliant to rfc7662.
use \Illuminate\Http\Request; use \SocialiteProviders\Zenit\rfc7662\IntrospectedTokenInterface; public function api(Request $request) { /** @var IntrospectedTokenInterface $token */ $token = Socialite::driver('zenit') ->introspectToken($request->bearerToken()); if ($token->isActive()) { // } }
Get user using existing token
$user = Socialite::driver('zenit') ->userFromToken($request->bearerToken());
Refreshing Token
$token = Socialite::driver('zenit') ->refreshToken($refresh_token);
Client Token
$token = Socialite::driver('zenit') ->grantClientCredentials('scope-1 scope-2');
Token by username and password
$token = Socialite::driver('zenit') ->grantPassword($username, $password, 'scope-1 scope-2');
Token by custom grant
$token = Socialite::driver('zenit') ->grant('custom_grant', [/* any request params */]);
Manage client
Package provides remote client management compliant to rfc7592. It allows to read OAuth client properties...
use SocialiteProviders\Zenit\ClientConfiguration; $config = new ClientConfiguration( Socialite::driver('zenit')->getClientConfiguration() );
...and update it programmatically:
use SocialiteProviders\Zenit\ClientConfiguration; use SocialiteProviders\Zenit\ClientScope; $config = new ClientConfiguration(); $config->name = 'name'; $config->namespace = 'namespace'; $config->redirect_uri = 'https://example.com'; $scope = new ClientScope(); $scope->name = 'name'; $scope->description = 'description'; $scope->aud = ['personal']; $scope->realm = 'public'; $config->scopes->add($scope) // etc Socialite::driver('zenit')->updateClientConfiguration($config->toUpdateArray());
Token authorization
Register auth driver, that would authorize incoming requests with bearer tokens, issued by oauth server.
use SocialiteProviders\Zenit\Auth\TokenAuthorization; use Laravel\Socialite\Facades\Socialite; use Illuminate\Support\Facades\Auth; Auth::viaRequest('access_token', new TokenAuthorization( socialiteProvider: 'zenit', userProvider: Auth::createUserProvider(config('auth.guards.api.provider')), cache: cache()->driver() ));
Next, register driver for the guard:
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], 'api' => [ 'driver' => 'access_token', 'provider' => 'users', ] ]
Usually, access_token associated with a user, but
client_credentials
access_token is not. Such access_token associated
with oauth client only.
So, the Authenticatable
may be
as App\User
,
as SocialiteProviders\Zenit\Auth\Client
class.
We expect that User
implements Laravel\Sanctum\Contracts\HasApiTokens
,
as Client
implements it too. If so, the Authenticatable
will be injected
with incoming token (aka current access token).
Current access token implements Laravel\Sanctum\Contracts\HasAbilities
interface, so you may inspect its scopes and abilities.
use Illuminate\Http\Request; use Laravel\Sanctum\Contracts\HasApiTokens; public function index(Request $request) { $authenticated = $request->user(); // Check scope $authenticated->currentAccessToken()->can('my-scope'); }
As current access token looks and behave like Sanctum
token, we may
protect routes with Laravel\Sanctum\Http\Middleware\CheckAbilities
or
Laravel\Sanctum\Http\Middleware\CheckForAnyAbility
middlewares, as
described in
official documentation.
Route::get('/orders', function () { // Token has both "check-status" and "place-orders" abilities... })->middleware(['auth:api', 'abilities:check-status,place-orders']);