Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom user provider in laravel using OAuth2

I want to use an external OAuth2 server under my control to authenticate users for my Laravel 5.2 application. As client library I want to use the package league/oauth2-client As far as I understood need to implement a custom user provider but I'm uncertain about the big picture of all required steps.

The idea is that the user provides the credentials to my Laravel application, with other words the client credentials method is used. Then the bearer-token and the refresh-token is stored on the client side. Every time a client makes a request, the token must be validated by the OAuth server. The OAuth server also provides some basic user information like email and name. So in my application there must be some kind of link between the local user and the OAuth user. This is accomplished with a simple table like

+-------------------+
|       Users       |
+-------------------+
| id      | int(10) |
| oauthId | int(10) |
+---------+---------+

First I followed this guide at laravel.io to create a basic provider skeleton. But at this point I have several questions:

  1. Is the method retrieveById supposed to return any user from the OAuth service or only the users which is the issuer of the request allowed to see?

  2. My OAuth server already has permission checking for each user. If retrieveById is supposed to return any existing user, is my permission check on the OAuth server worthless? This would be a flaw in my architecture.

  3. Some methods must return an implementation of the \Illuminate\Contracts\Auth\Authenticatable interface. Where do I have to implement this? Is this supposed to be the representation of the user which is trying to authenticate? If this should represent a user in my model I have the problem that I don't know the return value for getAuthPassword since this information is on my OAuth server. How can I solve this?

As you can see I have problems to understand how things working together in the whole authentication process. Your help is very appreciated.

like image 360
Noir Avatar asked Feb 23 '16 10:02

Noir


1 Answers

The idea is that the user provides the credentials to my Laravel application, with other words the client credentials method is used.

You should forward the user to your oauth server using authorization code grant

So

  1. The authorization code grant will use the user who is logged in on the oauth server.
  2. You can return the permissions for the user with the retrieveById call
  3. You can put some bogus fill in stuff for the functions that you don't use.

Heres my example,

I used a custom laravel/socialite provider to help with client routing and stuff. The league/oauth2-client should be pretty similar.

The first login redirect looks like

class LoginController extends Controller
{ 
    public function login(Request $request)
    {
        return Socialite::driver('custom-oauth')
            ->scopes(['read-permissions read-name read-email etc'])
            ->redirect();
    }
}

I changed the User model getAuthIdentifier() to be the access_token returned from the authorization code grant. For example

class User implements Authenticatable
{
    public function getAuthIdentifier()
    {
        return $this->token;
    }
}

My login callback looks like this sort of.

class LoginController extends Controller
{ 
    public function callback(Request $request)
    {
        /** @var \App\User $user */
        $user = Socialite::driver('custom-oauth')->user();

        Auth::login($user, true);

        return redirect()->home();
    }
}

Laravel's SessionGuard will store that access_token and your custom user provider should retrieveById back to the oauth server using the access_token to get the user information

And then my custom user provider's retrieveById looks like. Which basically hits the oauth server and requests for the current users information. $identifier = access_token

class CustomUserProvider implements UserProvider
{
    public function retrieveById($identifier)
    {
        try {
            return Socialite::driver('custom-oauth')->userFromToken($identifier);
        } catch (AuthenticationException $e) {
            return null;
        }
    }
}

I hope that helps

like image 137
fh-jashmore Avatar answered Oct 17 '22 13:10

fh-jashmore