Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

jlrdw's avatar
Level 75

Version 8 redirects

Has anyone figured out how to handle redirects once logged in?

Like:

  • if admin redirect to admin page
  • if bookkeeper redirect to accounts page
  • if user redirect to user page
  • etc

In previous version it had the authenticated method from trait. This version I have only seen the

'home' => RouteServiceProvider::HOME,
// which is
public const HOME = '/dashboard';  // only one redirect allowed
0 likes
42 replies
tykus's avatar

You can implement and bind your own LoginResponse class (which implements LoginResponse interface) into the container.

2 likes
jlrdw's avatar
Level 75

What I did, make a HomeController with only index method, then:

Changed RouteServiceProvider line to

public const HOME = 'redirects';

Made a route:

Route::get('redirects', 'App\Http\Controllers\HomeController@index');

And in HomeController it redirects depending on role:

    public function index()
    {
        $role = Auth::user()->role;
        $checkrole = explode(',', $role);
        if (in_array('admin', $checkrole)) {
            return redirect('dog/indexadmin');
        } else {
            return redirect('pet/index');
        }

    }

Note

Most will need a leading slash (/) like:

return redirect('/dog/indexadmin');

I don't because I set htacces to skip leading slash.

It works. But if you could a short example of a LoginResponse class, it would also help others.

7 likes
devutoo's avatar

I used your example here, so I didn't have to change all routes named 'dashboard' in the jetstream view files.

I didn't even change the RouteServiceProvider line and returned views instead of redirects in my HomeController.

It works fine. Are there any security or other concerns to not just handle it that way?

jacklinwood's avatar

This works great, thank you!

The only problem I'm now having is redirecting after email verification. Any idea how to change that too?

travis.elkins's avatar

I came here looking for the same information. Did you figure anything out?

I would like it to go to the email verification message page, but it goes to the login page (presumably via the dashboard).

I think this is default behavior, but can't work it out. It even says on the default email verification screen, "Thanks for signing up!".

🤔

SmyGeb05's avatar

hi,

has the directory structure changed recently. the path is different for me. Mine requires the [src] sub-directory:

public function boot()
    {
        $this->configurePermissions();

        Jetstream::deleteUsersUsing(DeleteUser::class);

        // register new LoginResponse
        $this->app->singleton(
            \Laravel\Fortify\src\Contracts\LoginResponse::class,
            \App\Http\Responses\LoginResponse::class
        );
    }

/Users/rbd/Documents/sites/project_name/vendor/laravel/fortify/src/Contracts/LoginResponse.php

jlrdw's avatar
Level 75

Will give it a try later, thanks.

jlrdw's avatar
Level 75

It works:

Just quick test and example for those redirecting depending on role:

<?php

namespace App\Http\Responses;

use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;

class LoginResponse implements LoginResponseContract
{

    public function toResponse($request)
    {
        
        // below is the existing response
        // replace this with your own code
        // the user can be located with Auth facade
        $role = Auth::user()->role;
        $checkrole = explode(',', $role);  // However you get role
       
        if (in_array('admin', $checkrole)) {
            Session::put('isadmin', 'admin');
           return redirect('dog/indexadmin');
        } else {
            return redirect('pet/index');
        }

        
        return $request->wantsJson()
                    ? response()->json(['two_factor' => false])
                    : redirect()->intended(config('fortify.home'));
    }

}

Note

Most will need a leading slash (/) like:

return redirect('/dog/indexadmin');

I don't because I set htacces to skip leading slash.

3 likes
sabroso's avatar

Ya solucione la cuestion del logout, pero no puedo poner el enlace mandame inbox

Snapey's avatar

The process is the same. Just create and bind a LogoutResponse instead

These are the bindings registered by Fortify;

    protected function registerResponseBindings()
    {
        $this->app->singleton(LoginResponseContract::class, LoginResponse::class);
        $this->app->singleton(LockoutResponseContract::class, LockoutResponse::class);
        $this->app->singleton(LogoutResponseContract::class, LogoutResponse::class);
        $this->app->singleton(RegisterResponseContract::class, RegisterResponse::class);
        $this->app->singleton(SuccessfulPasswordResetLinkRequestResponseContract::class, SuccessfulPasswordResetLinkRequestResponse::class);
        $this->app->singleton(FailedPasswordResetLinkRequestResponseContract::class, FailedPasswordResetLinkRequestResponse::class);
        $this->app->singleton(PasswordResetResponseContract::class, PasswordResetResponse::class);
        $this->app->singleton(FailedPasswordResetResponseContract::class, FailedPasswordResetResponse::class);
    }
