README.md

README.md
Last Update: 2024-11-29 16:14:00 +0000

Rodauth::Oauth

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

Certification

<img width=“184” height=“96” align=“right” src=“/openid-certified.jpg” alt=“OpenID Certification”>

rodauth-oauth is certified for the following profiles of the OpenID Connect™ protocol:

  • Basic OP

  • Implicit OP

  • Hybrid OP

  • Config OP

  • Dynamic OP

  • Form Post OP

  • 3rd Party-Init OP

  • Session Management OP

  • RP-Initiated Logout OP

  • Front-Channel Logout OP

  • Back-Channel Logout OP

The certifications were obtained using the example OIDC server deployed here.

Features

This gem implements the following RFCs and features of OAuth:

It also implements several components of OpenID Connect on top of the OAuth features it provides, including:

This gem supports also rails (via rodauth-rails, which also dictates the versioning policy).

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/os85/rodauth-oauth/wikis/home
CI gitlab.com/os85/rodauth-oauth/pipelines

Articles

Usage

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

plugin :rodauth do
  # enable it in the plugin
  enable :login, :oauth_authorization_code_grant
  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
      @books = Book.where(user_id: rodauth.current_oauth_account[:id]).all
      # ...
    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_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/os85/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_authorization_code_grant
  # ...
  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_authorization_code_grant
# OAuth
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

Access tokens, refresh tokens and client secrets are hashed before being stored in the database (using bcrypt), by default.

Disabling this behaviour is a matter of nullifying the hash column option:

plugin :rodauth do
  enable :oauth_authorization_code_grant

  # storing access token, refresh token and client secret in plaintext:
  oauth_grants_token_hash_column nil
  oauth_grants_refresh_token_hash_column nil
  oauth_applications_client_secret_hash_column nil

If you’d like to replace the hashing function (for, let’s say, argon2), you’ll need to perform the following overrides:

plugin :rodauth do
  enable :oauth_authorization_code_grant

  secret_matches? { |oauth_application, secret| Argon2::Password.verify_password(secret, oauth_application[oauth_applications_client_secret_hash_column]) }
  secret_hash { |secret| Argon2::Password.create(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.5 . 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/os85/rodauth-oauth.