Why Laravel `middleware('auth:sanctum')` causes 302 issues? - php

I'm trying to get some data from a Laravel API endpoint but I'm getting some very unusual redirect issues and disallowed methods. I will start by showing my javascript code first, then laravel code second.
First, I ran the following javascript code from the developer console of various websites with various top level domains to ensure I can authenticate without any CORS issues:
fetch("https://api.example.com/login",{
method:"post",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify({"email":"test#test.com","password":"test","remember_me":true})
})
.then(r=>r.json())
.then(r=>console.log(r));
// I get a perfect response like this:
{ data: { message: "Yay! Success!", token: "86|S5isCezrsYb1aToAsI3xZb9Ot9Tu7WU8XeOK1q8C" } }
I then take the token and do another get request from my developer console to the /auth/user end point to get my account details like this
fetch("https://api.example.com/auth/user",{
method:"get",
header:{
Authorization:"Bearer 86|S5isCezrsYb1aToAsI3xZb9Ot9Tu7WU8XeOK1q8C",
Accept: "application/json"
},
})
.then(r=>r.json())
.then(r=>console.log(r));
But something completely weird happens. The https://api.example.com/auth/user gives my developer console a 302 response. Then my developer console automatically (without any intervention from me) makes a GET request to https://api.example.com/login. The https://api.example.com/login then gives a 405 response with this message:
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: The GET method is not supported for this route. Supported methods: POST. in file /var/www/api/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php on line 117
#0 /var/www/api/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php(103): Illuminate\Routing\AbstractRouteCollection->methodNotAllowed(Array, 'GET')
#1 /var/www/api/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php(40): Illuminate\Routing\AbstractRouteCollection->getRouteForMethods(Object(Illuminate\Http\Request), Array)
#2 /var/www/api/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php(162):
...etc...
This is my Laravel code:
~/routes/api.php
Route::post('login', ['as' => 'login', 'uses' => 'Api\UserController#login']); //->middleware(['throttle:6,1']);
Route::middleware('auth:sanctum')->get('/auth/user', function (Request $request) {
return $request->user();
});
~/app/Http/Controller/Api/UserController.php
public function login(LoginRequest $request)
{
$user = User::where('email', $request->email)->first();
if (!$user || !Hash::check($request->password, $user->password)) {
throw ValidationException::withMessages([
'message' => ['The provided credentials are incorrect.'],
]);
exit;
} else if (!$user->active) {
throw ValidationException::withMessages([
'message' => ['Your account approval is pending.'],
]);
exit;
}
return response()->json([
'data' => [
"message" => __("Yay! Success!"),
"token" => $user->createToken('authentication-token')->plainTextToken,
],
]);
}
So my question is, why can't the /auth/user endpoint return information about the user I'm logged in with?
EDIT
I tried php artisan route:clear which had no effect.
I tried changing the route from /auth/user to authuser in both the route/api.php and my fetch() call, and suddenly I have a CORS error. Is the auth/ path a reserved word of some kind?
Oh...i guess this config/cors.php also matters:
'paths' => [
'api/*',
'auth/user',
'login',
'logout',
'sanctum/csrf-cookie',
],
UPDATE
I created a few more routes like this:
~/routes/api.php
Route::middleware(['auth:sanctum'])->group(function () {
Route::resource('blah1', Api\Blah1::class)->only(['index', 'store', 'show', 'update', 'destroy']);
Route::resource('blah2', Api\Blah1::class)->only(['index', 'store', 'show', 'update', 'destroy']);
// .. etc...
Route::get('/auth/user', function (Request $request) {
return $request->user();
});
});
~/config/cors.php
'paths' => [
'api/*',
'auth/user',
'blah*',
'login',
'logout',
'sanctum/csrf-cookie',
],
I noticed that POSTMAN has ZERO problems getting information from auth/user and blah1, blah2, etc...
However, it is just the browser that will always give a 302 and cause a redirect when pinging auth/user, blah1, blah2, etc.... FireFox shows me these responses:
If I remove the middleware('auth:sanctum'), then I no longer get the 405 and 302 issue. However, $request->user() becomes null without the middleware('auth:sanctum'). I need a way to get the user information from Authorization: Bearer <token>

Related

405 Method not allowed with Guzzle POST request in PHP

