Rodauth::Oauth

This is an extension to the rodauth gem which implements the OAuth 2.0 framework for an authorization server.

Features

This gem implements the following RFCs and features of OAuth:

It also implements the OpenID Connect layer (via the openid feature) on top of the OAuth features it provides, including:

This gem supports also rails (through rodauth-rails).

Installation

Add this line to your application’s Gemfile:

gem 'rodauth-oauth'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install rodauth-oauth

Resources

| | | | ————- | ———————————————————– | | Website | honeyryderchuck.gitlab.io/rodauth-oauth/ | | Documentation | honeyryderchuck.gitlab.io/rodauth-oauth/rdoc/ | | Wiki | gitlab.com/honeyryderchuck/rodauth-oauth/wikis/home | | CI | gitlab.com/honeyryderchuck/rodauth-oauth/pipelines |

Articles

Usage

This tutorial assumes you already read the documentation and know how to set up rodauth. After that, integrating roda-auth will look like:

plugin :rodauth do
  # enable it in the plugin
  enable :login, :oauth
  oauth_application_default_scope %w[profile.read]
  oauth_application_scopes %w[profile.read profile.write]
end

# then, inside roda

route do |r|
  r.rodauth

  # public routes go here
  # ...
  # here you do your thing
  # authenticated section is here

  rodauth.require_authentication

  # oauth will only kick in on ce you call #require_oauth_authorization

  r.is "users" do
    rodauth.require_oauth_authorization # defaults to profile.read
    r.post do
      rodauth.require_oauth_authorization("profile.write")
    end
    # ...
  end

  r.is "books" do
    rodauth.require_oauth_authorization("books.read", "books.research")
    r.get do
      # ...
    end
  end
end

For OpenID, it’s very similar to the example above:

plugin :rodauth do
  # enable it in the plugin
  enable :login, :oidc
  oauth_application_default_scope %w[openid]
  oauth_application_scopes %w[openid email profile]
end

Example (TL;DR)

Just check our example applications.

Database migrations

You have to generate database tables for accounts, oauth applications, grants and tokens. In order for you to hit the ground running, {here’s a set of migrations (using sequel) to generate the needed tables}[https://gitlab.com/honeyryderchuck/rodauth-oauth/-/tree/master/test/migrate] (omit the first 2 if you already have account tables, and follow recommendations from rodauth accordingly).

You can change column names or even use existing tables, however, be aware that you’ll have to define new column accessors at the rodauth plugin declaration level. Let’s say, for instance, you’d like to change the oauth_grants table name to access_grants, and it’s code column to authorization_code; then, you’d have to do the following:

plugin :rodauth do
  # enable it in the plugin
  enable :login, :oauth
  # ...
  oauth_grants_table "access_grants"
  oauth_grants_code_column "authorization_code"
end

If you’re starting from scratch though, the recommendation is to stick to the defaults.

HTML views

You’ll have to generate HTML templates for the Oauth Authorization form.

The rodauth default setup expects the roda render plugin to be activated; by default, it expects a views directory to be defined in the project root folder. The Oauth Authorization template must be therefore defined there, and it should be called oauth_authorize.(erb|str|...) (read the {roda render plugin documentation}[http://roda.jeremyevans.net/rdoc/classes/Roda/RodaPlugins/Render.html] for more info about HTML templating).

OAuth applications management

This feature is optional, as not all authorization servers will want a full oauth applications dashboard. However, if you do and you don’t want to do the work yourself, you can set it up in your roda app like this:

route do |r|
  r.rodauth
  # don't forget to authenticate to access the dashboard
  rodauth.require_authentication
  rodauth.oauth_applications
  # ...
end

Navigate to "http://your-app/oauth-applications" and click around.

Rails

Support for rails is achieved thanks to rodauth-rails. Therefore, the first step you’ll have to take is to add it to your dependencies.

You’ll have to run the generator task to create the necessary migrations and views:

> bundle exec rails generate rodauth:oauth:install
# create a migration file, db/migrate(*_create_rodauth_oauth.rb);
# Oauth Application, Grant and Token models into app/models;
> bundle exec rails generate rodauth:oauth:views
# copies default view files into app/views/rodauth

You are encouraged to check the output and adapt it to your needs.

You can then enable this feature in lib/rodauth_app.rb and set up any options you want:

# lib/roudauth_app.rb
enable :oauth
# OAuth
oauth_application_default_scope "profile.read"
oauth_application_scopes %w[profile.read profile.write books.read books.write]

Now that you’re set up, you can use the rodauth object to deny access to certain subsets of your app/API:

class BooksController < ApplicationController
  before_action :allow_read_access, only: %i[index show]
  before_action :allow_write_access, only: %i[create update]

  def index
    # ...
  end

  def show
    # ...
  end

  def create
    # ...
  end

  def update
    # ...
  end

  private

  def allow_read_access
    rodauth.require_oauth_authorization("books.read")
  end

  def allow_write_access
    rodauth.require_oauth_authorization("books.write")
  end
end

Features

In this section, the non-standard features are going to be described in more detail.

Token / Secrets Hashing

Although not human-friendly as passwords, for security reasons, you might not want to store access (and refresh) tokens in the database. If that is the case, You’ll have to add the respective hash columns in the table:

# in migration
String :token_hash, null: false, token: true
String :refresh_token_hash, token, true
# and you DO NOT NEED the token and refresh_token columns anymore!

And declare them in the plugin:

plugin :rodauth do
  enable :oauth
  oauth_tokens_token_hash_column :token_hash
  oauth_tokens_token_hash_column :refresh_token_hash

Client Secret

By default, it’s expected that the “client secret” property from an OAuth application is only known by the owner, and only the hash is stored in the database; this way, the authorization server doesn’t know what the client secret is, only the application owner. The provided OAuth Applications Extensions application form contains a “Client Secret” input field for this reason.

However, this extension is optional, and you might want to generate the secrets and store them as is. In that case, you’ll have to re-define some options:

plugin :rodauth do
  enable :oauth
  secret_matches? ->(application, secret){ application[:client_secret] == secret }
end

Internationalization (i18n)

rodauth-oauth supports translating all user-facing text found in all pages and forms, by integrating with rodauth-i18n. Just set it up in your application and rodauth configuration.

Default translations shipping with rodauth-oauth can be found in this directory. If they’re not available for the languages you’d like to support, consider getting them translated from the english text, and contributing them to this repository via a Merge Request.

(This feature is available since v0.7.)

Ruby support policy

The minimum Ruby version required to run rodauth-oauth is 2.3 . Besides that, it should support all rubies that rodauth and roda support, including JRuby and truffleruby.

Rails

If you’re interested in using this library with rails, be sure to check rodauth-rails policy, as it supports rails 5.2 upwards.

Development

After checking out the repo, run bundle install to install dependencies. Then, run rake test to run the tests, and rake rubocop to run the linter.

Contributing

Bug reports and pull requests are welcome on Gitlab at gitlab.com/honeyryderchuck/rodauth-oauth.