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

alchermd's avatar

After registration, users are redirected to the login page. Help me debug?

I'm not really sure what's tripping my code up. I've bootstrapped my authentication with php artisan make:auth, and then customized the RegisterController to fit my multi-model setup.

Let's say my app has two models: Student and Company that both extend the User model. I'd like my app to login both of these models. For now, as the title states, I'm able to register new Students, but wasn't able to log them in. My RegisterController (stripped of comments):

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Validation\Rule;
use Illuminate\Http\Request;
use App\Student;
use App\Company;

class RegisterController extends Controller
{
    use RegistersUsers;

    protected $redirectTo = '/home';

    public function __construct()
    {
        $this->middleware('guest');
    }


    public function register(Request $request)
    {
        $this->validator($request->all())->validate();

        $guard = $request->_account_type;
        $user = $this->create($request->all());

        auth()->guard($guard)->login($user);
        
        dd(auth()->user()); // returns null.

        return redirect($this->redirectPath());
    }


    protected function validator(array $data)
    {
        if ($data['_account_type'] == 'student') {
            return Validator::make($data, [
                'name' => 'required|string|max:255',
                'email' => 'required|string|email|max:255|unique:students',
                'password' => 'required|string|min:6|confirmed',
                'school' => 'required|string',
                'course' => [
                    'required',
                    Rule::in(app()->get('courses')),
                ],
                'address' => 'required|string|min:10',
                'contact_number' => 'required|min:7',
            ]);
        }

        if ($data['_account_type'] == 'company') {
            return Validator::make($data, [
                'name' => 'required|string|max:255',
                'email' => 'required|string|email|max:255|unique:companies',
                'password' => 'required|string|min:6|confirmed',
                'school' => 'required|string',
                'field' => [
                    'required',
                    Rule::in(app()->get('courses')),
                ],
                'address' => 'required|string|min:10',
                'contact_number' => 'required|min:7',
            ]);
        }

        return back()->withErrors('Invalid account type.');
    }


    protected function create(array $data)
    {
        if ($data['_account_type'] == 'student') {
            return Student::create([
                'name' => $data['name'],
                'email' => $data['email'],
                'password' => Hash::make($data['password']),
                'school' => $data['school'],
                'course' => $data['course'],
                'address' => $data['address'],
                'contact_number' => $data['contact_number'],
            ]);
        }

        if ($data['_account_type'] == 'company') {
            return Company::create([
                'name' => $data['name'],
                'email' => $data['email'],
                'password' => Hash::make($data['password']),
            ]);
        }
    }
}

Note that in the register method, a call to dd(auth()->user()); returns null even after the attempt to log the student in with auth()->guard($guard)->login($user);.

Any hints? Or maybe I should provide more info?

0 likes
18 replies
Cronix's avatar

This is not a good approach. Just use the users table with an account_type field or something to differentiate the type of user (or use roles, etc). You can use all of the same fields and have them all in the user table but just set the ones that are not common to both account types to nullable, so a company wouldn't store the school, etc.

alchermd's avatar

@Cronix wouldn't that make a massive User class if I ever need to add another account type in the future? I've heard that approach before, but I've also seen different models used (which makes more sense to me) for authentication. I'm not really sure which way to go.

Cronix's avatar

Not really. I mean, fields that have a null value don't take up any space.

This is really what user roles are for. The user is just a user, so the common data should be in a single table. I'd suggest looking at this: https://github.com/spatie/laravel-permission

alchermd's avatar

I would really want a native Laravel solution. I'm really conflicted right now, so I guess I'd try the roles approach too just to see how it works. But really, what I'm trying to do in my original post is possible, right?

Vilfago's avatar

As you can have different guard, it's possible. But I agree witjh @Cronix, a table user is for user. And it's better to work with roles/groups or anything else afterwards to differentiate them.

For your case, I think the middleware check only with the default guard. As they aren't logged with the default, they cannot access /home (for default laravel), so they're back to login. So you have to update your midlleware to fit your logic, if you want to stay this way.

Snapey's avatar

if you dd() in the login controller then the session is not written to and the user is not logged in when they go to the next page

try not to dd when writing to session

alchermd's avatar

@Snapey The dd() is not present on the code, sorry for the confusion. I mean if it is it wouldn't even redirect to the login page anyway since the execution died at that point :D

Cronix's avatar

In the 20+ years of writing apps, I've never needed to. A user is a user, but a user can have roles/permissions to do different things. You can also have a profile table or something and load that via a relationship depending on what kind of user (role) they are. There are many ways really. I've just never seen a good argument for having different tables for different types of users and it just adds unnecessary complexity, imo.

What if you want to show all users? You'd have to query as many tables as you have for different user types to get that, vs getting users with role of student. Yes, what if you add a new type of user? Then you'd have a lot of reworking to do vs creating a new role (in a single table) and just assigning users to that role.

1 like
Snapey's avatar

I would echo @cronix. They are all users... why make work hard for your self.

Anyway, you say that new students are created in the database?

Does your student model implement the authenticatable contract?

The given object must be an implementation of the Illuminate\Contracts\Auth\Authenticatable contract. Of course, the App\User model included with Laravel already implements this interface:

Vilfago's avatar

Just in case, if you use dump($var); to see some information in the process, your login will fail.

I never understood why, but good to know.

alchermd's avatar

Hey guys one last thing: if I'd just use the App\User class with a account_type field, how would I setup belongTo and hasMany relationships between the account_types?

Cronix's avatar

Are you sure a user will only ever have only one account type, or could they have multiple?

alchermd's avatar

@Cronix a user could either be a Student or a Company, at least from the start. I can see having an Admin role or different payment tiers in the future. Anyway, my current setup is having a role_id for a User which is connected to a Role model (seems cleaner than hard coding strings as a value for a role field).

Cronix's avatar

Then it sounds like a hasOne relationship (one to one). A user has one role, and a role can belongTo a user. https://laravel.com/docs/5.6/eloquent-relationships#one-to-one

Personally, I'd set it up so a user can have many roles (one to many), even if you just start with one role per user. Then you can easily grow without a lot of rewriting.

alchermd's avatar

Isn't that backwards? The app can have many students and companies. A one to one relationship means that there is only one student and one company, no? The way I set it up is that a User belongs to a Role, and a Role has many Users.

Cronix's avatar

Yes, but you're saying a user will have only one role. That's 1:1. It doesn't matter how many companies and students there are. Those are the roles (there's only 2 roles), but a user will only be either a student, or a company.

users
-id
-role_id
-name
-email
-etc

roles
-id
-name

Please or to participate in this conversation.