I'm using Devise (4.7.1) and omniauth-google-oauth2 (0.8.0) within a Rails 5.2 demo app to handle 3rd party sign ups. I can sign in correctly with seeded data and create new users no problem. But, when I try to use the "sign in with Google OAuth2.0" button it doesn't work. It routes my back to the root, which is part of the callback controller action.
I've been looking into various guides on the web regarding CSRF failures and invalid credentials being used. I have fixed these problems, but am now left with this one which has confounded me. The error I get is:
User Load (0.6ms) SELECT "users".* FROM "users" WHERE "users"."provider" = ? AND "users"."uid" = ? ORDER BY "users"."id" ASC LIMIT ? [["provider", "google_oauth2"], ["uid", "106922203178875367517"], ["LIMIT", 1]]
↳ app/models/user.rb:21
(0.1ms) begin transaction
↳ app/models/user.rb:21
User Exists (0.7ms) SELECT 1 AS one FROM "users" WHERE "users"."email" = ? LIMIT ? [["email", ""], ["LIMIT", 1]]
↳ app/models/user.rb:21
(0.1ms) rollback transaction
It seems as though the action of creating the new user starts, but is stopped due to there not being an Email within the params hash generated by the callback uri.
The params hash looks like this:
Parameters: {"state"=>"XXXXXXXXXXX", "code"=>"XXXXXXXXXXX", "scope"=>"email profile https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile openid", "authuser"=>"0", "prompt"=>"consent"}
My User model looks like this:
class User < ApplicationRecord
has_many :comments
has_many :books, through: :comments
validates :email, uniqueness: true
# validates :first_name, presence: {message: "Please enter your first name"}
# validates :last_name, presence: {message: "Please enter your surname"}
validates :encrypted_password, presence: true
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable, :omniauthable, :omniauth_providers => [:google_oauth2]
def self.from_omniauth(auth)
# Either create a User record or update it based on the provider (Google) and the UID
where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
user.token = auth.credentials.token
user.expires = auth.credentials.expires
user.expires_at = auth.credentials.expires_at
user.refresh_token = auth.credentials.refresh_token
end
end
end
And the callbacks controller looks like this:
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
skip_before_action :verify_authenticity_token
def google_oauth2
@user = User.from_omniauth(request.env["omniauth.auth"])
if @user.persisted?
sign_in @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Google") if is_navigational_format?
else
session["devise.google_data"] = request.env["omniauth.auth"]
end
redirect_to '/'
end
end
Any help/ guidance on this will be hugely appreciated as I'm a bit stumped right now.
Thanks :)
From what I see your code, you're creating user without email, but you have this validation validates :email, uniqueness: true
which won't work if you try to create 2 accounts.
Could you verify this? User.where(email: "").count
and let me know. I think if it's more than 0, you can't register.
Either remove email uniqueness validation or try to get email from the auth params.
You can debug with printing the error logs in the callback controller
if @user.persisted?
sign_in @user, :event => :authentication #this will throw if @user is not activated
set_flash_message(:notice, :success, :kind => "Google") if is_navigational_format?
else
Rails.logger.info(@user.errors.full_messages)
session["devise.google_data"] = request.env["omniauth.auth"]
end