Jwt token unable to generate - php

I am trying to generate a JWT Token in laravel. I am using Tymon. I am working in laravel 5.8 and I need to copy most of the stuff from 5.4 version.
This is what so far I have tried.
Controller
$payload = (object)array("userid" => $user->userid);
$extra = [
"userid" => $user->userid,
"username" => $user->username,
"useremail" => $user->useremail
];
$return = JWTAuth::fromUser($payload, $extra);
User.php
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
protected $fillable = [
'name', 'email', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
protected $casts = [
'email_verified_at' => 'datetime',
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
return [];
}
}
I am trying this using postman where I am getting this error:
Symfony \ Component \ Debug \ Exception \ FatalThrowableError (E_RECOVERABLE_ERROR)
Argument 1 passed to Tymon\JWTAuth\JWT::fromUser() must be an instance of Tymon\JWTAuth\Contracts\JWTSubject, instance of stdClass given, called in

To Use JWT Auth in Laravel you must follow these steps -
Install in Composer.json via:
composer require tymon/jwt-auth
Add the service provider to the providers array in the config/app.php config
file as follows:
'providers' => [
...
Tymon\JWTAuth\Providers\LaravelServiceProvider::class,
]
Run the following command to publish the package config file:
php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider"
You should now have a config/jwt.php file that allows you to configure the basics of this package.
Generate the secret Key via this command:
php artisan jwt:secret
this should update your .env file with something like:
JWT_SECRET=foobar
Then Update the User model as:
<?php
namespace App;
use Tymon\JWTAuth\Contracts\JWTSubject;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable implements JWTSubject
{
use Notifiable;
// Rest omitted for brevity
/**
* Get the identifier that will be stored in the subject claim of the JWT.
*
* #return mixed
*/
public function getJWTIdentifier()
{
return $this->getKey();
}
/**
* Return a key value array, containing any custom claims to be added to the JWT.
*
* #return array
*/
public function getJWTCustomClaims()
{
return [];
}
}
finally, configure the Auth guard in config/auth.php as:
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
...
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
Then You are ready to go..

As the error message says, you are passing a stdClass instance where JWTSubject instance is expected as the first parameter of the JWTAuth::fromUser method.
Have a look at this issue: github issue
The developers suggest to either pass User model or implementation of Tymon\JWTAuth\Contracts\JWTSubject interface

Related

Laravel Artisan event:generate command throwing a Fatal error

I'm following the official documentation for Laravel 5.7 on the events registration and generation: https://laravel.com/docs/5.7/events#generating-events-and-listeners
I have an EventServiceProvider with the following events defined:
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event handler mappings for the application.
*
* #var array
*/
protected $listen = [
'App\Events\FormBeforeCreate' => [
'App\Listeners\WebhookBeforeCreate',
],
'App\Events\FormAfterCreate' => [
'App\Listeners\NotifyAfterCreate',
'App\Listeners\WebhookAfterCreate',
],
'App\Events\FormBeforeUpdate' => [
'App\Listeners\WebhookBeforeUpdate',
],
'App\Events\FormAfterUpdate' => [
'App\Listeners\NotifyAfterUpdate',
'App\Listeners\WebhookAfterUpdate',
],
'App\Events\FormBeforeDelete' => [
'App\Listeners\WebhookBeforeDelete',
],
'App\Events\FormAfterDelete' => [
'App\Listeners\NotifyAfterDelete',
'App\Listeners\WebhookAfterDelete',
],
'App\Events\FormBeforeSave' => [
'App\Listeners\WebhookBeforeSave',
],
'App\Events\FormAfterSave' => [
'App\Listeners\NotifyAfterSave',
'App\Listeners\WebhookAfterSave',
],
];
/**
* The subscriber classes to register.
*
* #var array
*/
protected $subscribe = [
'App\Listeners\UserEventSubscriber',
];
/**
* Register any other events for your application.
*
* #return void
*/
public function boot()
{
parent::boot();
}
}
The error:
When I run the command php artisan event:generate I get the following error:
PHP Fatal error: Call to a member function listens() on null in /app/vendor/laravel/framework/src/Illuminate/Foundation/Console/EventGenerateCommand.php on line 35
[Symfony\Component\Debug\Exception\FatalErrorException]
Call to a member function listens() on null
According to the doc, it should do this:
This command will generate any events or listeners that are listed in
your EventServiceProvider. Events and listeners that already exist
will be left untouched
I don't understant what I've missed since I didn't find any similar error by searching the web
This is the line that is returning null:
$providers = $this->laravel->getProviders(EventServiceProvider::class);
therefore, there are some problems with your EventServiceProvider... please, try using this:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Event;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* #var array
*/
protected $listen = [
'App\Events\FormBeforeCreate' => [
'App\Listeners\WebhookBeforeCreate',
],
'App\Events\FormAfterCreate' => [
'App\Listeners\NotifyAfterCreate',
'App\Listeners\WebhookAfterCreate',
],
'App\Events\FormBeforeUpdate' => [
'App\Listeners\WebhookBeforeUpdate',
],
'App\Events\FormAfterUpdate' => [
'App\Listeners\NotifyAfterUpdate',
'App\Listeners\WebhookAfterUpdate',
],
'App\Events\FormBeforeDelete' => [
'App\Listeners\WebhookBeforeDelete',
],
'App\Events\FormAfterDelete' => [
'App\Listeners\NotifyAfterDelete',
'App\Listeners\WebhookAfterDelete',
],
'App\Events\FormBeforeSave' => [
'App\Listeners\WebhookBeforeSave',
],
'App\Events\FormAfterSave' => [
'App\Listeners\NotifyAfterSave',
'App\Listeners\WebhookAfterSave',
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
parent::boot();
//
}
}
My bad, it seems like I was really tired yesterday night, Our project runs on Docker, I was running the command outside of the docker instead of inside.
I have no idea why it showed this bug in particular but once I ran the command in the docker all files generated correctly.

