Passport can not generate refresh token - laravel

Can you please help me ?
I want to generate refresh token in passport.
I can generate a refresh token only if I use default hash password from Laravel. What I mean is this situation: I create a new registration (from registration form) and try to call the api in Postman with both email and password.
$http = new Client();
$response = $http->post('http://localhost/passport/public/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => '2',
'client_secret' => '**************',
'username' => $request->email,
'password' => $request->password,
'scope' => ''
],
]);
But the problem is that I don't use hash password which laravel has by
default. I am using another hash password and when I call the API
http://localhost/passport/public/oauth/token in postman it shows this
error :
Client error: `POST http://localhost/passport/public/oauth/token` resulted in a `401 Unauthorized` response: {"error":"invalid_credentials","error_description":"The user credentials were incorrect.","message":"The user credential

You should create a new hashing driver as a standalone class by extending the Illuminate\Hashing\AbstractHasher class and implementing Illuminate\Contracts\Hashing\Hasher interface.
After that you have to register your custom driver in the HashManager class. To do so, in the register method of a service provider put:
// Include the class at the top of your service provider
use Illuminate\Hashing\HashManager;
// Then in the register method
HashManager::extend('driverName', function ($app) {
// Replace the namespace and class with the one you have created in the first step
// Or resolve it from the app container
return new \App\Your\Custom\Hash\Driver();
});
Once you have done that you can set the same driverName you have chosen when you extended the HashManager in the config/hashing.php file, by setting the driver attribute.
In this way you replaced the default bcrypt hashing systemwide and the credential matching should work without any further modification.

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;

How to login with laravel passport in seeder file?

On laravel backend API site with passport I use service for data crud operations
and inside of this service I use Auth::user() to fill creator of data.
Testing this service in POSTMAN I use oauth/token with client_id, client-secret, username, password
parameters and it works ok.
I need to add some init data in seeders using the same service
Looking how oauth/token at docs https://laravel.com/docs/9.x/passport
I added to my seeder:
use Illuminate\Support\Facades\Http;
...
$response = Http::asForm()->post(url('oauth/token'), [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'username',
'password' => 'password',
'scope' => '',
]);
\Log::info($response->json()); // I can see valid response
if(Auth::user()) { // that condition did not true
\Log::info(Auth::user());
}
Which action have I to take to login with valid token?
When I refer Auth::user()->id in service I got error :
Attempt to read property "id" on null
I tried to debug by routes outpout:
.token › Laravel\Passport › AccessTokenController#issueToken
POST oauth/token/refresh ........................................................................................................................ passport.token
file src/Http/Controllers/AccessTokenController.php
but I see only token functionality...
"laravel/framework": "^9.2",
"laravel/passport": "^10.3",
Thanks in advance!
You can use Auth::loginUsingId() for user information that you want get

Generate both access and refresh tokens in Laravel login

Im trying to implement authentication in laravel using passport.
I need to create a New accessToken and refreshToken once the user logs in.
Now, following Laravel's documentation, it can be donde like this:
use Illuminate\Support\Facades\Http;
$response = Http::asForm()->post('http://passport-app.test/oauth/token', [
'grant_type' => 'password',
'client_id' => 'client-id',
'client_secret' => 'client-secret',
'username' => 'taylor#laravel.com',
'password' => 'my-password',
'scope' => '',
]);
return $response->json();
The workaround here would be to make an API endpoint that would basically take the user's credentials and post them with the other required data to the above endpoint.
Is it OK to call a route of my own API from another route or my API?. It feels like it should be a better way to do this. Can someone point me to that way if it exists or if there is a better implementation?
Thanks in advance!
If you are using OpenID-Connect, you should always ask for the openid scope.
To get a refresh token, you also need to ask for the offline_access scope.
Like
'scope' => 'openid offline_access',

Why am I getting an Unauthorized response with the Outlook API with Azure Active Directory?

I'm creating a task that will retrieve the messages in outlook mail with Microsoft Azure Active Directory.
I setup my azure account. Register an app, add certificate then add user to my AD. My signin method returns an access token which means signin is successful and pass the access token to outlook messages API. but the Outlook messages API returns unauthorize.
Here is my scope: email Group.Read.All Mail.Read Mail.Read.Shared Mail.ReadBasic openid profile User.Read User.ReadBasic.All Mail.ReadWrite
I used Laravel HTTP Client to send request. Hope anyone can help me, Im stuck on this problem for week
public function __construct()
{
$this->params = [
'client_id' => env('OAUTH_APP_ID'),
'scope' => env('OAUTH_SCOPES'),
'client_secret' => env('OAUTH_APP_PASSWORD'),
'username' => 'xxxxxxxx#mytenant.onmicrosoft.com',
'password' => 'xxxxxxxx',
'grant_type' => 'password',
'redirectUri' => env('OAUTH_REDIRECT_URI'),
'urlAuthorize' => env('OAUTH_AUTHORITY').env('OAUTH_AUTHORIZE_ENDPOINT'),
'urlAccessToken' => env('OAUTH_AUTHORITY').env('OAUTH_TOKEN_ENDPOINT'),
'urlResourceOwnerDetails' => '',
];
}
public function signin()
{
$url = 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token';
$response = Http::asForm()->post($url, $this->params);
if($response->ok()){
$returnData = $response->json();
$mail_api = 'https://outlook.office.com/api/v2.0/me/messages';
$messagesResponse = Http::withToken($returnData['access_token'])->get($mail_api);
dd($messagesResponse);
}
}
Here is the response of my signin. I used Laravel HTTP client to send request.
And for additinal info in my granted permission
It has mentioned in the document. One of the following permissions is required to call this API:
https://outlook.office.com/mail.read
wl.imap
And the permissions in your issue like Mail.Read, Mail.Read.Shared, Mail.ReadBasic are used for Microsoft Graph API, such as Get message API.

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).

Resources