2

I'm trying to implement login from google functionality in my Rails API.

I added this line to my device.rb

config.omniauth :google_oauth2, Rails.application.credentials.dig(:google, :google_client_id),
  Rails.application.credentials.dig(:google, :google_client_secret), scope: 'userinfo.email,userinfo.profile' 

I also added client id & secret in my credentials.

Here is my Google function

def google
    @user = User.from_omniauth(request.env["omniauth.auth"])
end

Here is my from_omniauth function from User.rb

def self.from_omniauth(auth)
  where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
    user.provider = auth.provider
    user.uid = auth.uid
    user.email = auth.info.email
    user.password = Devise.friendly_token[0,20]
  end
end

As I'm implementing an API, I don't know should I use request.env["omniauth.auth"] or hardcode the Access-token here I got from OAuthPlayground. If I hardcode the token how can I access the user information from that token?

I'm also using Devise for Authentication in my application, following this tutorial: https://www.digitalocean.com/community/tutorials/how-to-configure-devise-and-omniauth-for-your-rails-application

Stack Overflown
  • 672
  • 7
  • 21
Humayun Naseer
  • 440
  • 7
  • 18

2 Answers2

5

Hope you are fine.

Finally, I got the solution as I was confused that how can I fetch the data from the token_id I receive from the front end, as sending name and email from the front end is not the valid way as anyone can change it and can register himself with the wrong name and email.

After this add gem Httparty into your Gemfile.

You will get this token_id from the front-end by google or you can get this by Google-OAuthplayground for testing purposes & can test it by the postman.

Now add Function in users Controller

require 'httparty'                                                             
require 'json'                                                                                                                  
class UsersController < ApplicationController                              
  include HTTParty

     def google_oauth2
       url = "https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=#{params["id_token"]}"                  
       response = HTTParty.get(url)                   
       @user = User.create_user_for_google(response.parsed_response)      
       tokens = @user.create_new_auth_token                      
       @user.save
       render json:@user
     end
    end

or by get user info with access_token you can replace URL with

url = "https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=#{params["access_token"]}"

And add the following function into your User.rb

def self.create_user_for_google(data)                  
  where(uid: data["email"]).first_or_initialize.tap do |user|
    user.provider="google_oauth2"
    user.uid=data["email"]
    user.email=data["email"]
    user.password=Devise.friendly_token[0,20]
    user.password_confirmation=user.password
    user.save!
  end
end  

Now just hit the URL From postman & I hope everything will be working fine. if you have any query just comment, please.

Note: This solution is just for the backend side while Creating Rails API.

Humayun Naseer
  • 440
  • 7
  • 18
  • I think calling the token endpoint is only for debugging purposes and not to be used in production. The docs state this - "An easy way to validate an ID token signature for debugging is to use the tokeninfo endpoint. Calling this endpoint involves an additional network request that does most of the validation for you while you test proper validation and payload extraction in your own code. It is not suitable for use in production code as requests may be throttled or otherwise subject to intermittent errors.". i think you're better off using one of the gems to do this – JamesR Jan 17 '23 at 10:21
  • it is not recommended to send tokens as URI query-string parameters, because URI parameters can end up in log files that are not completely secure. Instead, it is better to send the token in HTTP Authorization request header. – Nathaniel Feb 19 '23 at 13:03
0

At this point @user = User.from_omniauth(request.env["omniauth.auth"]) after user is created OR found you need to generate JWT access token (for APIs) based on user data or login_user(@user) if you use sessions.

Here is a nice tutorial for JWT if you go with headless rails

or

Here us the link to Device gem that could provide you with login_user(@user) functionality

Video tutorial about oauth

Tim Kozak
  • 4,026
  • 39
  • 44
  • Thank you but as my work is just at the backend side so how can I get the user information in request.env["omniauth.auth"] – Humayun Naseer Nov 10 '20 at 10:38
  • this flow is used for user registration. after a user is created you can create additional endpoints to access the information along with the request you should pass the generated access token to authenticate the request. – Tim Kozak Nov 10 '20 at 10:50
  • sorry im a learning this should i pass that token here User.from_omniauth(token) instead of request.env["omniauth.auth"] – Humayun Naseer Nov 10 '20 at 11:43
  • this may help http://railscasts.com/episodes/241-simple-omniauth-revised?autoplay=true – Tim Kozak Nov 10 '20 at 17:26