Stripe\Exception\InvalidArgumentException The resource ID cannot be null or whitespace. #1266

Cashier Version: 13.5
Laravel Version: 8.63.0
PHP Version: 8.0.1
Database Driver & Version: mysql 10.4
When I try to add a new subscription getting the error "The resource ID cannot be null or whitespace.". while trying to do it with the user model it's working fine. But I need to do it with another custom model AppUser. which is pretty similar to the user model.
In the AppserviceProvder under boot method, I have given
Cashier::useCustomerModel(AppUser::class);
In the AppUser model given Billable and the relation ,
namespace App\Models;
use Carbon\Carbon;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Cashier\Billable;
// Authenticatable trait is required to work as User Model
class AppUser extends Authenticatable
{
use Billable;
use Notifiable;
public function subscriptions()
{
return $this->hasMany(\App\Subscription::class, 'app_user_id')->orderBy('created_at', 'desc');
}
My subscription Model is
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Cashier\Subscription as CashierSubscription;
class Subscription extends CashierSubscription
{
use HasFactory;
public function owner()
{
return $this->belongsTo(AppUser::class);
}
public function items()
{
return $this->hasMany(SubscriptionItem::class);
}
}
and
SubscriptionItem Model is
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Cashier\SubscriptionItem as CachierSubscriptionItem;
class SubscriptionItem extends CachierSubscriptionItem
{
use HasFactory;
public function subscription()
{
return $this->belongsTo(Subscription::class);
}
}
In My Config/ Auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'app_user' => [
'driver' => 'session',
'provider' => 'app_users',
],
],
'providers' => [
'app_users' => [
'driver' => 'eloquent',
'model' => App\Models\AppUser::class,
],
'users' => [
'driver' => 'database',
'table' => 'app_users',
],
],
Finally My controller is ,
config(['cashier.model' => 'App\Models\AppUser']);
$data = $request->all();
$user = AppUser::find($data['user_id']);
$paymentMethod = $request->input('payment_method');
$plan = $request->input('plan');
$plan = $plan ? $plan : 'halfyearly_NZD';
$response = $user->newSubscription('main', $plan)->create($paymentMethod);
After a long day of debugging, I found the issue.
In my app_users table while creating a new customer I just kept the stripe-id filed as blank. It should be either a stripe id or must be set as NULL.
Another important point, stripe_id filed is highly case sensitive so keep it as utf8mb4_ci encoding

Laravel Passport Multiauth

