Laravel "Unauthenticated" error in specific route - laravel

In my Laravel 7 backend I have some api url like:
Route::group(['namespace' => 'Api', 'middleware' => ['auth:sanctum']], function(){
Route::post('logout/all', 'Auth\LoginController#logoutAll');
Route::post('logout', 'Auth\LoginController#logout');
Route::put('profile/{profile}', 'ProfileController#update');
});
The route /logout and /profile/1 work fine, while the route /logout/all gives an error:
{
"error": "Unauthenticated"
}
The token I use is correct because I can use it for others route and it works.
Of course I didn't call the /logout before trying the /logout/all.
I tried to change the controller function of logoutAll, setting it to "logout":
Route::group(['namespace' => 'Api', 'middleware' => ['auth:sanctum']], function(){
Route::post('logout/all', 'Auth\LoginController#logout');
Route::post('logout', 'Auth\LoginController#logout');
Route::put('profile/{profile}', 'ProfileController#update');
});
In this way it works, but this invoke the same function.
That's the code of the function:
public function logout(Request $request)
{
Auth::user()->tokens()->where('id', Auth::user()->currentAccessToken()->id)->delete();
return response()->json(['data' => 'User logged out.'], 200);
}
public function logoutAll(Request $request)
{
//do nothing
return response()->json(['data' => 'User loggedAll out.'], 200);
}
Help me please.
UPDATE
If I use CURL command this is the output:
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException: The POST method is not supported for this route. Supported methods: GET, HEAD. in file /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php on line 117
#0 /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php(103): Illuminate\Routing\AbstractRouteCollection->methodNotAllowed(Array, 'POST')
#1 /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/AbstractRouteCollection.php(40): Illuminate\Routing\AbstractRouteCollection->getRouteForMethods(Object(Illuminate\Http\Request), Array)
#2 /Applications/MAMP/htdocs/test-server/vendor/laravel/framework/src/Illuminate/Routing/RouteCollection.php(162): Illuminate\Routing\AbstractRouteCollection->handleMatchedRoute(Object(Illuminate\Http\Request), NULL)
...

The problem was in the __constructor() method
$this->middleware('guest')->except('logout');
I change it to:
$this->middleware('guest')->except(['logout', 'logoutAll']);
Now it works fine.

Related

Laravel API call goes through even with session expired

I have a SPA based on Laravel 5.8 and Vue 2.0.
Everything is working fine, a little bit too much to be honest, because if I delete the session and I try to save the content afterward or keep navigating the private pages, every ajax call that I'm doing with Axios is going through without returning any error. Only if I forcefully refresh the page I get the error page I setup but if I don't, I can keep doing everything even if the session no longer exist.
This is my setup.
web.php is where I have the only php route that points to a singlePageController:
Auth::routes();
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');
Then in the singlePageController I return the view:
class SinglePageController extends Controller
{
public function index() {
return view('app', ['loggedUser' => auth()->user()]);
}
}
Then I have the api.php where I have the API routes. As you can see at the end I have the middleware to make it private. Just to make an example this is the one I use for updating the content:
Route::put('event/update/{slug}', 'EventController#update')->middleware('auth:api');
Then the related controller of that API route:
public function update(Request $request, $slug)
{
$event = Event::where('slug', $slug)->first();
$event->title = $request->input('title');
return new EventResource($event);
}
And in the end this is the Resource I use to define what and how the API data is going to be displayed:
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'curator' => $this->curator,
'featured_image' => $this->featured_image,
'body' => $this->body,
'date' => $this->date
];
}
So this above is the flow I have. Then when I do an axios call to update the content, I'm doing something like:
axios({
method: 'PUT',
url: '/api/event/update/' + this.$route.params.slug + '?api_token=' + this.isLogged.apiToken,
data: dataToSave,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
.then((response) => {
this.getNotification('Success: The Event has been saved');
})
.catch((error) => {
this.getNotification('Error: Impossible saving the event');
console.log(error);
})
Thanks in advance for the help
In Laravel routes in api.php ignore the session data.
If you want to authenticate with session data you could move your api routes to web.php and you should see the results you expect.

LARAVEL & VUE: How can I get the API_TOKEN of the logged in user with an API request?

I have a SPA using VUE and LARAVEL 5.8
I have setup an API_TOKEN associated to the logged in user. Everything works fine right after the login. I get the API_TOKEN, I save it into a var and I send it together with the Axios request. In Laravel I have a middleware that is taking care of the token and comparing it with the one setup on the logged in user.
the problem though occur when session expires. Because I still can navigate the private pages and make API requests to save and delete content. This is possible I think because I still have the same API_TOKEN saved in the var and the middleware apparently doesn't get that the session is expired.
So I want to obtain the API_TOKEN every time I'm doing an Ajax, request so when the session expires, I won't get the token and therefore, I won't be able to complete the request.
This is my setup.
web.php is where I have the only php route that points to a singlePageController:
Auth::routes();
Route::get('/{any}', 'SinglePageController#index')->where('any', '.*');
Then in the singlePageController I return the view:
class SinglePageController extends Controller
{
public function index() {
return view('app', ['loggedUser' => auth()->user()]);
}
}
Then I have the api.php where I have the API routes. As you can see at the end I have the middleware to make it private. Just to make an example this is the one I use for updating the content:
Route::put('event/update/{slug}', 'EventController#update')->middleware('auth:api');
Then the related controller of that API route:
public function update(Request $request, $slug)
{
$event = Event::where('slug', $slug)->first();
$event->title = $request->input('title');
return new EventResource($event);
}
And in the end this is the Resource I use to define what and how the API data is going to be displayed:
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'title' => $this->title,
'slug' => $this->slug,
'curator' => $this->curator,
'featured_image' => $this->featured_image,
'body' => $this->body,
'date' => $this->date
];
}
So this above is the flow I have. Then when I do an axios call to update the content, I'm doing something like:
axios({
method: 'PUT',
url: '/api/event/update/' + this.$route.params.slug + '?api_token=' + this.isLogged.apiToken,
data: dataToSave,
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
})
.then((response) => {
this.getNotification('Success: The Event has been saved');
})
.catch((error) => {
this.getNotification('Error: Impossible saving the event');
console.log(error);
})
Do you know how to make it? or if there is a better way to accomplish that?
you and do like, your login method should like this.
public function login(Request $request)
{
if (Auth::attempt(['email' => $request['email'], 'password' => $request['password']])) {
$user = Auth::user();
$success = $user->createToken(config('app.name'))->accessToken;
return response()->json(["token" => $success, 'status' => 200]);
} else {
return response()->json(['message' => "Email or Password do not match"], 401);
}
}

