Great tutorial, but I have some comments on the bad practices I’ve noticed.
A common practice I’ve noticed is storing the
provider inside the
users table. Well, this is a bad practice, because a user can have accounts on multiple social networks, but this technique can only store one.
A better practice is to keep the social network accounts in a different table, as you did. But you SHOULD NEVER give such a specific name to a table. Your tutorial shows that you should create a
social_facebook_accounts table. You can see that Socialite provides drivers for Twitter, Github, Google+, etc. If I was to follow your pattern, I would have
social_google_accounts if I wanted my users to be able to log in with all of these 4 platforms. This is crazy! More than that, I would have to create 4 different models, one for each table. Does this sound like a good pattern? I doubt it. Also, if my table is named
social_facebook_accounts, what’s the purpose of that
A better approach is to create a
social_accounts table with a
SocialAccount model. The table would have the same fields as you explained, but we would make that
provider field work as it should.
(note that I have properly created a foreign key on lines 1 and 2)
That way, we can have:
user_id provider_user_id provider
1 1233123 facebook
1 4asd23314 twitter
1 s1244123 github
Notice how one user (with an id of 1) has 3 different social accounts associated to its account on our platform?
Have you noticed that I have not added a
in(['facebook', 'twitter', ...]) directive to our
provider field? Well, that’s because we want flexibility with that table, and any restrictions will be handled by the PHP itself, not by the database. Anyway, this should not become a general rule.
To properly deal with our
SocialAccount model, we would add local scopes (check https://laravel.com/docs/5.5/eloquent#local-scopes).
One technique would be to add a scope for each of the social networks we’re allowing on our website. But we’re trying to use the best practices here, right?
What if next month we will want to add a LinkedIn login option for our users? We will have to open this model again and add a new scope. This will also make our model “fat”, writing 4 new lines of code for each social network we want to link our accounts to.
A better approach is building our model like this:
class SocialAccount extends Model
public function scopeByProvider($query, $provider)
return $query->where('provider', $provider');
That way we will have one scope that will work for each and every option we want to add.
So when we want to get all of our Facebook accounts, we will do it like so:
Also, always name your routes and never use the url itself while redirecting the user, but rather use the name of the route.
So if in our
web.php file we had this:
In our controllers we will redirect our users like this:
To all writers: please, if you decide to write tutorials so people will learn something from you, make sure you teach them the right things. Making something work is simple. The true challenge in development is properly building something, making it flexible, so it will make your future development of that project easier.