Auth::check() for client credential workflow with Passport - laravel

I have a Laravel app where some routes are protected with the 'client' middleware from Laravel Passport (Example from the docs):
Route::get('/orders', function (Request $request) {
...
})->middleware('client');
When I need to explicitly check for the success of authentication in my code, I normally do this with:
\Illuminate\Support\Facades\Auth::check();
However, this function appears to always return false with the client credentials workflow. I understand that e.g. Auth::user() does not make sense in this context but Auth::check() should be well-defined in this situation.
Question: Is there an alternative to Auth::check() for the client credentials workflow or am I missing something?

You need to pass the Access Token in header first, after doing so you should be able to check auth like this:
Auth::guard('api')->check()

Related

Laravel Gates, how to use them in the API route?

I'm defining my Gates for my API service in AuthServiceProvider (following the Laravel docs https://laravel.com/docs/7.x/authorization#gates):
Gate::define('view-users', function ($user) {
return $user->hasAccess(['view-users'])
or $user->inRole(['admin', 'operator']);
});
Here is my route:
Route::group(['namespace' => 'Api', 'middleware' => ['auth:api']], function () {
Route::get('/users', 'UserController#listing')->name('user.listing')->middleware(['can:view-users']);
});
How can I find the get the user from the Route API file to use in the Gate?
But I don't exactly understand where this $user is coming from. In my request I am sending an Authorization Bearer token. Should I be using this within my gate to fetch the correct user from the DB? How does Laravel know who $user is?
The $user is the current logged in user. You do not need to provide the additional $user, Or pass the user in.
So if your app currently has a login user, that will be the one. If there is no login user the gate will return false which is protecting your resources.
You'll notice from the documentation that Laravel provides the User for you in a Gate.
It says (emphasis mine):
Gates are Closures that determine if a user is authorized to perform a given action and are typically defined in the App\Providers\AuthServiceProvider class using the Gate facade. Gates always receive a user instance as their first argument.
As Andy Song has pointed out in the comments, Laravel will resolve the User via Auth. If there is no user (not logged in, or no authentication), then, per the docs:
By default, all gates and policies automatically return false if the incoming HTTP request was not initiated by an authenticated user.
If you want to trace how your user gets authenticated, your code snippet defines this middleware:
'middleware' => ['auth:api']
This uses the auth middleware, with api as a parameter. Your middleware is defined in app/Http/Kernel.php, and assuming you're using stock Laravel, it will then go on to authenticate your user, prior to your gate check taking place.
Laravel doesn't know who the $user is. You need to pass it when you use the Gate. If you pass Auth::user() as a first argument of the Gate you are using, the code you wrote will work. In other cases, you will need to fetch the user from the Database with any given input.

Laravel authentication lifecycle

I'm trying to understand how an authentication request is handled by laravel in order to be able to write my own authentication method that allows me to check data from multiple tables before authenticating (basically there are some columns that I need to check to understand if a user is able to login).
I'm actually quietly confused about the relation between guards, middleware, provider and driver.
Can someone please explain me the lifecycle of a login request?
Thank you
EDIT: i'm working with laravel 5.7, standard Auth scaffolding that is available using make:auth
To make a custom authentication follow this steps
1.go to routes/web.php and make a get route to handle login view and post login route to handle login logic
Route::get('login','LoginController#show')
Route::post('login','LoginController#login')
2. Make a controller called LoginController
php artisan make:controller LoginController
4.inside LoginController make a function called login to handle login logic like this
public function login(){
$input = $this->validate(request(),['username'=>'required','password'=>'required']);
$model = CustomUsersModel::where('username',$input['username'])
->where('password',bcrypt($input['password']))->first();
if($model){
//user exist and valid login information
auth()->login($model);//login user via model
//now user loggedin
}
//handle wrong login information
}

Dingo/Api and JWT auth

