Skip to content

yegor256/glogin

Repository files navigation

DevOps By Rultor.com We recommend RubyMine

rake PDD status Gem Version Maintainability Test Coverage Yard Docs Lines of code Hits-of-Code License

This simple gem will help you enable login/logout through GitHub OAuth for your web application. This is how it works with Sinatra, but you can do something similar in any framework.

Read this blog post to get the idea: Simplified GitHub Login for a Ruby Web App

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

require 'glogin'
configure do
  set :glogin, GLogin::Auth.new(
    # Make sure their values are coming from a secure
    # place and are not visible in the source code:
    client_id, client_secret,
    # This is what you will register in GitHub as an
    # authorization callback URL:
    'http://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.
        secret
      ).to_user
    rescue GLogin::Codec::DecodingError => _
      # Nothing happens here, the user is not logged in.
      cookies.delete(:glogin)
    end
  end
end

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

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

If the secret is an empty string, the encryption will be disabled.

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:
    secret
  ).to_s
  redirect to('/')
end

Finally, we need a logout URL:

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

It is recommended to provide the third "context" parameter to GLogin::Cookie::Closed and GLogin::Cookie::Open constructors, in order to enforce stronger security. The context may include the User-Agent HTTP header of the user, their IP address, and so on. When anything changes on the user side, they will be forced to re-login.

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 will be coming from the cookie will be trusted. For testing it will be convenient to provide a user name in a query string, like:

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

To enable that, it's recommended to 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 and 0pdd web apps (both open source), on top of Sinatra.

Also, you can use GLogin::Codec just to encrypt/decrypt a piece of text:

require 'glogin/codec'
codec = GLogin:Codec.new('the secret')
encrypted = codec.encrypt('Hello, world!')
decrypted = codec.decrypt(encrypted)

How to contribute

Read these guidelines. Make sure you build is green before you contribute your pull request. You will need to have Ruby 2.3+ and Bundler installed. Then:

$ bundle update
$ bundle exec rake

If it's clean and you don't see any error messages, submit your pull request.