Fortify: How to Disable Auto-login After User Registration

#laravel #hotfix

A noob mentality will have you thinking you can easily comment out that line and you're good to go. Well, you could do that and your code temporarily behaves as expected but what happens when you run `composer update/install` and your change is overridden––You are back to square one. You should never make changes to any code within the confines of the `vendor` folder.

With Fortify, a user is logged in, automatically, after registration. This might not be what you want for your application. Thankfully, the package is easily extensible.

This post is a walk-through on how to override the default behaviour and disable the auto-login.

Before we start, let's take a look at the package and try to understand what is happening behind the curtain. You register a user by hitting the /register endpoint with the expected name, email, password and password_confirmation fields' values. On a successful login, you get redirected to the home configuration option in your fortify's configuration file. The controller responsible for handling the registration request is RegisteredUserController. Inside the controller class, there is another method–store that handles the actual registration:

/**
 * Create a new registered user.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Laravel\Fortify\Contracts\CreatesNewUsers  $creator
 * @return \Laravel\Fortify\Contracts\RegisterResponse
 */
public function store(Request $request,
                        CreatesNewUsers $creator): RegisterResponse
{
    event(new Registered($user = $creator->create($request->all())));

    $this->guard->login($user);

    return app(RegisterResponse::class);
}

You can see that the registered user is logged in right after firing the Registered event.

$this->guard->login($user);

A noob mentality will have you thinking you can easily comment out that line and you're good to go. Well, you could do that and your code temporarily behaves as expected but what happens when you run composer update/install and your change is overridden––You are back to square one. You should never make changes to any code within the confines of the vendor folder.

Create a folder and name it Responses inside the Http folder of your application. Inside, create a RegisterResponse class that extends the FortifyRegisterResponse class.

<?php

namespace App\Http\Responses;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Laravel\Fortify\Contracts\RegisterResponse as RegisterResponseContract;

class RegisterResponse extends FortifyRegisterResponse
{
    /**
     * Create an HTTP response that represents the object.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Symfony\Component\HttpFoundation\Response
     */
    public function toResponse($request)
    {
        return $request->wantsJson()
                    ? new JsonResponse('', 201)
                    : redirect()->intended(config('fortify.home'));
    }
}

Take out everything inside the toResponse method and replace it with code that will first log out the just logged in user by Fortify and then defers to the base class's implementation:

<?php

namespace App\Http\Responses;

use Illuminate\Contracts\Auth\StatefulGuard;
use Laravel\Fortify\Http\Responses\RegisterResponse as FortifyRegisterResponse;

class RegisterResponse extends FortifyRegisterResponse
{
    protected $guard;

    public function __construct(StatefulGuard $guard)
    {
        $this->guard = $guard;
    }

    public function toResponse($request)
    {
        $this->guard->logout();

        return parent::toResponse($request);
    }
}

Fortify's RegisteredUserController accepts a stateful guard implementation on it's constructor. So, we are using the same approach so that the response object receives the same guard instance as that of the controller. Otherwise, we could have used the Auth facade to logout the user.

The final step is to register the implementation in Fortify's service provider's boot method as in the following:

/**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        ...

        $this->app->singleton(
            \Laravel\Fortify\Contracts\RegisterResponse::class,
            \App\Http\Responses\RegisterResponse::class,
        );
    }

And that's all, folks!

Did you enjoy this post?

Sign up for my newsletter to stay up to date.

You will receive monthly updates on my latest articles and products. I do care about the protection of your data. Read my Privacy Policy.