I'm looking for the way to implement auth with JWT and Dingo/Api. I've added JWT package to my project. Added 'jwt' => 'Dingo\Api\Auth\Provider\JWT', into my api.php auth part.
And also added into my BaseController
public function __construct()
{
$this->middleware('api.auth');
}
How do I check if the user has permission (by role) using FormRequest? It has an authorize method, however I'm not sure how to get my user.
Since I'm using JWT the token is sent in the headers.
One way to do it is to adding the role validation to the middleware.
You can try adding this custom validation to the part where it verifies the JWT the user gave as that is the part where you can determine who is the user that owns the token.
You can use the Auth Facade to retrieve the currently authenticated user:
$user = \Auth::user()
For authorization you can use policies, see https://laravel.com/docs/5.6/authorization
Once enabled you can check for a users ability in your authorize method(s), e.g.
public function authorize() {
$user = \Auth::user();
return $user->can("do-something");
}
But there are multiple possibilities how to perform authorization checks, read the docs mentioned above for more details.

How to authenticate API requests in Laravel?

I am currently building some sort of posts based web application using Laravel 5(.4). I have decided to load asynchronously the comment section for each post(and refresh it periodically). After some research I have decided to write a small integrated REST API (using the api routes of Laravel) that should answer to the requests made through AJAX.
However, I am facing the problem if authenticating the incoming requests. Take for example a request to post some comment. How exactly would you recommend to do that?
If you are making AJAX requests from browser and you are signed in then you don't need to use Laravel Passport tokens.
You can define certain routes which will be using web,auth middleware on requests like webapi/comments/get like this.
Route::group(['middleware' => ['web','auth]], function () {
Route::get('webapi/comments/get', 'CommentsController#get');
}
And use Auth Facade as you do in web request i.e Auth::check(), Auth::user() etc. and return the data in JSON like this.
class CommentsController extends Controller
{
public function get(Request $request)
{
if($request->acceptsJson()){
$data = array();
// add data
return response()->json([
"data"=> $data,
"status" => true
]);
}else{
return abort(404);
}
}
}
You can also send Accept header in AJAX request as application/json and in controller check if request $request->acceptsJson() and make your decision to show content when url is loaded from browser address bar or requested as AJAX.
Laravel Passport token are useful where there is no session and cookies are managed.
hope this helps :)
"Passport includes an authentication guard that will validate access tokens on incoming requests. Once you have configured the api guard to use the passport driver, you only need to specify the auth:api middleware on any routes that require a valid access token" - from the Laraven Documentation.
Apparently I have to configure passport, and after that configure the auth:api middleware to use the passport driver. Correct me if I'm wrong, please :)

Laravel 5.3 Ajax Login Customize Credentials

I am able to login via Ajax in Laravel 5.3
This is easily accomplished by making a post request to the login route with the proper parameters.
However, for my application, I am designing two ways for a user to be logged in - via the traditional email/password combination that Laravel already supports, and via an access code that would be distributed and allow the possessor of said code to login without an email/password combination. There is no "registration" in my app, there is just different levels of authentication.
Anyway, in /vendor/laravel/framework/src/Illuminate/Foundation/Auth I am editing the AuthenticatesUsers.php and understand that this function specifically handles the login attempts:
protected function attemptLogin(Request $request)
{
return $this->guard()->attempt(
$this->credentials($request), $request->has('remember')
);
}
My question is, how can I change the success of attempt() based on the content of the request?
In other words, if someone is sending an ajax access code it shouldn't be tested against an email/password combination, as it would obviously fail. Similarly, if they are sending an ajax with email/password parameters, it shouldn't be tested against the list of available access codes.
Am I on the right track? Where in Laravel can I go to make the Auth::attempt() contingent on request parameters?
I will not advice to edit a framework file.
You should rather write a middleware to handle identification of the type of authentication user is requesting for, before sending it to the controller. In your middleware,
public function handle($request, Closure $next)
{
// check if the request has access_code
$request->attributes->add(['using_access_code' => $request->has('access_code')]);
return $next($request);
}
And in your controller, you can check for positive test on this request parameter that we newly added (you can of course do this inside controller directly, but I personally like middleware to handle this because there are chances that you may want to add more functionality)
In your controller, if using_access_code is false, proceed with attempt() login, else, retrieve the user using access_code and manually authenticate the user using Auth::login($user). Let me know if you are unclear.

Resources