Search code examples
ruby-on-railsreactjsaxioscorsgithub-oauth

How to solve CORS error when redirecting to github omniauth route?


I'm trying to build a simple app that is just using a GitHub login for authentication for now. I am using Rails v5.2.3 for the backend, and React for the frontend. I currently have a button in my Root Component that sends an ajax request to my backend. That request will hit an action in my SessionsController that will redirect to the /auth/github route and begin the GitHub auth cycle.

I believe this is step is where I am getting an error.

My browser console gives me this error message:

Access to XMLHttpRequest at 'https://github.com/login/oauth/authorize?
client_id=db494fb7eadbc0c6129d&redirect_uri=http%3A%2F%2Flocalhost%3A3000%2Fauth%2Fgithub%2Fcallback&resp
onse_type=code&state=79557eda02a2340f9c02b5254f053528314ea750704690ae' (redirected from 
'http://localhost:3000/authenticate/github') from origin 'http://localhost:3000' has been blocked by CORS
 policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Here are some files that I believe are relevant:

Gemfile

source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

ruby '2.5.1'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.2.3'
# Use postgresql as the database for Active Record
gem 'pg', '>= 0.18', '< 2.0'
# Use Puma as the app server
gem 'puma', '~> 3.11'
# Use SCSS for stylesheets
gem 'sass-rails', '~> 5.0'
# Use Uglifier as compressor for JavaScript assets
gem 'uglifier', '>= 1.3.0'
# See https://github.com/rails/execjs#readme for more supported runtimes
# gem 'mini_racer', platforms: :ruby

# Use CoffeeScript for .coffee assets and views
gem 'coffee-rails', '~> 4.2'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

gem 'omniauth-github', github: 'omniauth/omniauth-github', branch: 'master'
gem 'figaro'
gem 'rack-cors'

# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', '>= 1.1.0', require: false

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
end

group :development do
  # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
  gem 'web-console', '>= 3.3.0'
  gem 'listen', '>= 3.0.5', '< 3.2'
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
  gem 'better_errors'
  gem 'binding_of_caller'
  gem 'pry-rails'
end

group :test do
  # Adds support for Capybara system testing and selenium driver
  gem 'capybara', '>= 2.15'
  gem 'selenium-webdriver'
  # Easy installation and use of chromedriver to run system tests with Chrome
  gem 'chromedriver-helper'
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]

routes.rb

Rails.application.routes.draw do  
  get '/authenticate/:type', to: 'sessions#authenticate'
  get '/auth/:provider/callback', to: 'sessions#create'
  
  root to: 'static_pages#root'
end

initializers/github.rb

Rails.application.config.middleware.use OmniAuth::Builder do
    provider :github, ENV['GITHUB_KEY'], ENV['GITHUB_SECRET']
end

sessions_controller.rb

class SessionsController < ApplicationController
    def authenticate
        redirect_to '/auth/github' if params[:type] == 'github'
    end

    def create
        @user = User.find_or_create_from_oauth(auth_params)

        if @user
            render json: @user
        else
            render json: [params['error']], status: 422
        end
    end

    private

    def auth_params
        request.env['omniauth.auth']
    end
end

root.jsx

import React, { useState } from 'react';
import axios from 'axios';

const Root = () => {

    const [name, setName] = useState('no name yet');

    const githubLogin = () => {
        axios.get('authenticate/github')
            .then(user => setName(user.name));
    }

    return (
        <div>
            <button onClick={githubLogin}>Github Login</button>
            <h1>Name: {name}</h1>
        </div>
    )
}

export default Root;

After a little research I saw some recommendations of adding the rack-cors gem. I tried doing that and added this initializer.

initializers/cors.rb

Rails.application.config.middleware.insert_before 0, Rack::Cors do
    puts 'setting up cors'
  allow do
    origins '*'
    resource '*', headers: :any, methods: [:get, :post, :patch, :put]
  end
end

I'm pretty new when it comes to setting up oauth and am trying to figure it out, but this has me stumped. I'm not sure if my redirect is getting the Headers it needs to not get blocked, and I'm sure on where to go from here.

Any help would be appreciated. Please let me know if there is any other info that I can provide. Thank you.


Solution

  • You're getting the error because redirect happens in the context of the XHR.

    One solution would be to make XHR to your controller and it would return a URL the client has to follow to.

    Another would be to not make an XHR and use a plain link to your action.

    Either way, you should make sure that you don't request GitHub URL from JS. It has to be a plain HTTP(s) request.