I'm stuck since several hours on a the consumption of a locale API (which I created) with PHP and Guzzle on a laravel project (8.7).
I've created deux differents laravel projects on the same local server. One is providing some API routes and the second one consume it.
On the first project (which providing APIs) I've created several routes to create, read, update and delete datas from my database.
To access this API routes we need to first consume an API route called "login". This one handle the creation of a token according to a given couple email/password.
This token is needed to call all the others API routes.
The /api/login API is a POST request with email and password datas.
/api/login route declaration : (I would like to specify that this route is into the api.php file into my laravel project so the corresponding url is : http://xxx.xxx.x.xxx/site/public/api/login)
Route::post('login',[AdminController::class,'index']);
Index method for /api/login :
function index(Request $request)
{
if(!($request->ip() == "xxx.xxx.x.xxx")) {
Log::alert('Ip ' . $request->ip() . ' a tenté de se connecter à l\'Api');
return response([
'message' => ['Authentification failed']
], 403);
}
$admin = Admin::where('email', $request->email)->first();
if (!$admin || !Hash::check($request->password, $admin->password)) {
return response([
'message' => ['Email-password couple is incorrect']
], 403);
}
$token = $admin->createToken('my-app-token')->plainTextToken;
$response = [
'admin' => $admin,
'token' => $token
];
return response($response, 201);
}
In my second project I'm using Guzzle to consome my APIs.
/articles route declaration : (http://xxx.xxx.x.xxx/backoffice/public/api/login)
Route::prefix('articles')->group(function () {
Route::any('/', [ArticlesController::class, 'index'])->name('articles-index');
});
Index method for /articles :
public function index() {
$client = new \GuzzleHttp\Client();
$request = $client->request('POST', 'http://xxx.xxx.x.xxx/site/public/api/login/', [
'headers' => ['Content-Type' => 'application/x-www-form-urlencoded'],
'form_params' => [
'email' => 'test#gmail.com',
'password' => 'dAvG454aquysla4'
],
'debug' => true,
]);
$response = $request->getBody()->getContents();
return view('articles.index', [
]);
}
I'm getting this error :
GuzzleHttp\Exception\ClientException Client error: 'POST http://xxx.xxx.x.xxx/site/public/api/login/' resulted in a '405 Method Not Allowed' response: <!doctype html> <html class="theme-light"> <!-- Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: Th (truncated...)
I don't understand where is my mistake...
The /api/login is correctly define in POST http method and works perfectly with Insomnia.
Does anyone have an idea or will be able to help me using Guzzle? It's the first time I'm using it.
I'm used to consume API with fetch (ajax) in JS.
Thanks ;)

Is it possible to create an custom response in laravel on methodNotAllowed

I've been searching a solution in Google but couldn't find anything similar tho this.
I'm basically trying to create a custom response upon the error methodNotAllowed in the framework Laravel 8.x
So I have this route:
Route::get('/test', function(Request $request){
return response([
'status' => 200,
'data' => 'Test'
]);
});
On requesting GET:/api/test I'm getting the expected response:
{
"status": 200,
"data": "Test"
}
But when requesting POST:/api/test or any other method it obviously throws an error 405 Method Not Allowed because I haven't setup any router for this.
Is there a "cleen way" to change the error response from 405 Method Not Allowed to
{
"status": 405,
"data": "Method Not Allowed"
}
By a "cleen way" I mean not creating aditional 100 routes just for catching the right method.
The Solution was adding the custom Response to App\Exceptions\Handler by doing this:
Add this to the top:
use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException;
And add the custom response to the method register:
public function register()
{
$this->renderable(function (MethodNotAllowedHttpException $e, $request) {
return response()->json([
'status' => 405,
'message' => 'Method Not Allowed'
], 405);
});
}
Source: https://laravel.com/docs/8.x/errors

Laravel request url with parameter problem with GET Method

I have a route in api.php which look like this:
Route::get('auth/logout/{token}','UserController.php';
I tested this API endpoint using Postman with these configurations:
Method: GET
Params: key = token; value = $2y$10$Xji0VW1Qq9rtF04QlXDu1ePKNKHpRA2ppjDYWNFX.37C30sd3WSIu
Header: none
URL: localhost:8000/api/v1/logout?token=$2y$10$Xji0VW1Qq9rtF04QlXDu1ePKNKHpRA2ppjDYWNFX.37C30sd3WSIu
Here is my UserController#logout:
public function logout($token){
return response()->json([
'message' => 'Logout Success',
'token' => $token
], 200);
}
As you can see there, I just want to show a message and the $token parameter in Postman. But my problem is, Postman shows me a blank response. I can't access the URL with ? as the parameter separator. But I can access the URL with /, just like host/api/v1/auth/logout/{token_value}. But it is not what I desired. Anyone can help me?
You can remove the token route parameter:
Route::get('auth/logout', 'UserController.php');
And retrieve the token from the request in the controller:
public function logout(Request $request) {
return response()->json([
'message' => 'Logout Success',
'token' => $request->token
], 200);
}

How can I log what is going wrong in my controller

I am trying to register a user on my website with the laravel/vue.js/vuex. In my store actions, I'm calling the tryRegister action to post a request. But it keeps responding with a 401 error not authorizaed, and I don't understand why. So I made my controller as basic as it can get to just get a response and even then it keeps throwing the 401 authorization error. I'm new to back-end developing and just can't understand why this happens. I do know for sure that the route is working. How can I make my controller function give a basic response to see if it is working? And why is it giving an authorization error even tho I'm not doing anything with authorization, is that just the standard error a controller gives?
Try register action
tryRegister(context, credentials) {
return new Promise((resolve, reject) => {
axios
.post("/api/auth/register", credentials)
.then(response => {
console.log(response.data);
//context.commit("registerSucces", response.data);
resolve(response.data);
})
.catch(error => {
console.log(error.response);
reject(error);
});
});
}
Authorization controller register function
public function register(Request $request)
{
// $user = User::create([
// 'email' => $request->email,
// 'password' => $request->password,
// ]);
//$token = auth('api')->login($user);
//return $this->respondWithToken($token);
return response()->json(['message' => 'controller register']);
}
your register method of the controller is not accessible because of the auth middleware. so you are getting not authorized error. make it accessible without authorization. in the constructor method of the controller change this line like below.
$this->middleware('auth:api', ['except' => ['login', 'register']]);
login and register are controller's method which will be now accessible without authorization.

Error Messages - Laravel 5.2

Can someone please tell me how to make my "Page not found" or something messages? For example if someone writes a link in the browser which do not exist in my project, not to show the standard error page ( Woops, something went wrong, View [bla.bla] not found ) but page specified by me?
<?php
Route::get('sendemail', 'EmailController#sendEmail');
Route::get('test', 'AuthController#getTest');
Route::get('napravisiadmin', 'ClassbookController#getIndex');
Route::group(['middleware' => ['web']], function () {
Route::group(['middleware' => ['guest']
], function () {
Route::get('login', 'AuthController#getLogin');
Route::post('login', 'AuthController#postLogin');
});
Route::get('logout', 'AuthController#getLogout');
//Admin
Route::group(['middleware' => ['auth', 'auth.admin']
], function () {
Route::group([
'prefix' => 'admin',
'namespace' => 'Admin'
], function () {
Route::controller('student', 'StudentsController');
Route::controller('profile', 'ProfilesController');
Route::controller('class', 'ClassesController');
Route::controller('subjects', 'SubjectsController');
Route::controller('teacher', 'TeachersController');
Route::controller('marktype', 'MarkTypeController');
Route::controller('rules', 'RuleController');
Route::get('{slug?}', 'PageController#getView');
});
});
//Admin
//Student
Route::group([
'middleware' => ['auth', 'auth.student'],
'prefix' => 'stu',
'namespace' => 'Stu'
], function () {
Route::get('{slug?}', 'StuController#getView');
});
//Student
//Teacher
Route::group([
'middleware' => ['auth', 'auth.teacher'],
'prefix' => 'educator',
'namespace' => 'Educator'
], function () {
Route::get('edit/{id}', 'AccountController#getEdit');
Route::post('edit/{id}', 'AccountController#saveEdit');
Route::get('account', 'AccountController#getView');
Route::get('class-subject', 'AccountController#getClassSubject');
Route::get('add-mark', 'AccountController#getAddMark');
Route::post('mark', 'AccountController#postAddMark');
Route::get('added', 'AccountController#marksList');
Route::get('statistics', 'AccountController#marksInTable');
Route::get('personalemails', 'PersonalEmailController#getView');
Route::post('personalemails', 'PersonalEmailController#personalEmail');
});
//Teacher
});
Route::get('{slug?}', 'PageController#getView');
For the "Page not found" 404 error create a view in resources/views/errors/404.blade.php and it will show when you get a 404 error.
From the documentation:
Custom HTTP Error Pages
Laravel makes it easy to return custom error pages for various HTTP
status codes. For example, if you wish to customize the error page for
404 HTTP status codes, create a resources/views/errors/404.blade.php.
This file will be served on all 404 errors generated by your
application.
The views within this directory should be named to match the HTTP
status code they correspond to.
https://laravel.com/docs/5.2/errors#custom-http-error-pages
You can always go a step further by utilising the exception handler and handling exceptions the way you desire by customising the render() method
https://laravel.com/docs/5.2/errors#the-exception-handler
For example, if you wanted to handle file not found error, Exceptions\Handler.php
public function render($request, Exception $e)
{
if ($e instanceof \Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException) {
return response()->view('errors/exceptions/file-not-found', [], 500);
}
return parent::render($request, $e);
}
You can create custom error 404 page. If someone will enter wrong URL in a browser, he will see that page.
Also, you can redirect user manually to this page with:
abort(404);
Update
I guess the problem is here:
Route::get('{slug?}', 'PageController#getView');
You're using this three times, try to remove all of them.
The thing is when Laravel doesn't find any routes, it takes {slug} and passes it to the PageController, so when you enter http://example.com/sometext, you will be transferred to the PageController with slug = sometext.
If you do not want to remove it, check for slug inside a controller and if slug means something - good. If not, just abort(404); and user will be transferred to an error page.
Also, if you're on 5.2.27 of higher, remove web middleware from routes.php (it applies automatically, and manual apply can cause errors and strage behavior).

Categories