1 like
jlrdw's avatar
Level 75

@snapey did you see answer on other post where I asked could you do a pull request to include this?

Thanks...

1 like
assoft's avatar

@snapey

This is works, but only if disabled two-factor authentication. My app responds like this.

Is there something wrong? Is it the same for you when you use two-factor authentication?

    public function toResponse($request)
    {
        $redirect = config('fortify.home');

        // Only if two factor authentication is disabled
        $check = Auth::user()->hasAnyRole([
            "admin",
            "maintainer",
        ]);

        if ($check) {
            $redirect = route("admin.dashboard");
        }

        return redirect($redirect);

        // return $request->wantsJson()
        //     ? response()->json(['two_factor' => false])
        //     : redirect()->intended(config('fortify.home'));
    }
assoft's avatar

If two-factor authentication is enabled, it always goes to the "fortify.home" @snapey

Niush's avatar

Yes, can confirm to @assoft

There is no Contracts\TwoFactorLoginResponse thingy to bind with custom Response. (There is one for TwoFactorChallengeViewResponse only.)

So, when user login successfully, then when 2fa is enabled, laravel will not use LoginViewResponse.

The \Laravel\Fortify\src\Http\Responses\TwoFactorLoginResponse.php is where fortify redirects to dashboard. Now, this cannot be used to bind like contracts.

1 like
Snapey's avatar

@assoft @nuish

I created a PR to add the TwoFactorLoginResponse also, and had it accepted this morning. I don't know when it will be released.

3 likes
jlrdw's avatar
Level 75

I know these fixes put my mind at ease with the new jetstream.

assoft's avatar

Updated Laravel Jetstream v1.2.0

I've tested and verified it works.

Thank you @snapey

Enjoy.

public function boot()
{
    $this->configurePermissions();

    Jetstream::deleteUsersUsing(DeleteUser::class);

    // register new LoginResponse
    $this->app->singleton(
        \Laravel\Fortify\Contracts\LoginResponse::class,
        \App\Http\Responses\LoginResponse::class
    );

    $this->app->singleton(
        \Laravel\Fortify\Contracts\TwoFactorLoginResponse::class,
        \App\Http\Responses\TwoFactorLoginResponse::class
    );
}
2 likes
braffzachlin's avatar

I don't know why everyone's binding the Login Response Class in Jetstreams Service Provider...

Here's what I did. Works for both TwoFactorLogin and vanilla login:

Create "LoginResponse.php" in "app/Http/Responses"

<?php

namespace App\Http\Responses;

use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;

class LoginResponse implements LoginResponseContract
{
    /**
     * Create an HTTP response that represents the object.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function toResponse($request)
    {
        $role = \Auth::user()->role;

        if ($request->wantsJson()) {
            return response()->json(['two_factor' => false]);
        }

        switch ($role) {
            case 'admin':
                return redirect()->intended(config('fortify.home'));
            case 'host':
                return redirect()->intended('/host/dashboard');
            default:
                return redirect('/');
        }
    }
}

Create "TwoFactorLoginResponse.php" in "app/Http/Responses"

<?php

namespace App\Http\Responses;

use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;

class TwoFactorLoginResponse implements TwoFactorLoginResponseContract
{
    /**
     * Create an HTTP response that represents the object.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function toResponse($request)
    {
        $role = \Auth::user()->role;

        if ($request->wantsJson()) {
            return response('', 204);
        }

        switch ($role) {
            case 'admin':
                return redirect()->intended(config('fortify.home'));
            case 'host':
                return redirect()->intended('/host/dashboard');
            default:
                return redirect('/');
        }
    }
}

Now register the response bindings in 'app\Providers\FortifyServiceProvider.php'

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Route;
use App\Actions\Fortify\CreateNewUser;
use App\Actions\Fortify\ResetUserPassword;
use App\Actions\Fortify\UpdateUserPassword;
use App\Actions\Fortify\UpdateUserProfileInformation;
use Illuminate\Support\ServiceProvider;
use Laravel\Fortify\Fortify;
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
use App\Http\Responses\LoginResponse;
use App\Http\Responses\TwoFactorLoginResponse;

class FortifyServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->registerResponseBindings();
    }

    /**
     * Register the response bindings.
     *
     * @return void
     */
    protected function registerResponseBindings()
    {
        $this->app->singleton(LoginResponseContract::class, LoginResponse::class);
        $this->app->singleton(TwoFactorLoginResponseContract::class, TwoFactorLoginResponse::class);
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {        
        Fortify::createUsersUsing(CreateNewUser::class);
        Fortify::updateUserProfileInformationUsing(UpdateUserProfileInformation::class);
        Fortify::updateUserPasswordsUsing(UpdateUserPassword::class);
        Fortify::resetUserPasswordsUsing(ResetUserPassword::class);
    }
}
7 likes
JanTay's avatar

Hi Thank you so much for posting this. I am using Fortity with no Jetstream and implementing 2fa. I've struggled for days with this and your code has been a God send. Jan

Triumfator's avatar

Can someone post a complete tutorial on this please.... I understand the concept, but i'm not sure where to do a check for authenticated user role. Also what migrations modification is needed to the database? Add another "user type" column to users table with let's say 0 for regular users and 1 for admins?

jlrdw's avatar
Level 75

The laravel from scratch series has several videos on authentication and authorization and this is a free video series.

1 like
javieralex's avatar

With a switch case, would it work for more roles?

example 4 roles.

super admin, admin, master and user

jlrdw's avatar
Level 75

@javieralex an example:

  • Bob is an admin

  • Suzy is admin and does bookkeeping

  • Mary is a bookkeeper only

  • If Bob is logged in, Bob can only do admin stuff and all access to user stuff. But Bob cannot mess with bookkeeping.

  • If Suzy is logged in she can access admin stuff and bookkeeping and accounting stuff.

  • If Mary is logged in she cannot mess with admin stuff, but has access to bookkeeping and accounting stuff.

So I just check at method level if the logged in users role can or cannot access that method / function.

So in pseudocode:

public function makeInvoice()
    {
        if (a required role of bkeep is not true here) {   // bkeep = bookkeeper
            return redirect('somewhere'); // whereever you redirect to if not authorized
        }
        // Rest of method here is accomplished if 
        // the logged in user has the required role of 'bkeep'.
    }

It's good to use Authorization with query scopes to fine tune.

Another example:

public function update(Request $request, Post $post) {
    if ($post->author !== auth()->user()->id || auth()->user()->cannot('edit posts'))
        abort(404);// or redirect, or whatever action 
    }
    //rest of method if all okay
}

I usually like protecting methods rather than messing around with several middleware setups.

But just my opinion.

1 like
javieralex's avatar

Hi, can you help me? In jetstreams we have a default navigation drop down menu, how can I change according to the user's role, I already tried directly in the view with a condition and directly in app.blade. I would appreciate your help

1 like
Fleo's avatar

Hello, what was the problem ?

jovs's avatar

On your RouteServiceProvider class and boot method, you can programmatically set what will be value of the "HOME" constant.

nekooee's avatar

after rewrite ResponseLogin how to redirect to hme page blade? I use this code in ResponseLogin.php:

return $request->wantsJson()
            ? response()->json(['two_factor' => false])
            : redirect()->intended("/");

and my home page is the blade. Unfortunately, it opens the home page in a pop-up dialog. and doesn't redirect to home with refresh page.

yanziyan's avatar

If you want to implement the documentation https://laravel.com/docs/9.x/fortify#customizing-user-authentication

Typically, this should be done within the register method of your application's App\Providers\FortifyServiceProvider class:

use Laravel\Fortify\Contracts\LoginResponse;


class FortifyServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->instance(LoginResponse::class, new class implements LoginResponse {
            public function toResponse($request)
            {
              	
              if ($request->user()->type == 'editor') {
                return redirect('/editor');
              }
              return redirect('/');							

              
            }
        });
    
    }

That is all. you don't need to do anything else

Warning: If you want to use the code from the Laravel documentation, remember that the sample code is for logout and change LogoutResponse to LoginResponse

toyapogi's avatar

@yanziyan Hi guys, I tried this method and it is working properly. But I have a little bit of problem, When I log in it redirects me to "/super/dashboard" which is correct. But if I click back and refresh the page which is the login page and login again, it redirects me to the default fortify dashboard "/dashboard". Any idea how to fix this?

Thanks

Please or to participate in this conversation.