# Github Signup

{% embed url="<https://youtu.be/YIJ6ybDlFAk>" %}
Tutorial for adding github authentiaciton to Lightning Rails
{% endembed %}

## Install Github authentication Gem

The first step will be to install the [omniauth Github gem.](https://github.com/omniauth/omniauth) In our Gemfile, let's add

```ruby
gem 'omniauth'
gem 'omniauth-rails_csrf_protection'
gem 'omniauth-github'
```

As usual, we will bundle

```
bundle install
```

As we wish to have our users sign up with Github, we must let devise know. Let's go into the initializers/devise.rb file and add this line:

```ruby
# config/initializers/devise.rb

# ==> OmniAuth
  config.omniauth :github, ENV["GITHUB_ID"], ENV["GITHUB_SECRET"], scope: 'user,public_repo'
  
```

## Create a Github OAuth App

Now that we have done some config, we can see that we are missing the API keys that will connect our app to GitHub. Unlike Google OAuth, Github is very easy to create.

* [ ] **Create** a new app [here.](https://github.com/settings/applications/new)
* [ ] Add your authentication code if required.
* [ ] **Give your application the name** "My Super Cool App Development"
* [ ] **Give a Homepage URL:** <http://localhost:3000/> (we will create a second OAuth app for production and real domain)
* [ ] Add an application description for your users
* [ ] Add exactly this URL as app callback: <http://localhost:3000/users/auth/github/callback> (we will change it for the production environment)
* [ ] Save and add your logo if you have one

You will see that you have a CLIENT ID but still need to generate a new secret key, so let's do it by clicking "Generate a new client secret".

## Add keys to .env

Copy the Secret key and add it to your .env file along with the client ID:

```
# .env

# modify with your keys
GITHUB_ID=Ov23*********
GITHUB_SECRET=3cc73c***********************
```

## Routes

Now that we have a good config, we'll need to activate new routes, and replace the existing `devise_for :user` by this line:

```ruby
# routes.rb

devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
```

## Controller

Let's create that new controller we added to the routes, in the terminal run:

```
mkdir app/controllers/users
```

And&#x20;

```
touch app/controllers/users/omniauth_callbacks_controller.rb
```

Now in our brand new controller file, we will add the GitHub OmniAuth logic:

```ruby
# app/controllers/users/omniauth_callbacks_controller.rb

class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def github
      @user = User.from_omniauth(request.env['omniauth.auth'])

      if @user.persisted?
        sign_in_and_redirect @user, event: :authentication
        flash[:notice] = I18n.t 'devise.omniauth_callbacks.success', kind: 'Github'
      else
        session['devise.github_data'] = request.env['omniauth.auth'].except('extra')
        redirect_to new_user_registration_url, alert: @user.errors.full_messages.join("\n")
      end
  end
end
```

## Model

After adding the proper routes and controller action we will need to activate the Omniauth option from devise. In `user.rb` uncomment and add the following symbols to the devise options:

```ruby
# models/user.rb
class User < ApplicationRecord
    # Include default devise modules. Others available are:
    # :confirmable, :lockable, :timeoutable, :trackable
    
    devise :database_authenticatable, :registerable,
           :recoverable, :rememberable, :validatable, 
           :omniauthable, omniauth_providers: [:github] # <- The new options
   # [...]
 end
```

We will also add the Omniauthable custom method:

```ruby
# models/user.rb
class User < ApplicationRecord
  # has_one_attached :avatar <- Uncomment If you want to attach a picture from github
  # [...]
  
  def self.from_omniauth(access_token)
    data = access_token.info
    user = User.where(email: data['email']).first
    if user
       user.update(
          # Optional: You can create a migration for users to add GitHub username and name to the user instance.
          # github_username: data['nickname'], 
          # name: data['name'], 
          email: data['email']
       )
    else
        user = User.create(
           # Optional: You can create a migration for users to add GitHub username and name to the user instance.
           # github_username: data['nickname'],
           # name: data['name'],
           email: data['email'],
           password: Devise.friendly_token[0,20]
        )
    end
     # Optional: Uncomment for adding avatar image from github, make sure you have a cloudinary API_KEY in your .env
     # user.avatar.purge if user.avatar.attached?
     # user.avatar.attach(io: URI.open(data['image']), filename: 'avatar.jpg', content_type: 'image/jpg')
    user
  end
end
```

## Views

Let's add the GitHub signup to the sessions/new file. I like to add it to the login instead of the signup as to not lose the before\_action :authenticate\_user! auto-redirect function. As our code either updates or creates. You can now ignore the signup page and unlink it from all the buttons on your page.

```erb
#app/views/sessions/new.html.erb

# [...] 

# Add this code where you want the GitHub sign in button
<%- if devise_mapping.omniauthable? %>
  <%- resource_class.omniauth_providers.each do |provider| %>
    <%= button_to omniauth_authorize_path(resource_name, provider), data: { turbo: false }, class: "btn btn-primary mt-12" do %>
    <svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 opacity-70" viewBox="0 0 24 24"><path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/></svg>
      Sign in with Github<br />
     <% end %>
     <small class="text-xs text-gray-500">Your Github Username to receive an automatic invite to LightningRails repo.</small>
  <% end %>
<% end %>

# [...]
```

## In Production

To have this code work on production as well as on development, you will need to create a second Github app and follow these steps again:

* [ ] **Create** a new app [here.](https://github.com/settings/applications/new)
* [ ] Add your authentication code if required.
* [ ] **Give your application the name** "My Super Cool App Production"
* [ ] **Give a Homepage URL:** <https://yourdomain.com> (we will create a second OAuth app for production and real domain)
* [ ] Add an application description for your users
* [ ] Add exactly this URL as app callback: <https://yourdomain.com/users/auth/github/callback> (change this domain to your final live domain)
* [ ] Save and add your logo if you have one

Now you should have two GitHub apps. One for development and one for production.

The only step left will be to add the production ID and key to Heroku from your terminal:\
\&#xNAN;*(replace the API key by your actual production API key and ID)*

<pre><code><strong>heroku config:set GITHUB_SECRET=YOUR_API_KEY
</strong></code></pre>

And&#x20;

```
heroku config:set GITHUB_ID=YOUR_GITHUB_ID
```

Et voila! You have a brand-new GitHub authentication setup.&#x20;

Your techy users will thank you! 🙏

***

{% hint style="info" %}
Common Errors 🐞:&#x20;

* Omniauthable is undefined: Did you restart your server after installing the Omniauthable Gem? If not do it an it should get fixed.
* Must supply API\_KEY: Are you adding avatars without a Cloudinary key in your .env file? That's probably the cause, head to Cloudinary, and add your API key in the .env file.
  {% endhint %}
