Laravel - Jetstream - Routing authentication api/web - laravel

what i got:
created a new jetstream project (inertia) and Features::api() enabled in jetstream.php config,
web.php:
Route::middleware(['auth:sanctum', 'verified'])->get('/testweb', function () {
return "test web called";
})->name('testweb');
api.php:
Route::get('/testapi', function(){
return 'api called';
})->middleware('auth:sanctum');
also i created a test API token
now when I call /testweb in the browser and I am logged in I get "test web called"
when I am logged out and call it I get redirected to login view
when I make the API request WITH the token
I get the expected result "api called"
BUT
when I don't add a token to the request
I don't get a 401 or so but I get a 200 with an "empty" view (with livewire i see it is the loginview, so i think with inertia it is the loginview too)
what is the cause o that? do i have to handle it myself? if yes, where and how??
additional note:
I made the API request with POSTMAN, does it differ if I do not set the header as Accept: application/json?

When the request is made with that head included
Accept: application/json
then the Authenticate Middleware will know what to do and decide
if it will redirect it or
just send back a 401 response.

Related

Laravel Sanctum CSRF Token Mismatch using Thunder Cilent (Testing API)

CSRF Token Mismatch when using Thunder Cilent to test Laravel Sanctum API. Works fine on app, just not when testing API outside app.
Trying to test API with Laravel Sanctum with Thunder Cilent (Think Postman but VSCode extension). However, despite setting the xsrf-token and Cookie, I'm always getting CSRF token mismatch.
Note logging on works fine in the app, it's only the api testing with thundercilent that's failing.
Getting the CSRF Token
GET http://localhost:8000/sanctum/csrf-cookie
Response Cookies
xsrf-token: eyJpdiI6ImN6Q3JLVEQrYnhXVXhyVWFQWC9YQlE9PSIsInZhbHVlIjoia2F2aTNjNDU2cTZURHRSSTN5Ny9ETnFJMGZoN0I2dmZ3bTA0UEZ6UjhzdCtCRjRPam9OSW5TWVkzYzAvMTQ0ZEp6b2JvYVdhRWg2TGsrejlkcnYzTGY3eGNFcTRGN253dUUxZjE3YXJBSFlVUHk4aGM5RmVYRWF6UFY2ZGRnYUEiLCJtYWMiOiI4OWU3OGI3MzQ3ZTdiNTNiZDQ2Yjg0ZDE3YWNiYmVhNDQ1NTI0MmI3MTY1NjdlZGI5ZGJlZDJlN2Q5NTc0ZjRhIiwidGFnIjoiIn0%3D
laravel_session: eyJpdiI6IjV6VTV4di9IMXNST1ZvNVh0K1pZelE9PSIsInZhbHVlIjoiTSsycEVWdjJ1VTc4dU81TVNJWTJ4aTRHOE81WTVHVW1OeU55OEt3cVU3bHc5N090dEdPQy9yZGJsamhOaDUzaFZmZVp0Z2FTeGp4UWJyVFVmSDdnVytTNS9SZTF5c0daak9EZ1I1V0w3aWpjTnVESWtIRmR2QzNGZ1VqWlZHZ2oiLCJtYWMiOiI0Mzg4NGI4MTc5MGQ1MDE1NTUxY2VmNGRmNGFkNjUyYmI1MjUwMTJiODQ4NmY4M2E5OTRlZGRlNTM3NjAzNTg1IiwidGFnIjoiIn0%3D
Logging in
POST http://localhost:8000/login
Body: {
"email": "example#example.com",
"password": "password"
}
Raw Headers:
User-Agent: Thunder Client (https://www.thunderclient.com)
Accept: application/json
Referer: http://localhost:3000
xsrf-token: eyJpdiI6ImN6Q3JLVEQrYnhXVXhyVWFQWC9YQlE9PSIsInZhbHVlIjoia2F2aTNjNDU2cTZURHRSSTN5Ny9ETnFJMGZoN0I2dmZ3bTA0UEZ6UjhzdCtCRjRPam9OSW5TWVkzYzAvMTQ0ZEp6b2JvYVdhRWg2TGsrejlkcnYzTGY3eGNFcTRGN253dUUxZjE3YXJBSFlVUHk4aGM5RmVYRWF6UFY2ZGRnYUEiLCJtYWMiOiI4OWU3OGI3MzQ3ZTdiNTNiZDQ2Yjg0ZDE3YWNiYmVhNDQ1NTI0MmI3MTY1NjdlZGI5ZGJlZDJlN2Q5NTc0ZjRhIiwidGFnIjoiIn0%3D
Cookie: XSRF-TOKEN=eyJpdiI6ImN6Q3JLVEQrYnhXVXhyVWFQWC9YQlE9PSIsInZhbHVlIjoia2F2aTNjNDU2cTZURHRSSTN5Ny9ETnFJMGZoN0I2dmZ3bTA0UEZ6UjhzdCtCRjRPam9OSW5TWVkzYzAvMTQ0ZEp6b2JvYVdhRWg2TGsrejlkcnYzTGY3eGNFcTRGN253dUUxZjE3YXJBSFlVUHk4aGM5RmVYRWF6UFY2ZGRnYUEiLCJtYWMiOiI4OWU3OGI3MzQ3ZTdiNTNiZDQ2Yjg0ZDE3YWNiYmVhNDQ1NTI0MmI3MTY1NjdlZGI5ZGJlZDJlN2Q5NTc0ZjRhIiwidGFnIjoiIn0;laravel_session=eyJpdiI6IjV6VTV4di9IMXNST1ZvNVh0K1pZelE9PSIsInZhbHVlIjoiTSsycEVWdjJ1VTc4dU81TVNJWTJ4aTRHOE81WTVHVW1OeU55OEt3cVU3bHc5N090dEdPQy9yZGJsamhOaDUzaFZmZVp0Z2FTeGp4UWJyVFVmSDdnVytTNS9SZTF5c0daak9EZ1I1V0w3aWpjTnVESWtIRmR2QzNGZ1VqWlZHZ2oiLCJtYWMiOiI0Mzg4NGI4MTc5MGQ1MDE1NTUxY2VmNGRmNGFkNjUyYmI1MjUwMTJiODQ4NmY4M2E5OTRlZGRlNTM3NjAzNTg1IiwidGFnIjoiIn0%3D;
I copied how this SO Postman example, but it's not working at all. Thunder Cilent doesn't have pre-run scripts so I can't add cookies that way.
Open thunder client, switch to Env and create an environment.
Click on the options button of your collection and choose settings.
Add a test to your collection by navigating to the Tests tab, then select Set Env Variable, set query to cookie.xsrf-token and value to {{XSRF-TOKEN}}
In the Headers tab, add an header named X-XSRF-TOKEN with value {{XSRF-TOKEN | urlDecode}}.
Create a request to /sanctum/csrf-cookie to refresh CSRF Token if it expires
This should fix CSRF Token.
Consult docs for more information: https://github.com/rangav/thunder-client-support
Decided just to use token based auth for API testing instead. Much easier then messing around with CSRF cookies.
Notes for my future self.
When testing the Token based auth, you need to set the accept to application/json otherwise it won't work.
If using collections, don't delete the Accept header in the request, just untick the box. Otherwise the request would override the collection header with something else and not work.

Laravel PUT Request fails : Parse Error: The response has a duplicate "Content-Length" header

Context
Using Postman I send a PUT HTTP request to my Laravel API.
Expected behavor
Postman should show "test" as a response.
Actual behavior
Postman shows the error "Parse Error: The response has a duplicate "Content-Length" header" as a response.
The route
I have defined in api.php the following route:
Route::put('/test', function(Request $request) {
return 'test';
})->name('test');
This route exists: indeed, php artisan route:list returns the following...
PUT | api/test | test | Closure | api
The request
In Postman I have defined the following request (the URL is in the shape of: https://<laravel site>/api/test):
What I've tried to do
According to the Laravel docs, _method = PUT should be sent when a HTML form pointing to a PUT route is sent with POST because it's incompatible with PUT. Normally here, since I use JSON, it's not the case. But even though it could be useless, I've put it, in case I was wrong.
Moreover I've explicitly specified application/json as value for Content-Type and Accept. Also I've specified XMLHttpRequest for make the server know it's an XHRequest.
Finally, there is the CSRF token and the Sanctum token (Bearer Token). I don't know if their values are correct but thanks to other requests not shown here, I know I'm authenticated using Fortify so normally the Sanctum token value may not be used (because of the standard authentication cookie session is defined by Fortify) ; for the CSRF token maybe it's the same.
Question
Why doesn't Laravel simply show "test"?
Clues
NGinx configuration could be the root cause of this problem. Digging deeper...
Just because I can't see the url. Do you have '/api/test'?

Laravel Passport throwing MethodNotAllowedHttpException exception when I try to access my routes via Insomnia REST API

This has happened way too often. I've cleared my local database by running php artisan migrate:fresh and after that, php artisan passport:install --force. For some obscure reason, I'm having this infernal error
MethodNotAllowedHttpException
when I try to access my auth:api routes only, since registration and login work.
These are my routes:
Route::middleware('auth:api')->group(function () {
Route::get('me', 'Api\UserController#details');
Route::get('profile/{username}', 'Api\UserController#getUsername');
Route::post('profile/{username}/trust', 'Api\TrustController#trust');
});
Route::post('register', 'Api\UserController#register')->name('register');
Route::post('login', 'Api\UserController#login')->name('login');
I am absolutely sure I am sending a GET request.
I know that this happens when I am not properly logged in, in other words, giving a correct token to the API, which is not the case now because I have logged in normally, and pasted the token in the header as usual.
What else? Before I refreshed my database it was working. After the refresh, this has started. Any ideas?
When you are sending this request laravel thinks that you are sending a web request instead of api request.
In order for laravel to know that its a api request set the headers:
Content-Type : application/json
Accept: application/json
On your postman request. Since based the 1 flag on your header I cann see that your headers are not set correctly.

How to use Separate Passport api for Api and Web

There are web and api route files. Web Routes are guarded by auth and the unauthenticated users are getting redirected to login page. But my requirement is in api route file. Unauthenticated api routes should get a custom json response instead of redirection to login page.
I am new to passport feature. And I cannot change the Web routes because its made by some other developer.
When a laravel request is not authorized (aka 'unauthenticated api routes') laravel throws the same exception regardless of it being a web or api route.
However, when the exception is handled/rendered by the application the response is determined by $request->expectsJson(), if its true it returns it as json, if not it will act as if it is a web route.
The above function checks multiple function, and returns true if any number of these is correct:
header X-Requested-With === XMLHttpRequest
header Content-Type contains application/json
header Content-Type contains a wildcard (*/*)
header Accept contains application/json
Ensure that your api request matches any of the above described headers, and in that case should return the authentication error as json.
To enforce that api routes always throw json authentication errors you could do any of these:
override the request header in a service provider if the route is determined to be an api route. (do not try this in middleware, it might not work)
override the exception handler in a same manner as described above
and of course other scenarios are also possible
I updated render method of app/Exception/Handler.php method to as follows and it worked.
{
if($exception instanceof \Illuminate\Auth\AuthenticationException && $request->is('api/v*'))
{
return Response(['success'=>-1,'statuscode'=>401,'msg'=>'Sorry, your account has been logged in from another device.'],401);
}
return parent::render($request, $exception);
}

Swagger/Swashbuckle redirects to request url

I use WebAPI 2 and setup Swashbuckle there.
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "medEbridge2.API");
}).EnableSwaggerUi(c =>{
c.InjectJavaScript(thisAssembly, "UHG.mb2.WebApi.SwaggerExtensions.onComplete.js"); });
Then in javascript, I overwrite api_key with my bearer
window.swaggerUi.api.clientAuthorizations.add('oauth2', apiKeyAuth);
So, now when I press "Try it out!" swagger
Sends requests and received OK response (checked with Fiddler)
Redirects me to request url https://mb2-api-local.uhg.com.au/fhir/valueset/authoritytype/$expand
So now I have open empty page
I did not do Oauth, but I have overridden swagger api_key with my token. But there I used custom HTML instead of customJS. Where you can configure your keys and token.
You can get swaggerUI HTML from GitHub and modify it as required.
Can you try it using
c.CustomAsset("index", thisAssembly, "yourHTMLHere.html");
and override keys there

Resources