Override auth redirection of apis url in laravel with auth passport system

I have created some apis thats work fine. Now when someone hit that protected apis url that have get request on web browser then it redirect to login of auth system. How can I override this functionality?
Full Details
I am working in laravel application in which I have implemented passport and auth system. This project has not any web interface till date.
This is my api.php
Route::group(['middleware' => ['auth:api'],'namespace' => 'Api', 'prefix' => '/v1'], function () {
Route::get('/user/profile', 'UserController#profile');
Route::get('/logout', 'Auth\LoginController#logout');
});
Route::group(['middleware' => ['api'], 'namespace' => 'Api', 'prefix' => '/v1'], function () {
Route::post('/auth/register', 'Auth\RegisterController#create');
Route::post('/auth/login', 'Auth\LoginController#login');
Route::post('/auth/password/email', 'Auth\ForgotPasswordController#getResetToken');
Route::post('/auth/password/reset', 'Auth\ResetPasswordController#reset');
});
and this is my web.php
Route::get('/', function () {
return view('welcome');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
When I hit
{{site_url}}/api/v1/user/profile
without passing or with invalid access token in postman then it returns the following error(this is OK).
{"status":"fail","success":0,"error":401,"message":"Invalid Token!"}
But when I hit this url in web browser then it redirect me to login page.
I solved this problem by adding these functions to /app/Exceptions/Handler.php:
public function unauthenticated($request, AuthenticationException $exception){
if($request->expectsJson()){
return response()->json('Please login',401);
}
return redirect()->guest('admin/login');
}
public function unauthorized($request, AuthorizationException $exception){
if($request->expectsJson()){
return response()->json("You don't have permission to do this",401);
}
return redirect()->guest('login');
}

Laravel 5.2 redirect doesn't save flash messages

I installed fresh laravel 5.2.29.
My routes.php:
Route::group(['middleware' => ['web']], function () {
Route::get('/a', function () {
return redirect('/b', 302)->with('error', 'error description');
});
Route::get('/b', function () {
return session('error');
});
});
When I go to /a in browser it redirects me to /b, but shows me nothing. What should I do to it show me error description? Or why does not it store flash data?
Basically, if you are running Laravel 5.2.27 and up, do not use the web middleware group. It is applied for you by default as you can see in app/Http/RouteServiceProvider.php:
protected function mapWebRoutes(Router $router)
{
$router->group([
'namespace' => $this->namespace, 'middleware' => 'web',
], function ($router) {
require app_path('Http/routes.php');
});
}
If you try to apply the web middleware again, you'll run into weird problems like what you are currently facing.

Laravel 5.1 API redirects ALL requests to /home after a user have registered

I have the weirdest problem ever...
Currently I have 2 routes in my laravel 5.1 project which i will use as my api.
Route::post('register', 'Auth\AuthController#postRegister');
Route::post('login', 'Auth\AuthController#postLogin');
First time I make an ajax call from my front-end to the 'register' route, everything works as expected.
However, if I make another ajax call to ANY laravel route, it redirects me to the 'home' route.
My code:
AuthController:
public function postRegister(CreateUserRequest $request)
{
User::createUser($request);
return response()->json();
}
public function postLogin(Request $request)
{
if (!Auth::attempt(['email' => $request->email, 'password' => $request->password])) {
return response()->json()->setStatusCode(403);
}
return response()->json();
}
Model:
public static function createUser($data)
{
DB::table('users')->insert([
'f_name' => $data->f_name,
'l_name' => $data->l_name,
'gender' => $data->gender,
'email' => $data->email,
'birth_date' => $data->birth_date,
'password' => bcrypt($data->password),
'activation_code' => $data->activation_code
]);
}
Ajax call:
$.ajax({
url: Api.route('register'),
method: 'POST',
data: requestData,
statusCode: {
200: function()
{
console.log('register: 200');
},
422: function()
{
console.log('register: 422');
}
}
});
I have tried:
making the first ajax call, then commenting out everything in the controller to only return a string, but it still redirects me to the 'home' route on the second request.
If i comment out the "DB::insert(...)" it works like expected.
If I make the "DB::insert()" without any data it also works like expected.
If i make the "DB::insert()" with any single field it redirects on the second call.
If I use the default Request instead of my custom request it's still redirecting.
Any suggestions are greatly appreciated!
The guest middleware applied to all routes of AuthController, except the getLogout.
Hence, any ajax call to these routes it redirects to the home route (check the RedirectIfAuthenticated middleware), except the getLogout.
So, you should logout the user to work like expected.
Set the below route and call it:
Route::get('logout', 'Auth\AuthController#postLogout');
Or logout the user manually:
Auth::logout();

Resources