Getting No route matches [GET] "/auth/google_oauth2" error while trying to authenticate with Gmail API in rails

Viewed 1225

I am Getting No route matches [GET] "/auth/google_oauth2" error while trying to authenticate with Gmail API in rails.

by following this article https://www.twilio.com/blog/2014/09/gmail-api-oauth-rails.html, i am implementing the Gmail API integration.

code seems to be corrrect. But dont know what was the issue.

in routes file:

  root to: 'visitors#index'
  if defined?(Devise)
    devise_for :users, :controllers => { :registrations => "registrations", :passwords => "passwords", omniauth_callbacks: 'omniauth_callbacks' }
    devise_scope :user do
      get 'auth/:provider/callback', :to => 'users/omniauth_callbacks#facebook'
    end
  end
  get "/auth/:provider/callback" => "candidates#authenticate_from_google"

in rake routes, i even have the route as well.

GET /auth/:provider/callback(.:format)  candidates#authenticate_from_google

  

in Gemfile :-

gem "omniauth"
gem "omniauth-linkedin"
gem "jwt", "~> 1.4.1"
gem "linkedin-scraper", "~> 0.1.5"
gem "omniauth-facebook"
gem "omniauth-google-oauth2"
gem 'signet' 
gem 'google-api-client', '0.8.2'

in views

   <%= link_to("Sync", "/auth/google_oauth2" , class: "btn btn-sm btn-primary", method: :get)%>

in /app/controllers/candidates_controller.rb

   def authenticate_from_google
    @auth = request.env['omniauth.auth']['credentials']
    if @auth
      @identity = current_user.identities.new
      @identity.provider = "google_oauth2"
      @identity.access_token = @auth['token']
      @identity.refresh_token = @auth['refresh_token']
      @identity.expires_at = Time.at(@auth['expires_at']).to_datetime
      @identity.save
      flash[:notice] = "Successfully Authenticated from Google"
    else
      flash[:notice] = "Google Authentication failed"
    end
    redirect_to account_path
  end

in /config/initializers/omniauth.rb

  Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, ENV['GOOGLE_API_KEY'], ENV['GOOGLE_SECRET_KEY'], {
  scope: ['email',
    'https://www.googleapis.com/auth/gmail.send'],
    access_type: 'offline'}
end

in /config/initializers/devise.rb

Devise.setup do |config|

  config.omniauth :linkedin, ENV['LINKEDIN_API_KEY'], ENV['LINKEDIN_SECRET_KEY']
  config.omniauth :facebook, ENV['FACEBOOK_API_KEY'], ENV['FACEBOOK_SECRET_KEY'] ,
              :info_fields => 'email,name,first_name,last_name,verified', :display => 'page', :scope => 'email'

   config.omniauth :google_oauth2, ENV['GOOGLE_API_KEY'],
                               ENV['GOOGLE_SECRET_KEY'],
                               scope: 'email,https://www.googleapis.com/auth/gmail.send',
                               access_type: 'offline'#, :prompt => "select_account",
                                skip_jwt: true
    config.timeout_in = 7.days
end
3 Answers

For omniauth gem >= 2.0.0 you must specify which request methods you are going to allow in your link button.

<%= link_to("Sync", "/auth/google_oauth2" , class: "btn btn-sm btn-primary", method: :get)%>

Just add the line OmniAuth.config.allowed_request_methods = [:post, :get]

# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  OmniAuth.config.allowed_request_methods = [:post, :get]
  provider :google_oauth2, ENV['GOOGLE_API_KEY'], ENV['GOOGLE_SECRET_KEY'], {
  scope: ['email',
    'https://www.googleapis.com/auth/gmail.send'],
    access_type: 'offline'}
end

Change your config/initializers/onmiauth.rb file with below code.

Rails.application.config.middleware.use OmniAuth::Builder do
  provider :google_oauth2, ENV['GOOGLE_CLIENT_ID'], 
  ENV['GOOGLE_CLIENT_SECRET']
end

OmniAuth.config.allowed_request_methods = %i[get]

Since omniauth 2.0 you must use POST method for /auth/:provider endpoint, not GET, see upgrade notes.

So the proper way to handle this is:

  1. Change login link in template to use POST
link_to 'Login with Facebook', '/auth/facebook', rel: 'nofollow', method: :post
  1. Add omniauth-rails_csrf_protection gem to your Gemfile
gem 'omniauth-rails_csrf_protection'
  1. Adjust tests
  before { OmniAuth.config.test_mode = true }

  it 'redirects to callback url' do
    token = SecureRandom.base64(ActionController::RequestForgeryProtection::AUTHENTICITY_TOKEN_LENGTH)
    allow_any_instance_of(ActionDispatch::Request).to receive(:session) { { _csrf_token: token } }

    post '/auth/facebook', params: { authenticity_token: token }
    expect(response).to redirect_to('/auth/facebook/callback')
  end

That's it!

You will get this warning if you set allowed_request_methods to %i[get] as other answers here suggest:

You are using GET as an allowed request method for OmniAuth. This may leave
  you open to CSRF attacks. As of v2.0.0, OmniAuth by default allows only POST
  to its own routes. You should review the following resources to guide your
  mitigation:
  https://github.com/omniauth/omniauth/wiki/Resolving-CVE-2015-9284
  https://github.com/omniauth/omniauth/issues/960
  https://nvd.nist.gov/vuln/detail/CVE-2015-9284
  https://github.com/omniauth/omniauth/pull/809
Related