How to authenticate API requests in Laravel? - 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 :)

Related

Laravel Jetstream/Sanctum API authentication

I have been working with Laravel since version 5.X up to version 8.X but always use it for backend API (never used blade template), and always pair it with VueJS on the front-end using JWT authentication (also never messed with any other authentication method).
Now with Laravel 9 and Vue 3, Im trying to use native Laravel Jetstream that uses SANCTUM and Vue+Inertia JS, and I'm quite lost with the authentication process. with JWT method, once the user succesfully login on the browser, all api request to Laravel will be authenticated using Authoraziation header. but this seems a different case with Sanctum.
After deploying and installing Jetstream and completed all the set-up. I created a user and loggedin with that user details. and I notice few things, there is a default API route
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
when I tried to directly access my.domain/api/user I notice it was redirected to GET /login
then redirected again to GET /dashboard
I then created a test api route using below
Route::get('test', function( Request $req) {
dd( [
'test' => $req->all(),
'user' => auth()->user(),
'request' => $req
] );
});
and I notice this request is not authenticated even when the cookies is present on the request as Im when I'm alraedy logged-in on the same browser, the auth()->user() is null.
I tried adding auth:sanctum middleware
Route::middleware('auth:sanctum')->get('test', function( Request $req) {
dd( [
'test' => $req->all(),
'user' => auth()->user(),
'request' => $req
] );
});
but having sanctum middle behave the same as the api/user where if i open api/test directly on the browser, it gets redirected to GET /login then redirected again to GET /dashboard and I'm quite lost at this point. I tried reading the docs and it says I have to do a separate authentication for this that would issue an API token and I was thinking I might better be going back with using JWT auth as it seems a lot easier to deal with.
So my question is; How can I authenticate an API end-point without having to redirect it to /login then /dashboard if the user is already logged in on my application using default sanctum authentication.
My goal is just to simply create /api/test that will be automatically authenticated if user already loggedin on the same browser and return the data I set on its return value and not doing any redirects.
Appreciate any help
I have got the same issue with laravel8
Jetstream and inertia vue3.
Am looking for the solution since 3 days posting messages on discord, searching on YouTube and more but nothing.
When i make an api call from your SPA to laravel, i got UNAUTHENTICATED response.
on postman you need put
headers
Accept = application/json
this tells your application know how works with Json
and go stop redirect to "Login"

Issue with POST requests with Laravel Sanctum and Postman

I have a problem with Sanctum and Postman that's related to this post: SPA Authentication Issues with Sanctum and Postman
I followed everything from the Laravel docs about Sanctum and configured it correctly. Then I followed this tutorial: https://blog.codecourse.com/laravel-sanctum-airlock-with-postman/
Everything is working except for POST requests. When I do login, it works. But then I have a collection without the pre-request Script and when I do a GET request to for example /user, it will return the logged in user.
But when I change the method to POST in Laravel and in Postman, I'll get a CSRF token mismatch error.
Does anybody knows what I have to do, to make POST requests working?
Route::middleware('auth:sanctum')->post('/user', function (Request $request) {
return $request->user();
});
I've been using sanctum in one of my e-commerce APIs and I've also followed the same tutorial you've linked in the question. It's hard to tell what's the actual problem in your case but it seems like that you're not sending the X-XSRF-TOKEN header in your POST requests.
The last paragraph in the above-mentioned tutorial, the writer shows how to hit the /logout route which is a POST route.
Remove this function in the controller
public function __construct()
{
$this->middleware('auth');
}
Or change it to
public function __construct()
{
$this->middleware('auth:sanctum');
}
Also, check your RouteServiceProvider and change your API route to
Route::prefix('api/v1')
->middleware('auth:sanctum')
->namespace($this->namespace)
->group(base_path('routes/api.php'));
csrf_token is used to validate forms having method POST in laravel and token is created dynamically,
two thing you can do
First thing if you are writing api's you need to use https://<base_url>/api
and routes in routes/api.php, there you donot need csrf_token but make sure to use proper api authentication
Second just disable csrf token for those routes until you are testing on postman, once you successfully tested enable again, its provide security
disable like this
<?php namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
protected $except = [
'submitMyForm/*',
];
}

How to make laravel passport auth redirect in json response?

I am trying to create API with laravel passport authentication now it is very easy to make API with laravel passport. I am using personal access token to create access token for API users. As my client and server are both one, but when token not provided in the API it redirect to login page create by laravel auth scaffold php artisan make:auth, I want to return json response with message "Token not provided."
https://laravel.com/docs/5.4/passport#personal-access-tokens
I am using auth:api in routes.
How to pass json response for API if token not provided?
I also encountered this same issue. To solve that redirection, you have to pass an extra parameter into the header of the request:
Accept application/json
Now, it will return JSON response instead of redirection to the login page.
So now with an invalid request, it will return JSON response like:
{"error":"Unauthenticated."}
But there is no easy way to customize the passport responses. I'm searching some standard way, but didn't get any yet.
I also encountered this same issue. To solve that redirection, you have to pass header of the request of json response. for that i made decision to make middleware as below
public function handle($request, Closure $next)
{
$request->headers->set('Accept', 'application/json');
return $next($request);
}
the above middleware will force the header to add json response, group the api collection as below
Route::group(['middleware' => 'json.response'], function () {
//your routes here
});

Laravel 5.3 and VueJS 2 Authenticating

Im using Laravels default auth to lock down some paths in the routes/api.php file.
Route::get('/projects', 'ProjectController#index')->middleware('auth:api');
I log the user in via a PHP form (not via a http request via Vue).
This creates the session and when I submit a HTTP request via Vue I can see that the header includes the Cookie and X-CSRF-Token however I keep getting a 401 {"error":"Unauthenticated."}
In my config/auth I have api driver set as 'token' (have tried changing this to 'session' but that did work :/)
From my understanding and what I have read online I should be able to use the default Laravel auth functionality to accomplish API calls from Vue HTTP requests.
this.$http.get('/api/projects')
.then(response => {
this.projects = response.body;
})
.catch (err => {
console.log(err);
});
I've read about methods of authenticating by generating an JWT token and storing that in local storage when the user logs in. Is this the method I should use or should I be able to accomplish it with the default Laravel Auth middleware?
Hope my questions make sense, any help/advice would be appreciated.
The auth:api middleware doesn't use cookies, it uses api_token param, which can be passed via get or Bearer <token> header. Just use web middleware.
I suppose you need to access the same route in two ways - for API users and for browser users. So why don't you create two routes for one action?
// api group with /api prefix
Route::get('/projects', 'ProjectController#index')->middleware('auth:api');
// web group
Route::get('/projects', 'ProjectController#index')->middleware('web');

Blacklisting JWT tokens

For my API i'm using this package tymondesigns/jwt-auth with Laravel.
Security is very important! Tokens will be blacklisted after every request with a new token in the response. While doing some tests using both middlewares jwt.auth and jwt.refresh on the same route I get mixed results. Sometimes it works OK, sometimes I get a 401 unauthorized and have to login again.
I'm using the jtw.auth middleware so I can make use of Auth::user() in my app.
$api->group(['middleware' => ['jwt.auth', 'jwt.refresh']], function ($api)
{
// Protected routes here
});
Does someone have a working example for this?

Resources