How I make phpunit auth tests for laravel/passport? - laravel

I make backend API with laravel 9 (based on laravel/passport 10.3) and
I init app with command :
php artisan passport:install
which generates personal access client and client secret code
I use these codes in login request and recieve Bearer Token, which is used in all datas raeding/updating data with request.
Now I make phpunit tests for these requests and wonder in which wat these register/login requests must be tested as
usuallyin tests controllers I use
$this->actingAs($user, 'api');
Where $user is created with factory...
How that can be implemented ? Please link to example...
Thanks!

Well, you can use :
Passport::actingAs($user)
and usually we don't test third party code, so don't bother testing passport authentication routes, it's already well tested
but if you really want to do that, you can for example with $this->postJson
$this->postJson('api/oauth/token', [
'username' => 'username',
'password' => Str::random(),
'client_id' => 'client_id',
'client_secret' => 'secret',
'grant_type' => 'password',
'scope' => '*',
])->assertStatus(400)->assertJson([
'error' => 'invalid_grant',
]);

Related

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',

401 Unauthorized when creating Password Grant Tokens with laravel passport

I have created an api with passport and want to use password grant tokens because it is more of application to application interactions. But i get below error when i try to access it.
GuzzleHttp\Exception\ClientException
Client error: `POST http://127.0.0.1:8000/oauth/token` resulted in a `401 Unauthorized` response: {"error":"invalid_client","error_description":"Client authentication failed","message":"Client authentication failed"}
my route
Route::get('/get_token_by_password', function (Request $request) {
$http = new GuzzleHttp\Client;
$response = $http->post('http://192.168.0.103:8000/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 13,
'client_secret' => 'f37AwQGsVMiZDVu786KiRdbpn4MXYSBWCvqNcqiC',
'username' => 'developer#ymail.com',
'password' => '123456789',
'scope' => '*',
],
]);
return json_decode((string) $response->getBody(), true);
})->name('get_token_by_password');
What might I be doing wrong?
Also, how do I use postman to get the token?
How do i get a link to be used in other applications that want to consume my api
The request seems correct. Check if you have correct keys and client. After, check in DB the new value of client_secret.
php artisan passport:keys
php artisan passport:client --password
Your client id and/or client secret is not correct, since the error is "invalid_client".

Conception, separate Laravel Passport in resource and authorization server

Ok, i've a small question of application conception. I want to distinct the ressource and the authorization server with laravel passport.
I've an OAuth2 server and a classic laravel app with stateless authentification system homemade.
I've an SPA with Vue.js which send login request to an REST interface to the front laravel app.
This app called GuzzleClient to send an oauth password grant-type request to get a token.
public function login(Request $request, Client $client)
{
$url = config('app.auth.server') .'/oauth/token';
$response = $client->post($url, [
'form_params' => [
'grant_type' => 'password',
'username' => $request->name,
'password' => $request->password,
'client_id' => config('auth.oauth.password.client-id'),
'client_secret' => config('auth.oauth.password.client-secret'),
]
]);
if ($response->getStatusCode() !== Response::HTTP_OK) {
return http_response_code($response->getStatusCode());
}
return response()->json($response->getBody()->getContent(), Response::HTTP_OK);
}
But, if i want to protect an API route, i cannot use the auth:api guard provided by passport.
2 solutions.
Create middleware in front app which call a custom route created in authorization server (laravel passport) to send bearer access_token (sent from javascript) and verify it's validity by the OAuth server.
Get the secret key used by passport for jwt and let the resource server verify itself the token validity. (using custom guard)
The second solution is probably better. But what do you think ? Do you have any idea or best practices ?
Thx for reading.

Laravel passport 500 internal server error when using subdomain

Using laravel passport on my local machine and domain http://myapp.test, I have no problem.
When I push the code to my server on my main domain https://myapp.com, again no problem.
However, I have a sudomain used for my live test (pre-production) before to push to the main domain in production. If I use https://dev.myapp.com, then I get a 500 internal server error.
Any idea how to fix it?
This is the guzzle call I'm doing:
$http = new GuzzleHttp\Client;
$response = $http->post('https://dev.myapp.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'client_id',
'client_secret' => 'client_secret_key',
'username' => 'john#example.com',
'password' => '123456',
'scope' => '',
],
]);
return $response;
If I change the url to my local or production website (changing the passport key and making sure the same user exists), it works properly.
My bad. Just forgot to run that command on the server for that specific domain as specified in the documentation. This command generates the encryption keys Passport needs in order to generate access token.
php artisan passport:keys

Resources