This is a mobile version, full one is here.

Yegor Bugayenko
19 June 2018

Simplified GitHub Login for a Ruby Web App

You know what OAuth login is, right? It’s when your users click “login” and get redirected to Facebook, Twitter, Google, or some other website which then identifies them. Then they go back to your website and you know who they are. It’s very convenient for them. It’s convenient for you too, since you don’t need to implement the login functionality and don’t need to keep their credentials in a database. I created a simple Ruby gem to simplify this operation for GitHub only. Here is how it works.

First, you will have to register your application in GitHub, as this page explains. This is how it works with Sinatra, but you can do something similar in any framework.

First, somewhere in the global space, before the app starts:

require 'glogin'
configure do
  set :glogin, GLogin::Auth.new(
    # You get this from GitHub, when you register your
    # web application:
    client_id,
    # Make sure this value is coming from a secure
    # place and is NOT visible in the source code:
    client_secret,
    # This is what you will register in GitHub as an
    # authorization callback URL:
    'https://www.example.com/github-callback'
  )
end

Next, for all web pages we need to parse a cookie, if it exists, and convert it into a user:

require 'sinatra/cookies'
before '/*' do
  if cookies[:glogin]
    begin
      @user = GLogin::Cookie::Closed.new(
        cookies[:glogin],
        # This must be some long text to be used to
        # encrypt the value in the cookie:
        encryption_secret
      ).to_user
    rescue OpenSSL::Cipher::CipherError => _
      # Nothing happens here, the user is not logged in.
      cookies.delete(:glogin)
    end
  end
end

If the glogin cookie comes in and contains valid data, a local variable @user will be set to something like this:

{ login: 'yegor256', avatar: 'http://...' }

Next, we need a URL for GitHub OAuth callback:

get '/github-callback' do
  cookies[:glogin] = GLogin::Cookie::Open.new(
    settings.glogin.user(params[:code]),
    # The same encryption secret that we were using above:
    encryption_secret
  ).to_s
  redirect to('/')
end

Finally, we need a logout URL:

get '/logout' do
  cookies.delete(:glogin)
  redirect to('/')
end

One more thing is the login URL you will need for your front page. Here it is:

settings.glogin.login_uri

For unit testing you can just provide an empty string as a secret for GLogin::Cookie::Open and GLogin::Cookie::Closed and the encryption will be disabled: whatever comes from the cookie will be trusted. For testing it will be convenient to provide a user name in a query string, like this:

http://localhost:9292/?glogin=tester

To enable that, it’s recommended you add this line (see how it works in zold-io/wts.zold.io):

require 'sinatra/cookies'
before '/*' do
  cookies[:glogin] = params[:glogin] if params[:glogin]
  if cookies[:glogin]
    # same as above
  end
end

I use this gem in sixnines, 0pdd, and Zold web apps on top of Sinatra (all open source).