I am working on an API for 2 frontend apps (vue2/mobile). One uses User model and the other uses the Admin model (Laravel is just an API)
I am using Laravel Passport for authenticating users and admins, i successfully provided access token for users but i'm facing some problem with admins
So for i did
1-> created Admin model
<?php
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use HasApiTokens, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password','role',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
2-> created a admins guard which uses passport
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
'admin' => [
'driver' => 'passport',
'provider' => 'admins',
],
],
3-> created Route and Controller for granting access token for admins
Route::post('/oauth/token/admin', [
'uses' => 'Auth\CustomAccessTokenController#issueUserToken'
]);
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use Psr\Http\Message\ServerRequestInterface;
use Laravel\Passport\Http\Controllers\AccessTokenController;
class CustomAccessTokenController extends AccessTokenController
{
/**
* Hooks in before the AccessTokenController issues a token
*
*
* #param ServerRequestInterface $request
* #return mixed
*/
public function issueUserToken(ServerRequestInterface $request)
{
$httpRequest = request();
if ($httpRequest->grant_type == 'password') {
$admin = \App\Admin::where('email', $httpRequest->username)
->where('password', $httpRequest->password)
->first();
//dd($admin);
return $this->issueToken($request);
}
}
}
4-> i tested with Postman
http://localhost:8000/api/oauth/token/admin
client_id:4
client_secret:M4QkLqhPkJ4pGL52429RipassQ3BOjKTJZe3uoWK
grant_type:password
username:admin#gmail.com
password:secret
//i'm getting
{
"error": "invalid_credentials",
"message": "The user credentials were incorrect."
}
//if i use the User model credentials
username:user#gmail.com
password:secret
//i'm getting the access token
{
"token_type": "Bearer",
"expires_in": 31536000,
"access_token": "eyJ0eXAiOiJKV1Qi....",
"refresh_token": "UI354EfJlVdmOhO...."
}
i'm really tired figuring out what went wrong
looking forward for much needed help
thank you

Multi Auth with Laravel 5.4 and Passport

