Assign a password to new users when they sign up through 3rd party account

Image for post
Image for post

In my Rails app, there are two ways to sign up a new user in my app: the traditional one that you provide password and email, and the one that you use the third party account, which is Google account here in my app. In the building of the second route, I came across a validation issue, and the way I fixed it is by assigning a password to the user when it is created in the database. Here’s how I did it.

Ominauth

So to implement the second feature, I use Ominauth. Omniauth is a Gem in rails that offers another way to authenticate a user’s identity. Here in my app on the Login page, you see a button that says “Login with Google”. Once you click it, Google would usually ask if you want to authorize this operation of the website accessing your information to create a user in their database( or if you haven’t already logged in your Google account, you will be asked to log in first). Once you agree, a user is created in the database with the personal information sent by Google and you will usually be redirected to the page when you are logged in.

Problem

To make sure a user provides a password and an email when signing up, I put validations for User model. Therefore, if an attempt to sign up a user without providing both of those two items, it will fail.

It is not too difficult when a form is provided to capture a password and an email. However, it is hard when I use Omniauth.

The good thing of Omniauth is, it is just one “agree” button away before you can sign up. It is very fast because it saves you a lot of trouble filling out a form. On the other side, the bad thing is, how can a user tell the database what the password is if there is not even a form?

Solution

At first, I was looking for a way to validate two ways of signing up differently. For example, ask for a password ONLY in the traditional route to sign up. But after I talk to one of my instructors, he told me better not to do that because a password is very important, and therefore, we should never give a roundabout route to skip setting up a password.

He gave me a suggestion on changing the corresponding action to create a user through third party accounts, which is, new_from_google action in Sessions Controller here.

It looks like this before:

def new_from_google
auth = request.env['omniauth.auth']['info']
@user = User.find_or_create_by(email: auth['email'])
if @user.persisted?
session[:user_id] = @user.id
redirect_to user_path(@user)
else
@user.name = auth['name']
end
end

The key lies in the assignment statement: @user = User.find_or_create_by(email: auth['email']). The method find_or_create_by accepts a block and would pass the params to create if a user is not found.

I change it in the following way. When a user with that specific email cannot be found, the block including a password will be passed to create a new user and the problem is solved! And next time, when the same user wants to log in, a google account’s presence is enough.

def new_from_google
auth = request.env['omniauth.auth']['info']
@user = User.find_or_create_by(email: auth['email']) do |u|
u.name = auth['name']
u.password = "superhardpassword"
end
if @user.persisted?
session[:user_id] = @user.id
redirect_to user_path(@user)
else
@user.name = auth['name']
end
end

Of course, you can also provide a way for the user to change their password later, just in case they want to log in using the email/password combination. Thanks for reading!

Web Developer | Ruby | Rails | SQL | Sinatra | React | Redux | HTML&CSS | JavaScript| MERN LinkedIn:https://www.linkedin.com/in/yingqi-chen/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store