Laravel - Oauth password grant - laravel

I find it difficult to wrap my head around the password grant authentication process.
What I'm trying to achieve: A mobile device sends the username and the password of a registered user to the API and gets the access token as a response in JSON form.
What I've achieved so far: The API receives the user credentials (username and password) and authenticates the user using Laravel's built-in Auth authentication system.
I know that at this point I should proceed to Oauth authentication. Once the credentials pass the Auth step, I have the user's username, password (specified in the users table) and I can get the client_id and client_secret from the oauth_clients table, but I'm not sure how to accomplish the rest. Do I need to make another POST request? If yes, then how do I do it from the controller?

I am actually implementing this right now. Let me show you some code.
This is my part of my login function:
// this does the process for getting the access token
$oauth = AuthorizationServer::performAccessTokenFlow();
// some hacks
$oauth = (array) $oauth;
// more hacks
$oauth = json_decode($oauth["\0*\0data"], true);
// checks if a token was actually generated
if(!in_array('bearer', $oauth))
{
// returns what was generated if the token is missing
return Responser::error(400, $oauth);
}
You would have to post additional data on your login other than the username and password of the user.
So your post request will contain:
username=the_username
password=the_password
grant_type=password
client_id=the_client_id
client_secret=the_client_secret
note that grant_type=password is constant.
Now you have to check the configurations of the package too found at app/config/packages/lucadegasperi/oauth2-server-laravel/oauth2.php:
You should have the following code:
'password' => array(
'class' => 'League\OAuth2\Server\Grant\Password',
'access_token_ttl' => 604800,
'callback' => function($username, $password){
$credentials = array(
// change this to username if username is the field on your database
'email' => $username,
'password' => $password,
);
$valid = Auth::validate($credentials);
if (!$valid) {
return false;
}
return Auth::getProvider()->retrieveByCredentials($credentials)->id;
}
),
And you are done.
update
the code above that generates the token is inside this function:
// allow user to login with username or email and password
$user_pass = array('username' => $username, 'password' => $password);
$email_pass = array('email' => $username, 'password' => $password);
// check if input is email and use $email_pass combination or else use $user_pass combination
$login = ($isEmail->passes() ? $email_pass : $user_pass);
// try to authenticate username & password
if (Auth::attempt($login))
{
// now you are authenticated here
// get the client id and secret from the database
// maybe use curl or some hacks
// login stuff and token generation
}

This is a bit of an old post, but if you are looking to do this without having multiple post requests, you could always just do something like:
//Get Oauth creds
$apiCreds = OauthClient::where('email', Input::get('email'))->first();
//Provide additional post data for password grant
Input::merge([
'grant_type' => 'password',
'client_id' => $apiCreds->id,
'client_secret' => $apiCreds->secret,
'username' => Input::get('email'),
'password' => Input::get('password'),
'scope' => 'all'
]);
//Login
return AuthorizationServer::performAccessTokenFlow();

Related

Authorization code grant with Socialite setup

I'm trying to implement an Authorization code grant with Socialite. I'm able successfully to receive users in the callback, but struggling to set up the other part of auth. I've created the personal passport client and received the client ID & Secret in oauth_clients. Whenever I use the createToken() I am able to see oauth_access_tokens these tokens with the name of PKCE(which contains the same name as in oauth_client). The $code is taken from the query in the callback, however, the $response in the very end is null, any idea why?
public function callbackGoogle()
{
// Receive the user credentials from social
$googleUser = Socialite::driver('google')->stateless()->user();
// Get the user by email
$user = User::where('email', $googleUser->email)->first();
// Create token
$user->createToken('PKCE')->accessToken;
// Get query parameter code from callback
$code = request()->query()['code'];
// Get client data
$client = DB::table('oauth_clients')->where('name', 'PKCE')->first();
$response = Http::asForm()->post('http://localhost:5000/oauth/token', [
'grant_type' => 'authorization_code',
'client_id' => $client->id,
'client_secret' => $client->secret,
'code' => urldecode($code),
'redirect_uri' => $client->redirect,
]);
// // Receiving null
dd($response->json());
}
You are trying to exchange an access token from google with your own application.
This does not make sense.
With this line:
$googleUser = Socialite::driver('google')->stateless()->user();
You have already exchanged the code from the URL with a token from google.
If you want to get an API token for your API, you already did this with
$user->createToken('PKCE')->accessToken;
You could use
$token = $user->createToken('PKCE')->accessToken;

Laravel passport generate user access and refresh token with only user id

