This is an extension to the rodauth
gem which implements the OAuth 2.0 framework for an authorization server.
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.
This gem implements the following RFCs and features of OAuth:
-
oauth
- The OAuth 2.0 protocol framework:- Access Token generation;
- Access Token refresh token grant;
oauth_authorization_code_grant
- Authorization code grant;oauth_implicit_grant
- Implicit grant (off by default);oauth_client_credentials_grant
- Client credentials grant (off by default);oauth_device_code_grant
- Device code grant (off by default);oauth_token_revocation
- Token revocation;oauth_token_introspection
- Token introspection;oauth_pushed_authorization_request
- Pushed Authorization Request;- Authorization Server Metadata;
oauth_pkce
- PKCE;oauth_tls_client_auth
- Mutual-TLS Client Authentication;oauth_jwt
- JWT Access Tokens;oauth_jwt_secured_authorization_request
- JWT Secured Authorization Request;oauth_jwt_secured_authorization_response_mode
- JWT Secured Authorization Response_mode;oauth_resource_indicators
- Resource Indicators;- Access Type (Token refresh online and offline);
-
oauth_assertion_base
- Assertion Framework;oauth_saml_bearer_grant
- SAML 2.0 Bearer Assertion;oauth_jwt_bearer_grant
- JWT Bearer Assertion;
-
oauth_dpop
- OAuth 2.0 Demonstrating Proof-of-Possession at the Application Layer (DPoP); -
oauth_dynamic_client_registration
- Dynamic Client Registration Protocol and Dynamic Client Registration Management; -
OAuth application and token management dashboards;
-
The recommendations for Native Apps;
It also implements several components of OpenID Connect on top of the OAuth features it provides, including:
oidc
- OpenID Connect Core;oidc_self_issued
- Self-Issued OpenID Provider- OpenID Multiple Response Types;
- OpenID Connect Discovery;
oidc_dynamic_client_registration
- OpenID Connect Dynamic Client Registration;oidc_session_management
- Session Management;oidc_rp_initiated_logout
- RP Initiated Logout;oidc_frontchannel_logout
- Frontchannel Logout;oidc_backchannel_logout
- Backchannel Logout;
This gem supports also rails (via rodauth-rails, which also dictates the versioning policy).
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
- How to use rodauth-oauth with rails and rodauth
- How to use rodauth-oauth with rails and without rodauth
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
Just check our example applications.
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 (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.
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 for more info about HTML templating).
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.
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
In this section, the non-standard features are going to be described in more detail.
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
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
.)
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.
If you're interested in using this library with rails, be sure to check rodauth-rails
policy, as it supports rails 5.2 upwards.
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.
Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/os85/rodauth-oauth.