Laravel's signedURL generates wrong URL when using api middlware - laravel

I have a front-end running on Nuxt and Laravel as a back-end service. When I generate the signedURL using the Laravel's API middleware - the path includes "api" in the URL, resulting into a page not found exception on the Nuxt side
So, here are the steps to better understand what's happening:
User clicks a button in Nuxt application and sends the ajax request to the Laravel API
API Controller generates the signedURL
$signedUrl = URL::signedRoute('register', ['email' => $this->request->email, 'group_id' => $this->request->group_id], null, false);
Generated URL includes the "api" in the path, which of course, cannot be accessed
http://localhost:3000/api/register?email=ss%40gmail.com&group_id=2&signature=ce4fba05bf5ccae6ea20a6043a47ca11de603238214deda7202d19f2989272cb
Is there a way to get rid of the /api/ from the generated URL? I've tried setting 4th param (absolute) in the method signedRoute to false, but it doesn't help.

The default api routes have prefix 'api' as seen in your RouterProvider:
protected function mapApiRoutes()
{
Route::prefix('api')
...;
}
When you generate the signed URL, for your route 'register' which is using the prefix api , the generated URL will be as expected: www.mydomain.com/api/register?...

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"

Using Sanctum with regular Laravel authentication

I have a simple web app using regular authentication for all of my web routes. There are just a few places in my app where I want to be able to call a few API routes from Javascript. Can I setup Sanctum's SPA authentication to work without doing an SPA-style login?
I have followed the instructions server-side, and on my login page I am doing a CSRF cookie request using the axios library before the user logs-in using the standard routes. But when I try to then hit a Sanctum protected route I just get redirected to the home page.
Is it expected that Sanctum session-based auth should work with a regular app login?
Edit
I located the problem. In EnsureFrontendRequestsAreStateful is this function:
public static function fromFrontend($request)
{
$referer = Str::replaceFirst('https://', '', $request->headers->get('referer'));
$referer = Str::replaceFirst('http://', '', $referer);
return Str::startsWith($referer, config('sanctum.stateful', [])) ||
Str::is(config('sanctum.stateful', []), $referer);
}
$referer is null on my requests, so this function cannot return true. If 'referer' is changed to 'host' it works. Is this acceptable? Does it satisfy the point of the function still, that the "given request is from the first-party application frontend" or are there security implications I haven't considered?
'Referer' works when hitting the API endpoint from Javascript, but when hitting it from Postman or in a browser window the headers non-existence causes a problem. So in simple GET testing it is redirecting to login, but is working fine when called from the Axios library in a Vue component.
'Referer' works in postman too, you need only add header to your request Referer -> {{host}}. host it's postman variable or you can type it like localhost. Sanctum by default checking this referers localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1, but you can specify your own referer by adding variable to env file SANCTUM_STATEFUL_DOMAINS=your-app-domain.com here.

Why does one Route fail and the other work?

I am using Laravel to serve both my website and a stateless API. I use Passport with a token set in the cookie to Authenticate the API, this is handled by Passport.
I make calls to the API using axios within vue.js
I was getting an issue with an API call that was returning Unauthorized, all other requests were fine, by playing around I have arrived at the finding that
this.$axios.get('session/'+this.session+'/posts')
.then(response => { console.log(response.data); });
Route::get('/session/{code}/posts' , 'PostController#posts');
works; whereas
this.$axios.get('session/posts')
.then(response => { console.log(response.data); });
Route::get('/session/posts' , 'PostController#posts');
does not (returns 401 Unauthorized).
In the first example the $code value is simply an obfuscated ID and is not related to authentication, it is a string of characters. Also, session refers to an internal Application object and is not related to the php session at all.
This is in my Routes service provider:
Route::prefix('api')
->middleware('auth:api')
->namespace($this->namespace.'\API')
->group(base_path('routes/api.php'));
This sets a token in a cookie (laravel_token by default), and uses that to authenticate.
Other routes are successfully authenticating through this, when I add the variable to the route, it works!
Can anyone explain to me why the second version gives an Unauthorized response?
It appears to be the auth:api guard that makes this distinction, but I don't know where in the Laravel framework the actual check() code is.
Kindly check if your routes where a part of a prefix that has the auth:guard api activated. whereas you need to send api generated token to gain authorization.

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

Resources