narodel's avatar

Authenticate users based on Microsoft OAuth login

Hi there,

Very new to laravel(and PHP in general), so sorry if this is a stupid question... I have successfully implemented OAuth login via Microsoft using this tutorial: https://docs.microsoft.com/en-us/graph/tutorials/php?tutorial-step=1

However, I now want to set per page permissions using the "Spatie" package. I can't get this to work though, because the spatie documentation assumes the users are in your database, but they are not. How can I do either one of the following two options?:

  1. Whenever a user logs in using OAuth, create that user in the database as well, and see the user as authenticated if exists.
  2. Somehow see the OAuth logged on user as authenticated and use spatie this way. (I get back info since my name and e-mail is displayed, see microsoft tutorial)
  3. Perhaps there is a better option I didn't think about?

I only want users to have to log on once, so adding a second log on screen to add the users to the database isn't an option.

I've spent a lot of hours on this, with pretty much 0 progress. Any help would be greatly appreciated. Thanks!

0 likes
8 replies
m7vm7v's avatar
m7vm7v
Best Answer
Level 51

If you keep reading the documentation you can reach https://docs.microsoft.com/en-us/graph/tutorials/php?tutorial-step=3 where you can see the functionality for creating a token

try {
  // Make the token request
  $accessToken = $oauthClient->getAccessToken('authorization_code', [
    'code' => $authCode
  ]);

  $graph = new Graph();
  $graph->setAccessToken($accessToken->getToken());

  $user = $graph->createRequest('GET', '/me')
    ->setReturnType(Model\User::class)
    ->execute();

  // HERE YOU CAN SAVE THE USER IN THE DB + LOGIN WITH LARAVEL

  $tokenCache = new TokenCache();
  $tokenCache->storeTokens($accessToken, $user);

  return redirect('/');
}

as part of it you have an instance of the $user ... this is the step where you can call User::create(...) then auth()->login(); then I'd say storing the data to the session will be not needed as you can have it in the user instance but you can still use the same workflow from this documentation.

1 like
narodel's avatar

Thanks for your reply, really appreciate it.

I am very bad at this currently, so could you point me in the right direction with this? For User::create() to work I need to make a new model right (as seen in https://laravel.com/docs/7.x/eloquent) ?

You don't have to provide any code. If you could just list the steps I need to take to get this to work, I will try to figure the rest out on my own, so I learn from it.

One last thing, if do the following I can see the info I get from Microsoft:

dd($user);

How do I access this info when I want to create the user, would the following work?

$newuser = User::create([
    'name' => $user->displayName,
    'mail' => $user->mail,
]);

$newuser->save();

Thanks for your time!

m7vm7v's avatar

Yes, thats what you need. The User model is already created for you to use at app\User.php. Open the database so you can check your fields. It will look something like this in the end -

...
$newUser = User::create([
    'name' => $user->displayName,
    'email' => $user->mail,
]);

auth()->login($newUser);
...
1 like
narodel's avatar

To my own suprise I got this to work editing the code a little bit (still need to remove the password requirement since this won't be passed):

$newUser = User::create([
      'name' => $user->getdisplayName(),
      'email' => $user->getmail(),
      'password' => 'test',
 ]);
 auth()->login($newUser);

However, one last thing; How do I check if the user already exists, and log him/her in if that is the case? Would this work:

if (User::where('email', '=', Input::get($user->getmail()))->exists()) {
    auth()->login();
}
m7vm7v's avatar

It depends on what point would you like to check that. You have some handy helpers such as auth()->check().

Generally do not trust the user's input like your example does. In the example with the token creation you could have something like

$user = App\User::firstOrCreate(
    ['email' => $user->getmail()],
    ['name' => $user->getdisplayName(), 'passport' => 'secret']
);

auth()->login($user);

Can you please make sure if you find someones reply as an answer to your question then please mark it as a best reply.

1 like
narodel's avatar

Thanks for all the help! Very last question: what does 'passport' => 'secret' do in your last bit of code?

m7vm7v's avatar

My bad, should've been password.

normunds.pauders's avatar

Thank about this question and answers, but I cant get it work. I have install php make:auth. Then I add this: https://docs.microsoft.com/en-us/graph/tutorials/php?tutorial-step=3 Next step i read this article and add this code:

                $user = $graph->createRequest('GET', '/me')
                    ->setReturnType(Model\User::class)
                    ->execute();

                // HERE YOU CAN SAVE THE USER IN THE DB + LOGIN WITH LARAVEL

                //https://stackoverflow.com/questions/38268137/laravel-5-2-split-string-first-name-last-name
                $split = explode(" ", $user->getDisplayName());
                $firstname = array_shift($split);
                $lastname  = implode(" ", $split);



                $user = User::firstOrCreate([
                    'email' => $user->getmail()
                ], [
                    'surname' => $lastname,
                    'name' => $firstname,
                    'password' => 'secret'
                ]);
             auth()->login($user);
             //   dd($user);

But now all the time I get this error: Call to undefined method App\User::getDisplayName(). I add this

use App\User;

In AuthController, but it didnt work.

Can you help please with this error. I understand that if user is created then he redircet to home view? I was planing this use with default laravel autenfication (make:auth).

p.s. This looks like my route (web.php) file:

Route::get('/', function () {
    return view('welcome');
});


Route::get('/signin', 'AuthController@signin');
Route::get('/callback', 'AuthController@callback');
Route::get('/signout', 'AuthController@signout');

Auth::routes();
Route::get('/home', 'HomeController@index')->name('home');

Add these erros I get:

(1/1) BadMethodCallException
Call to undefined method App\User::getDisplayName()

in ForwardsCalls.php line 50
at Model::throwBadMethodCallException('getDisplayName')
in ForwardsCalls.php line 36
at Model->forwardCallTo(object(Builder), 'getDisplayName', array())
in Model.php line 1618
at Model->__call('getDisplayName', array())
in TokenCache.php line 12
at TokenCache->storeTokens(object(AccessToken), object(User))
in AuthController.php line 106
at AuthController->callback(object(Request))
at call_user_func_array(array(object(AuthController), 'callback'), array(object(Request)))
in Controller.php line 54
at Controller->callAction('callback', array(object(Request)))
in ControllerDispatcher.php line 45
at ControllerDispatcher->dispatch(object(Route), object(AuthController), 'callback')
in Route.php line 219
at Route->runController()
in Route.php line 176
at Route->run()
in Router.php line 680

Please or to participate in this conversation.