what is the route for candidateDashboard definition? any middleware? is it directed to a controller? any authentiication/gates there in controller? or a form request maybe?
Authenticated user redirecting to the Login page
Hi,
I have a custom login/2FA form posting to a route like so:
Route::post('/2fapassword', [SocialController::class, 'checkPassword'])->name('2fapassword');
which I am handing like below:
public function checkPassword(Request $request)
{
$request->validate([
'code' => 'required',
]);
if (Otp::where('recipient', $request->email)->first()->password == $request->code)
{
$user = User::create(
[
'name' => strstr($request->email, '@', true),
'email' => $request->email,
'password' => Hash::make($request->email . now()),
]
);
Auth::login($user, $remember = true);
return redirect('/candidateDashboard');
}
}
The user is created properly, and Auth::check() returns true but the user always redirects (302) from candidateDashboard to the login page. I can't understand why.
Any help is appreciated. Thank you.
Ca you show the dashboard route please ? With the middlewares applied to it ?
you need to regenerate the session after logging in your user. the session you are redirecting with is not authenticated
@krisi_gjika not in my experience....
@Snapey havent tested this specific case, but based on the docs https://laravel.com/docs/12.x/authentication#authenticating-users a successful attempt call is followed by $request->session()->regenerate(); and Auth::attempt still uses Auth::login under the hood
@krisi_gjika I tried this but it did not work.
The route is as below
Route::middleware([
'auth:sanctum',
config('jetstream.auth_session'),
'verified',
])->group(function () {
Route::get('/candidateDashboard', [Controller::class, 'show'])->name('dashboard');
});
And the controller
class Controller extends BaseController
{
use AuthorizesRequests, ValidatesRequests;
public function show(): View
{
if (Auth::check() && Auth::user()->is_backend == 1) {
return view('dashboard');
} else {
if (Auth::user()->candidate()->exists()) {
return view('candidate.dashboard');
} else
return view('candidate.create-profile');
}
}
}
@burfi What is the code for candidate() ?
The candidates table has the user_id as a foreign key.
public function candidate(): HasOne
{
return $this->hasOne(Candidate::class);
}
@burfi I would have a look at the authentication process.
Route::middleware([
'auth:sanctum',
config('jetstream.auth_session'),
'verified',
])
Quite sure that if one of the middleware doesn't pass, the user is redirected to the login page.
Have you checked if the user is authenticated ?
Have you checked if the user is verified ?
Have you checked the jetstream auth session middleware ?
To check this, I removed the other middleware except for the auth
Route::middleware([
'auth:sanctum',
])->group(function () {
...
while dump(Auth::check()); returns true, it still goes to the Login screen
Is this app a SPA, API, or Mobile? Just wondering if the correct part of sanctum is being used depending on the type of app.
@jlrdw as of how, this is just a simple web app.
@burfi I don't know if this post will help, but have a look:
https://laracasts.com/discuss/channels/laravel/login-redirects-in-jetstream
remove middleware until it stops redirecting
To add to my last reply to vincent1500, if I remove even the auth middleware, it goes to the controller function.
@burfi So it's now clear that either the user isn't connected, or you have a problem with the sanctum configuration.
Have a look at the devtools (network tab) in your browser and tell us what you see when you are logging in.
Name - status - type - initiator
candidateDashboard - 302 - document/Redirect - other
login - 200 - document - candidateDashboard
@burfi Hmmm all seems to be ok, so the only problem I can see is that there is probably a problem with the authentication.
Or ... you are using sanctum to protect your routes, so I guess that you are using a JS framework for the frontend : VueJS ? React ? Angular ?
If it's the case, you can't redirect from the controller, it's just impossible. (if it's not the case, you shouldn't use sanctum)
When you work in API mode (that means with a separate frontend), the controller has just to return a success or an error JSON response.
I guess that your frontend doesn't receive any reponse (considered as false, not connected) and redirects to the login page.
In API mode :
-
you can't redirect from the backend (controller)
-
you can redirect only from the frontend
I just tried this:
Route::middleware([
/* 'auth:sanctum',
config('jetstream.auth_session'),
'verified', */
'auth',
])->group(function () {
...
Still the same... is there a way I can check the validity of the session?
@burfi Put something in session, go to another page and see if you can pull it back out of session.
Also delete packages.php and services.php from bootstrap\cache.
And clear all cache as well.
@jlrdw Sorry, but I am not sure I understand your first suggestion... there are no "other" pages.
It is just the login page -> the PIN page -> the dashboard page
and the problem is that I am not able to reach the dashboard page.
Regarding the second suggestion, I cleared and retried... didn't help.
Like @vincent15000 said, it is a problem with auth, need to find out what's that problem?
@burfi Can you just answer this simple question : what frontend are you using ?
@vincent15000 No React or Vue or any JS stuff... just Jetstream
@burfi Ok ... if you are using Jetstream, you are necessarily using :
-
either Livewire
-
or Inertia / VueJS
If you are using Sanctum, you are necessarily using Inertia / VueJS.
https://jetstream.laravel.com/introduction.html
In this particular case, you have two ways to redirect :
-
either you can redirect directly from the controller using the Inertian helper https://inertiajs.com/redirects
-
or you can redirect from the frontend (VueJS), this way you need to return a standard JSON response from the controller and redirect from VueJS with vue-router or a simple window location href
@vincent15000 Livewire, no Intertia
To check, as per your previous suggestion, I tried using only auth as a middleware, but it did not help.
@burfi So why are you using Sanctum ? With Livewire, you don't need Sanctum.
What is the configuration sur the sessions ? cookie ? file ? database ?
I am not using Sanctum in the middleware any more. I am using just auth
And the config is DB table:
'driver' => env('SESSION_DRIVER', 'database'),
@burfi And in the .env file ? What's the value for SESSION_DRIVER ?
And this is how the session looks like:
array:5 [▼ // app/Http/Controllers/SocialController.php:233
"_token" => "0L4F3dyLnHOnvPjsicfbZt1WBmwhdmAZXdj6wLlL"
"url" => array:1 [▼
"intended" => "http://127.0.0.1:8000/candidateDashboard"
]
"_previous" => array:1 [▼
"url" => "http://127.0.0.1:8000/2fachallenge/[email protected]"
]
"_flash" => array:2 [▼
"old" => []
"new" => []
]
"login_web_59ba36addc2b2f9401580f014c7f58ea4e30989d" => 4
]
Is there a way I can compare the session value that the browser sends and the one server matches it with?
@burfi Delete all rows in the sessions table, then log in to the application and check the sessions table. Do you have a new row created ?
@vincent15000 Yes, it does create a new row...
Can payload size be an issue here? Ref - https://github.com/laravel/framework/issues/53277
@burfi Which Laravel version are you using ? How have you installed jetstream ? Is it via a startkit ? I want to reproduce your problem with a fresh installation on my computer.
@burfi I just did a fresh installation of JetStream with Livewire and effectively I see that the routes are by default protected with the auth:sanctum middleware, which has no sense for me at the moment.
@burfi I don't understand what you are trying to do with your controller.
I just tested the 2 factors authentication with Laravel / JetStream, exactly like mentioned in the JetStream documentation, and it works fine.
https://jetstream.laravel.com/features/two-factor-authentication.html
As you have a SocialController, I think that you are using an external service like Google Authenticator or 2FAS ?
Sorry if my explanation is confusing. My application lets user log in in 2 ways -
- Google Login
- Login with SMS based PIN
===
I am doing Google Login with Socialite. It works fine.
Login with SMS is not working.
@burfi If you want help about this, it's necessary that you explain all the process and show the code you are using. For the moment, the only you show is this one with 2FA.
For example what are the steps for authentication with a code sent by SMS ?
-
generate a unique code and store it in the database
-
send the code to the user by SMS
-
display a form so that the user can type de code received by SMS
-
validate the code, login the user if the code is valid and delete the code from the database
And what is your code for each of these steps ?
@vincent15000 what about simple blade files, you know, like before livewire or inertia were invented
@Snapey Why are you asking me for this ? I just don't understand the connection with the topic.
I have recorded the screen for better understanding which shows both these flows - https://nimb.ws/RZnsBUV
- Google Login (in first 10-11 seconds)
- Login with SMS based PIN (rest of the video)
Now to answer your questions:
generate a unique code and store it in the database - yes, I will share the code below
send the code to the user by SMS - currently for testing purposes, I am not sending over SMS, I am reading the code from the DB and entering on the form
display a form so that the user can type de code received by SMS - hopefully the video shows the whole flow
validate the code, login the user if the code is valid and delete the code from the database - currently not yet deleting the code from the DB
====== code below ====
public function checkPassword(Request $request)
{
$request->validate([
'code' => 'required',
]);
if (Otp::where('recipient', $request->email)->first()->password == $request->code)
{
if (!User::where('email', $request->email)->exists()) {
$user = User::create(
[
'name' => strstr($request->email, '@', true),
'email' => $request->email,
'password' => Hash::make('password'),
'is_active' => 1,
]
);
} else
$user = User::where('email', $request->email)->first();
Auth::login($user, $remember = true);
if (Auth::check()) {
return redirect('/candidateDashboard');
}
} else
return back()->withErrors([ 'code' => 'The provided credentials do not match our records.', ]);
}
@burfi Why Otp:: ?
@burfi Is there some problems with your brackets ?
I have added brackets where it seems to be necessary.
public function checkPassword(Request $request)
{
$request->validate([
'code' => 'required',
]);
if (Otp::where('recipient', $request->email)->first()->password == $request->code)
{
if (!User::where('email', $request->email)->exists()) {
$user = User::create(
[
'name' => strstr($request->email, '@', true),
'email' => $request->email,
'password' => Hash::make('password'),
'is_active' => 1,
]
);
} else {
$user = User::where('email', $request->email)->first();
}
Auth::login($user, $remember = true);
if (Auth::check()) {
return redirect('/candidateDashboard');
}
} else {
return back()->withErrors([ 'code' => 'The provided credentials do not match our records.', ]);
}
}
@vincent15000 if brackets would have been problematic, it would have given syntax error. Isn't it?
@burfi Yes but only if brackets were missing. I think that you have to better organize your code and be sure that every line of code is executed at the right place. So I have added brackets.
if you are using Jetstream, you are necessarily using :
either Livewire
or Inertia / VueJS
@Snapey Oh ok sorry, I was sure that JetStream only works with Livewire or Inertia / VueJS.
@vincent15000 @snapey I observed that if I return view instead of redirect, it shows the dashboard. But at the time of navigating to profile or any other route, it logs out.
return view('candidate.dashboard');
instead of this
return redirect('/candidateDashboard');
@burfi Have you tried this ? (assuming you have named the route)
return redirect()->route('candidate.dashboard');
@vincent15000 yes, i was trying that at the very start, it never worked.
I have a strong feeling now, that this problem is with the session/cookies (the setup).
But I tried Laravel Herd (today) but the issue persists.
Update:
It looks like my assumption of the setup being an issue is wrong.
I created a new setup without Jetstream.
The manual login (as per the documentation - https://laravel.com/docs/10.x/authentication#authenticating-users) works but Auth::login() still does not work.
@burfi Have you regenerated the token after the connection ?
Although the Laravel documentation does not mention that you need to regenerate if you use Auth::login() but yes I tried that anyway and it did not work.
Hi brother, I have been struggled with the same issue for so long Let me tell you it's simple trick Don't. Validate in controller using $request, Simply create a request using Php artisan make:request RequestName And write your validation code inside it. And pass that RequestName inside your controller like Public function ControllerName(RequestName request ) This will first validate then go inside the controller logic This will solve your problem.
@gauravsharma121997 I think that you don't have understood the post of the OP, the form request can't give any solution to this problem.
@gauravsharma121997 it is a PIN based login kind of a scenario, wherein I am creating the user manually and then logging the user in by using Auth::login($user) if the PIN on the email matches the one entered on the login form.
The problem is that even after successful login, the user is logged out (maybe because of session issue by auth) when trying to access a protected route.
can you please check cookie generation?
clear cookies for the site and check that one is created when you login.
@Snapey yes the cookie is getting generated.
Is there anything specific that I could check in the cookie? Maybe the value is wrong or anything else?
Its clear that sessions are not working, and that any request following login is not associated with the logged in user.
However this DOES work when you authenticate using socialite.
Do you have any middleware associated with the socialite login, which could be messing with the session?
You can list all the middleware associated with your dashboard route;
php artisan route:list -vv name=dashboard
Hmmm ... can you show the code of the view in which the user has to type the code for 2FA please ?
I suggest after all you have tried, start a new app and:
- get regular auth working first
- then work on the 2FA following the documentation
Also view the free course: https://laracasts.com/series/30-days-to-learn-laravel-11
@snapey @vincent15000 apologies for not replying. I've been busy with something else. I will probably post an update when I get back to this.
Thank you.
Please or to participate in this conversation.