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',
Related
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
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',
]);
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).
i have a multi-tenant app and i am trying to add Facebook linking in it i have tried the process using laravel socialite but i have a problem that when i use dynamic redirect url like so
return Socialite::driver('facebook')
->with([
'redirect_uri' => "https://" . $dynamichost . "/social/facebook/callback",
])
->redirect();
or this way
return Socialite::driver('facebook')->redirectUrl('https://' . $dynamichost .
'/social/facebook/callback')->redirect();
facebook returns error url mismatch. Note i also have set a value for redirect_url in .env
then i have services values like this
'facebook' => [
'client_id' => env('FACEBOOK_APP_ID'),
'client_secret' => env('FACEBOOK_APP_SECRET'),
'redirect' => env('CALLBACK_URL_FACEBOOK'),
'default_graph_ve`enter code here`rsion' => 'v3.3',
],
my guess is socialite somehow set the redirect url equal to the value which is coming from .env and when i change it dynamically it still thinks that url will be like the value of .env and i have tested this scenario the request get success response if keep the redirect url static.
Any suggestions how can i overcome this. thanks.
if you want to use custom redirect-uri dynamic :
use Socialite;
use Laravel\Socialite\Two\FacebookProvider;
$socialite = Socialite::buildProvider(
FacebookProvider::class, [
'client_id' => 'your_id',
'client_secret' => 'your_secret',
'redirect' => 'url',
'default_graph_version' => 'v3.3', //not sure if this needed as far as i know, in socialite the version is defined
]
)->redirect();
well it was dumb mistake i had to match the redirect url in callback handling method. its fixed now thanks.
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