Conception, separate Laravel Passport in resource and authorization server - laravel

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.

Related

How I make phpunit auth tests for laravel/passport?

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',
]);

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

use laravel passport for make token and send request with axios

i want make panel . . for frontend i use vuejs ...
I have 3 ways
1 -- i use laravel default auth with make:auth and use
enter code here
\Laravel\Passport\Http\Middleware\CreateFreshApiToken::class,
enter code here
middleware for Make Auto Token and send my axios request ,,
2 - i use laravel default auth with make:auth and make login.vue and send login request with axios for laravel default auth service and in authenticated method in AuthenticatesUsers class
use this code and return token for login.vue ..
enter code here
$http = new Client();
$response = $http->post(config('app.url') . '/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => config('services.passport.client_id'),
'client_secret' => config('services.passport.client_secret'),
'username' => $request->username,
'password' => $request->password,
],
]);
enter code here
after get token in login vue set this in vuex and set in header and send axiox request with token
3 -- i just use laravel passport and send user name and password for passport , make token and return token .. and send request with axios and token ..
Which way is safer?
Which is the best choice?
if i use 2 or 3 save token in localstorage or cookie? tanks

API login from android app using laravel 5.3 passport

For two days I am digging google but could not find the starting thread for my problem, now I am out of option. Please help me with some direction/howTo
I have a web application running built with laravel 5.3, I have installed passport as described here . if I go /home its showing perfectly.
Now I have to make an android app from which
An already existing user of web app can login
get all the task list of that user TaskModel (ons_tasks(id, title, description))
routes related only
in web.php
Auth::routes();
in api.php
Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:api');
Route::group(['middleware' => ['auth:api']], function () {
Route::get('/test', function (Request $request) {
return response()->json(['name' => 'test']);
});
Route::get('/task/list', function (Request $request) {
$list = \App\Model\TaskModel::all();
return response()->json($list);
});
});
To login : if I send post request /login with email & password get the TokenMismatchException error but Where do I obtain a token for
android app in mobile? Do I need the Auth::routes() in the api too?
if then what else Do I need to just login and get a token so later I
can send it for getting the task lists.
Secondly,
If I go to /api/test it redirects me to /home page without
showing any error !!!
Thanks in advance.
To authenticate with your Passport-enabled API
You'll need to use the Password Grant Client in this situation, see this section of Passport's documentation.
Once you've generated a Password Grant Client, using:
php artisan passport:client --password
You will need to request an access token from your application, and send it with your subsequent requests, in order to access the protected auth:api middleware routes.
To get an access token, send a request to your app's /oauth/token route (this is a PHP implementation obviously, ensure you are correctly formatting below request in your Java implementation):
$http = new GuzzleHttp\Client;
$response = $http->post('http://your-app.com/oauth/token', [
'form_params' => [
'grant_type' => 'password',
'client_id' => '<client id returned from the artisan command above>',
' client_secret' => '<secret returned from artisan command above>',
'username' => 'taylor#laravel.com',
'password' => 'my-password',
'scope' => '',
],
]);
return json_decode((string) $response->getBody(), true);
Ensure you add the client_secret and client_id that was returned from the artisan call above, and ensure username and password references a valid user in your database.
If everything is fine here, you should receive an access_token and refresh_token in the response. The access_token is what you need to authenticate using the auth:api guard. To correctly pass this back to your api, you will need to send your subsequent requests with the headers Authorization: Bearer <your accessToken> and Accept: application/json
For example, to access your "test" route:
$response = $client->request('GET', '/api/test', [
'headers' => [
'Accept' => 'application/json',
'Authorization' => 'Bearer '. <accessToken from /oauth/token call>,
],
]);
If you've set these correctly, you should see a JSON response with the array you have specified.
Why is /api/test redirecting me with no error?
You are requesting a route with the auth:api middleware. This will redirect you as you have not specified the correct headers as described above, this is expected behavior.
Hope this helps.

Resources