Currently i would like to generate user access and refresh token after registering a user inorder to automatically login a user after registrations
Currently am doing this.
$user = User::create(//user detaisl) //this creates a user
$guzzle = new \GuzzleHttp\Client([
'base_uri' => env("APP_URL"),
'defaults' => [
'exceptions' => false
]
]);
$response = $guzzle->post('/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => env("PASSPORT_CLIENT_ID"),
'client_secret' => env("PASSPORT_CLIENT_SECRET"),
'username' => $user->email,
'password' => $request->input("password"),
],
]);
return json_decode((string) $response->getBody(), true);
The above with guzzle works but i was wondering if there is a simpler way to simply generate access and refresh tokens without need to perform another guzzle http request by simply using the user id after create.
I would like this as guzzle sometimes fails to work especially on localhost during development continously hangs.
Is there another way?
Instead of using a guzzle request, you can call directly the controller method that handles the token route. Generally directly calling another controller method is a bit of a code smell. You could attempt to dive into the code to refactor this out if you wanted, but since you don't "own" the passport code, I wouldn't worry about it.
// Save off the original request object.
$originalRequest = app('request');
// Create a new request object for the token request.
$tokenRequest = \Illuminate\Http\Request::create('/oauth/token', 'POST', [
'grant_type' => 'password',
'client_id' => config('passport.password_client_id'),
'client_secret' => config('passport.password_client_secret'),
'username' => $user->email,
'password' => $request->input("password"),
]);
// Replace the current request with the new token request in the app container.
app()->instance('request', $tokenRequest);
// Call the access token controller method using the app container,
// which will auto inject the new request.
$response = app()->call('\Laravel\Passport\Http\Controllers\AccessTokenController#issueToken');
// Replace the token request in the container with the original request.
app()->instance('request', $originalRequest);
return $response;
A couple notes:
The $user->createToken() method creates personal access tokens, not password grant tokens. Personal access tokens cannot be refreshed.
I converted the env() calls to config() calls. You should avoid using the env() method outside of the config files. As soon as you cache your config, the env() calls will return null (for values only set in the .env file).

Microsoft Graph in a LARAVEL PHP app - oauth2 grant method 'password'

i'am using a LARAVEL PHP application which is trying to get a token from Microsoft GRAPH API.
Acutally, i can easily get a token by using the an OAuth2 Authorisation CODE grant method.
here is the way to do it : https://github.com/microsoftgraph/microsoft-graph-docs/blob/master/concepts/php.md
But using this method is redirecting the browser to a Microsoft authentication web page, and i don't want this. I would like a transparent method without any browser redirection.
Here are all the Oauth2 grant méthods to get a token :
https://alexbilbie.com/guide-to-oauth-2-grants
So i want to get a token by using "Resource owner credentials grant". Here is my code :
$provider = new \League\OAuth2\Client\Provider\GenericProvider([
'clientId' => 'b9e6844b-b20c-4eef-bbff-fa052c1c0f94',
'clientSecret' => '1A8yUUcMaD5Zdv1dgwqy3SR',
'redirectUri' => 'https://my-website-url/oauth',
'urlAuthorize' => 'https://login.microsoftonline.com/common/oauth2/v2.0/authorize',
'urlAccessToken' => 'https://login.microsoftonline.com/common/oauth2/v2.0/token',
'urlResourceOwnerDetails' => '',
'scopes' => 'openid email profile' // Admin restricted scopes : Directory.Read Directory.ReadWrite Groups.Read.All
]);
$accessToken = $provider->getAccessToken('password',[
'username' => 'myaccount#assystem.com',
'password' => 'xxxxx'
]);
But i got the following error :
(1/1) IdentityProviderException
invalid_grant
in GenericProvider.php (line 217)
Any help?
After getting an error exception, i know why i got this error :
try {
// Try to get an access token using the resource owner password credentials grant.
$accessToken = $provider->getAccessToken('password', [
'username' => 'myapp#assystem.com',
'password' => 'mypassword'
]);
} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
// Failed to get the access token
throw $e;
}
'error_description' => 'AADSTS70000: The grant is not supported by this API version ...(Microsoft Graph API)

Laravel 5.1: How to login using both username or email fields

There is an option available to login using the username or email fields at a time. But I would to login to site using both fields, username OR email,
means: if user input value is matched with username column or email column, then login to the system.
laravel 5.1 having trait AuthenticatesUsers contains this code. which only checks for single column.
$credentials = $this->getCredentials($request);
if (Auth::attempt($credentials, $request->has('remember'))) {
return $this->handleUserWasAuthenticated($request, $throttles);
}
Kindly guide me, login attempt for both column (email or username)
Assuming that you know how to validate the form field, just have username validation as well in your validation rules
Then in your controller validate the login like
if (Auth::attempt(['username' => $request->username, 'password' => $request->password])){
//suceess
}
elseif (Auth::attempt(['email' => $request->email, 'password' => $request->password])){
//logged in using email
}
else{
echo fail
}
Have a look at this thread as well

Using Sentry 2, what is the difference between authenticate() and login()?

Using Cartalys Sentry 2, and I can't seem to find any documentation on the difference between the authenticate() and login() methods, nor when to use one versus the other. Any guidance appreciated.
The difference is that authenticate will receive an array of credentials:
// Login credentials
$credentials = array(
'email' => 'john.doe#example.com',
'password' => 'password',
);
// Authenticate the user
$user = Sentry::authenticate($credentials, false);
And the login method receives an $user object
// Find the user using the user id
$user = Sentry::findUserById(1);
// Log the user in
Sentry::login($user, false);

Resources