I am trying to setup multi auth with Laravel Passport, but it doesn't seem to support it. I am using the Password Grant to issue tokens which requires me to pass username/password of the user wanting access tokens.
I have 3 auth guards/providers setup, 4 in total.
Users, Vendors, Admins and API
2 of the Auths need passport access, so each user needs to be able to issue tokens. But Passport automatically takes the API auth provider, but I want this to change based on which user is logging in.. If user does then the User provider and if its a vendor then the Vendor provider.
But the way Passport currently only supports only 1 user type, so its defaulting to the API provider.
Is there something better for this? or should I go with roles based authentication instead.
If you still need.
I prefer go with roles, there is an amazing plugin for that: https://github.com/larapacks/authorization
But if you somehow needs that, you will be able to use following the steps bellow.
For multi guards, you will have to overwrite some code.
Instead of loading PassportServiceProvider, you create your own and extends the PassportServiceProvider and overwrites the method makePasswordGrant.
On this method, you will change the Passport UserRepository for your own repository extended. On user repository you must to change the static model config for a dynamic one (I load from request attributes, but you can get from anywhere).
You may have to overwrite something else, but I made a test and works.
Ex:
PassportServiceProvider
namespace App\Providers;
use League\OAuth2\Server\AuthorizationServer;
use League\OAuth2\Server\Grant\PasswordGrant;
use Laravel\Passport\PassportServiceProvider as BasePassportServiceProvider;
use Laravel\Passport\Passport;
class PassportServiceProvider extends BasePassportServiceProvider
{
/**
* Create and configure a Password grant instance.
*
* #return PasswordGrant
*/
protected function makePasswordGrant()
{
$grant = new PasswordGrant(
$this->app->make(\App\Repositories\PassportUserRepository::class),
$this->app->make(\Laravel\Passport\Bridge\RefreshTokenRepository::class)
);
$grant->setRefreshTokenTTL(Passport::refreshTokensExpireIn());
return $grant;
}
}
UserRepository
namespace App\Repositories;
use App;
use Illuminate\Http\Request;
use League\OAuth2\Server\Entities\ClientEntityInterface;
use Laravel\Passport\Bridge\UserRepository;
use Laravel\Passport\Bridge\User;
use RuntimeException;
class PassportUserRepository extends UserRepository
{
/**
* {#inheritdoc}
*/
public function getUserEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity)
{
$guard = App::make(Request::class)->attributes->get('guard') ?: 'api';
$provider = config("auth.guards.{$guard}.provider");
if (is_null($model = config("auth.providers.{$provider}.model"))) {
throw new RuntimeException('Unable to determine user model from configuration.');
}
if (method_exists($model, 'findForPassport')) {
$user = (new $model)->findForPassport($username);
} else {
$user = (new $model)->where('email', $username)->first();
}
if (! $user ) {
return;
} elseif (method_exists($user, 'validateForPassportPasswordGrant')) {
if (! $user->validateForPassportPasswordGrant($password)) {
return;
}
} elseif (! $this->hasher->check($password, $user->password)) {
return;
}
return new User($user->getAuthIdentifier());
}
}
PS: Sorry my bad english.
You have to modify the main library Files.
1) File: vendor\laravel\passport\src\Bridge\UserRepository.php
Find getUserEntityByUserCredentials and Copy the complete method and Paste this method below with name getEntityByUserCredentials. Donot modify the main function because it is used somewhere.
//Add the $provider variable at last or replace this line.
public function getEntityByUserCredentials($username, $password, $grantType, ClientEntityInterface $clientEntity, $provider)
Then, in the new duplicated function, find the below:
$provider = config('auth.guards.api.provider');
and Replace it with:
$provider = config('auth.guards.'.$provider.'.provider');
2) File: vendor\league\oauth2-server\src\Grant\PasswordGrant.php
In the function validateUser add the below code after line no. 88
$provider = $this->getRequestParameter('provider', $request);
if (is_null($provider)) {
throw OAuthServerException::invalidRequest('provider');
}
After adding replace the following code with
$user = $this->userRepository->getEntityByUserCredentials(
$username,
$password,
$this->getIdentifier(),
$client,
$provider
);
Now try this using postman
Add the provider field in your input field like
provider = api_vendors
OR
provider = api_admins
OR
provider = api_users
And so on....
make sure you have added your provider and set the drivers in the config/auth.php
'guards' => [
'api_admins' => [
'driver' => 'passport',
'provider' => 'admins',
],
'api_vendors' => [
'driver' => 'passport',
'provider' => 'vendors',
],
I hope this helps.
I have created a small package for this issue. Here's the link for the complete doc link
But the gist is, whenever a user entity gets logged in, it checks for the guards and providers.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
'customers' => [
'driver' => 'passport',
'provider' => 'customers'
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => 'App\User',
],
/**
* This is the important part. You can create as many providers as you like but right now,
* we just need the customer
*/
'customers' => [
'driver' => 'eloquent',
'model' => 'App\Customer',
],
],
You should have a controller like this:
<?php
namespace App\Http\Controllers\Auth;
use App\Customers\Customer;
use App\Customers\Exceptions\CustomerNotFoundException;
use Illuminate\Database\ModelNotFoundException;
use Laravel\Passport\Http\Controllers\AccessTokenController;
use Laravel\Passport\TokenRepository;
use League\OAuth2\Server\AuthorizationServer;
use Psr\Http\Message\ServerRequestInterface;
use Lcobucci\JWT\Parser as JwtParser;
class CustomerTokenAuthController extends AccessTokenController
{
/**
* The authorization server.
*
* #var \League\OAuth2\Server\AuthorizationServer
*/
protected $server;
/**
* The token repository instance.
*
* #var \Laravel\Passport\TokenRepository
*/
protected $tokens;
/**
* The JWT parser instance.
*
* #var \Lcobucci\JWT\Parser
*/
protected $jwt;
/**
* Create a new controller instance.
*
* #param \League\OAuth2\Server\AuthorizationServer $server
* #param \Laravel\Passport\TokenRepository $tokens
* #param \Lcobucci\JWT\Parser $jwt
*/
public function __construct(AuthorizationServer $server,
TokenRepository $tokens,
JwtParser $jwt)
{
parent::__construct($server, $tokens, $jwt);
}
/**
* Override the default Laravel Passport token generation
*
* #param ServerRequestInterface $request
* #return array
* #throws UserNotFoundException
*/
public function issueToken(ServerRequestInterface $request)
{
$body = (parent::issueToken($request))->getBody()->__toString();
$token = json_decode($body, true);
if (array_key_exists('error', $token)) {
return response()->json([
'error' => $token['error'],
'status_code' => 401
], 401);
}
$data = $request->getParsedBody();
$email = $data['username'];
switch ($data['provider']) {
case 'customers';
try {
$user = Customer::where('email', $email)->firstOrFail();
} catch (ModelNotFoundException $e) {
return response()->json([
'error' => $e->getMessage(),
'status_code' => 401
], 401);
}
break;
default :
try {
$user = User::where('email', $email)->firstOrFail();
} catch (ModelNotFoundException $e) {
return response()->json([
'error' => $e->getMessage(),
'status_code' => 401
], 401);
}
}
return compact('token', 'user');
}
}
and the request should be:
POST /api/oauth/token HTTP/1.1
Host: localhost
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
grant_type=password&username=test%40email.com&password=secret&provider=customers
To check in your controller who is the logged in user, you can do:
auth()->guard('customers')->user()
I have done it in Laravel 7 without any custom code as suggested other answers. I have just changed 3 file as follows
config/auth.php file (My new table name is doctors)
'guards' => [
...
'api' => [
'driver' => 'passport',
'provider' => 'users',
'hash' => false,
],
'api-doctors' => [
'driver' => 'passport',
'provider' => 'doctors',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'doctors' => [
'driver' => 'eloquent',
'model' => App\Doctor::class,
],
],
Revise my Doctor model similarly as User model (App/Doctor.php)
....
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class Doctor extends Authenticatable
{
use HasApiTokens, Notifiable;
Finally define routes using middleware routes/api.php file as follows
//normal middleware which exist already
Route::post('/choose', 'PatientController#appointment')->middleware('auth:api');
//newly created middleware provider (at config/auth.php)
Route::post('/accept', 'Api\DoctorController#allow')->middleware('auth:api-doctors');
Now when you will create new oauth client you may use artisan passport:client --password --provider this command which prompt you in command line for choosing table
before that do not forget to run
php artisan config:cache
php artisan cache:clear
Also you can create user manually in oauth_clients table by replacing provider column value users to doctors
Some hints at reference link
https://laravel.com/docs/7.x/passport#customizing-the-user-provider
We are waiting for Laravel to add this feature to its package but for those who want to add this feature, I suggest using this package
Laravel passport is only working with User as a provider. Even if you fetch token by adding above changes with PasswordGrant & UserRepository, while you go for API call for Post and get requests are not working with changed passport provider other than User.
Better you create multi auth with session driver if must needed as Vendors and Customers. let 'User' model only for passport whose table columns supports admin, API, vendor, etc.
Repo here laravel-multiAuth
if you look for solution to the Passport Multi-Auth API
I recommend you this solution

Laravel Socialite and Office365: InvalidArgumentException in Manager.php line 90: Driver [microsoft] not supported

So I definitely can't wrap my head around this one. I'm following a Laravel 5.2 tutorial here.
http://blog.damirmiladinov.com/laravel/laravel-5.2-socialite-facebook-login.html#.V2gUIrgrJPY
And getting the error listed above in the title. My routes look like this:
Route::get('/', function () {
if(Auth::check()) return view('auth/register');
return view('auth/login');
});
Route::get('/redirect', 'MailAuthController#redirect');
Route::get('/callback', 'MailAuthController#callback');
Controller looks like this:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Socialite;
class MailAuthController extends Controller
{
//
public function redirect()
{
return \Socialite::with('microsoft')->redirect();
}
public function callback()
{
// when microsoft calls with token
}
public function user()
{
}
}
And services.php looks like this:
<?php
return [
/*
|--------------------------------------------------------------------------
| Third Party Services
|--------------------------------------------------------------------------
|
| This file is for storing the credentials for third party services such
| as Stripe, Mailgun, Mandrill, and others. This file provides a sane
| default location for this type of information, allowing packages
| to have a conventional place to find your various credentials.
|
*/
'mailgun' => [
'domain' => env('MAILGUN_DOMAIN'),
'secret' => env('MAILGUN_SECRET'),
],
'mandrill' => [
'secret' => env('MANDRILL_SECRET'),
],
'ses' => [
'key' => env('SES_KEY'),
'secret' => env('SES_SECRET'),
'region' => 'us-east-1',
],
'sparkpost' => [
'secret' => env('SPARKPOST_SECRET'),
],
'stripe' => [
'model' => App\User::class,
'key' => env('STRIPE_KEY'),
'secret' => env('STRIPE_SECRET'),
],
'microsoft' => [
'client_id' => env('MICROSOFT_CLIENT_ID'),
'client_secret' => env('MICROSOFT_CLIENT_SECRET'),
'redirect' => env('http://localhost:8000/callback'),
],
];
And other than that I have no idea where I might be going wrong. Light my way!
I would recommend using the Microsoft Graph provider from the Socialite Providers package.
Pull in the Microsoft-Graph provider via your composer.json file:
"require": {
...
"laravel/socialite": "^2.0",
"socialiteproviders/microsoft-graph": "dev-master"
},
Run composer update.
Next, add the connection credentials to config/services.php:
...
'graph' => [
'client_id' => 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
'client_secret' => 'xxxxxxxxxxxxxxxxxxxxxxx',
'redirect' => 'https://my-app.dev',
],
*Note: if committing config/services.php to a public repo, extract these values to your .env file and reference them via the env helper method;
In config/app.php add the SocialiteProviders/Generators service provider to the providers array:
'providers' => [
...
/*
* Package Service Providers...
*/
Laravel\Socialite\SocialiteServiceProvider::class,
// This is a dependency of the socialiteproviders/microsoft-graph provider, and will be installed with the provider via it's composer.json file
SocialiteProviders\Manager\ServiceProvider::class,
Register the Socialize facade (also in config/app.php):
'aliases' => [
...
'Socialize' => 'Laravel\Socialite\Facades\Socialite',
],
Register an event listener in app/Providers/EventServiceProvider.php:
protected $listen = [
...
'SocialiteProviders\Manager\SocialiteWasCalled' => [
'SocialiteProviders\Graph\GraphExtendSocialite#handle'
],
];
Create your controller to handle the requests:
<?php
namespace App\Http\Controllers\Auth;
use Illuminate\Http\Request;
use Socialize;
class AuthController extends \App\Http\Controllers\Controller
{
/**
* Redirect the user to the Graph authentication page.
*
* #return Response
*/
public function redirectToProvider()
{
return Socialize::with('graph')->redirect();
}
/**
* Obtain the user information from graph.
*
* #return Response
*/
public function handleProviderCallback(Request $request)
{
$user = Socialize::with('graph')->user();
// $user->token;
}
}
Finally add your routes in routes/web.php:
<?php
Route::get('auth/graph', 'Auth\AuthController#redirectToProvider');
Route::get('auth/graph/callback','Auth\AuthController#handleProviderCallback');
If anyone still arrives here with the same error, but using the SocialiteProviders Microsoft provider already:
Check if you have set up the library correctly.
Make sure to install socialiteproviders/microsoft from composer
Add the SocialiteProviders Manager to your config/providers.php: \SocialiteProviders\Manager\ServiceProvider::class
Add the event listener to your app/Providers/EventServiceProvider.php:
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
[SocialiteProviders\Microsoft\MicrosoftExtendSocialite::class, 'handle'],
],
The last step is important, and what caused the error for me, because I didn't understand the event listener is required (and not just an optional way to extend the provider).
So this might seem obvious but both in my case and judging from the info provided in the question, this step is also missing. I changed from the current Microsoft to the Graph and still got the same error, however I then realized this error happens when the Driver is not registered in the service provider. Make sure you are using the same spelling of the service provider in vendor and that you include the Service provider, in my case:
<?php
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* #var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
\SocialiteProviders\Manager\SocialiteWasCalled::class => [
// ... other providers
/*--- I forgot this --->*/\SocialiteProviders\Graph\GraphExtendSocialite::class.'#handle',
],
];
/**
* Register any events for your application.
*
* #return void
*/
public function boot()
{
//
}
/**
* Determine if events and listeners should be automatically discovered.
*
* #return bool
*/
public function shouldDiscoverEvents()
{
return false;
}
}
This added worked with microsoft graph, driver: "graph" from: https://github.com/SocialiteProviders/Microsoft-Graph
I never got to try with the listed driver "Microsoft" on socialiteproviders.com
and as of the time of this writing Graph was removed from that website, however all I care is that it works and it worked as expected!

Categories