2 years ago

A future note to self about Omniauth

Every time I try to set up Omniauth on a Rails codebase I run into the same issue:

Not found. Authentication passthru

And every time I have to spend a fair amount of time understanding what’s causing the error.

Luckiy it won’t have anymore after writing this note for my future self.

Besides the standard steps to set up Omniauth and Omniauth GitHub, we need to add omniauth-rails_csrf_protection to bring CSRF Protection to the requests that are sent from the authentication pages. After adding the dependency to the Gemfile, we need to add a new initializer, omniauth.rb, to allow sending POST requests from the Omniauth links:

OmniAuth.config.allowed_request_methods = [:get, :post]

In that same initializer, we need to set the host to ensure Omniauth passes the right redirection URL when initiating the authentication flow. Otherwise the Omniauth provider might fail due to mismatching URLs:

OmniAuth.config.full_host = "https://myapp.com"

If we generated the Devise views under our project’s app/views directory, we can notice that the Omniauth links are already configure to be POST in the _links.html.erb file:

 <%= link_to("Sign in with #{OmniAuth::Utils.camelize(provider)}",
       omniauth_authorize_path(resource_name, provider),
       { method: :post }) %>

And last but not least, we need to instruct Omniauth on what to do once the authentication flow has finished. We do that by configuring a controller in the routes.rb:

Rails.application.routes.draw do
  # Devise
  devise_for :users, controllers: { omniauth_callbacks: "users/omniauth_callbacks" }
end

In the controller each provider is represented by a method with the same name of the provider. Note that the request’s env attribute provides all the user metadata that we need to find or create the user in our database and authenticate them using Devise’s sign_in_and_redirect method:

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def github
    @user = ... # Create the user

    if @user.persisted?
      sign_in_and_redirect(@user, event: :authentication)
    else
      data = auth_data.except("extra")
      session["devise.oauth.data"] = data
      redirect_to(new_user_registration_url)
    end
  end

  def failure
    redirect_to(root_path)
  end

  def auth_data
    request.env["omniauth.auth"]
  end
end

And that should be it. I hope this is also useful for other users running into similar issues with the Gem.

About Pedro Piñera

I created XcodeProj and Tuist, and co-founded Tuist Cloud. My work is trusted by companies like Adidas, American Express, and Etsy. I enjoy building delightful tools for developers and open-source communities.