Rails engine allowing apps to act as their own OAuth 2.1 provider. The goal of this project is to make standards-based authorization as simple as possible.
TokenAuthority is simple to install and configure. For MCP server developers, see the MCP Quickstart guide for a complete working example.
Add this line to your application's Gemfile:
gem "token_authority"Install the gem, generate the required set-up files, and run the migration:
$ bundle
$ bin/rails generate token_authority:install
$ bin/rails db:migrateSee the Installation Guide for generator options and custom configurations.
Configure TokenAuthority in the generated initializer. TokenAuthority is configured with dynamic client registration, client metadata documents, and resource indicators enabled by default. The following represents a minimal configuration:
# config/initializers/token_authority.rb
TokenAuthority.configure do |config|
# The secret key used for signing JWT tokens
config.secret_key = Rails.application.credentials.secret_key_base
# Define available scopes (required by default)
config.scopes = {
"read" => "Read your data",
"write" => "Create and modify your data"
}
# Define protected resources (required by default)
# :resource is used as the audience (aud) claim in tokens
# :authorization_servers provides the issuer (iss) claim
config.resources = {
api: {
resource: "https://example.com/api",
resource_name: "My API",
scopes_supported: %w[read write],
authorization_servers: ["https://example.com"],
bearer_methods_supported: ["header"],
jwks_uri: "https://example.com/.well-known/jwks.json",
resource_documentation: "https://example.com/docs/api",
resource_policy_uri: "https://example.com/privacy",
resource_tos_uri: "https://example.com/terms"
}
}
endSee the Configuration Reference for all available options.
Add the engine routes to your config/routes.rb:
Rails.application.routes.draw do
token_authority_auth_server_routes
token_authority_protected_resource_route
endThis exposes:
- RFC 8414 Authorization Server Metadata at
/.well-known/oauth-authorization-server - RFC 9728 Protected Resource Metadata at
/.well-known/oauth-protected-resource - OAuth endpoints at
/oauth/authorize,/oauth/token, etc.
To mount the engine at a different path, use the at option:
Rails.application.routes.draw do
token_authority_auth_server_routes(at: "/auth")
token_authority_protected_resource_route
endFor applications with multiple protected resources, each resource must be on its own subdomain. This is because RFC 9728 defines a fixed well-known path (/.well-known/oauth-protected-resource) that can only exist once per host:
Rails.application.routes.draw do
token_authority_auth_server_routes
constraints subdomain: "api" do
token_authority_protected_resource_route
end
constraints subdomain: "mcp" do
token_authority_protected_resource_route
end
endDevelopment Note: Rails subdomain constraints require a real domain with proper DNS resolution. Use
lvh.me(which resolves to127.0.0.1) for local development:mcp.lvh.me:3000,api.lvh.me:3000, etc. You'll also need to allow these hosts in your development config:# config/environments/development.rb config.hosts << /.*\.lvh\.me/See the Installation Guide for details.
Before issuing authorization codes, TokenAuthority displays a consent screen where users can approve or deny access to OAuth clients. The consent views are fully customizable and the layout is configurable—see Customizing Views for details.
The consent screen requires user authentication. Your authenticatable_controller must provide two methods:
authenticate_user!- Ensures the user is logged in (redirects to login if not)current_user- Returns the authenticated user
If you use Devise, these methods are already available on ApplicationController. For other authentication systems, see User Authentication.
Use the TokenAuthentication concern to validate access tokens:
class Api::V1::UsersController < ActionController::API
include TokenAuthority::TokenAuthentication
before_action :require_read_scope
def current
render json: { id: token_user.id, email: token_user.email }
end
private
def require_read_scope
return if token_scope.include?("read")
render json: { error: "insufficient_scope" }, status: :forbidden
end
endThe concern automatically validates the access token on every request and provides:
token_user- Returns the authenticated usertoken_scope- Returns an array of scope tokens (e.g.,["read", "write"]), or[]if no scopes
See Protecting API Endpoints for error handling details.
TokenAuthority emits structured events using Rails 8.1's event reporting system for monitoring, debugging, and auditing. Events cover the full OAuth lifecycle:
- Authorization requests and consent
- Token exchanges, refreshes, and revocations
- Client and token authentication
- Security events (e.g., token theft detection)
Event logging is enabled by default. Events are automatically logged to Rails.logger:
[TokenAuthority] token_authority.authorization.request.received client_id="..." client_type="public" ...
[TokenAuthority] token_authority.token.exchange.completed client_id="..." user_id=42 session_id=1 ...
[TokenAuthority] token_authority.security.token.theft_detected client_id="..." user_id=42 ...
See Event Logging for the full event reference and custom subscriber examples.
TokenAuthority emits ActiveSupport::Notifications instrumentation events for performance monitoring. These events provide timing data that APM tools (New Relic, Datadog, Skylight) automatically capture.
Instrumentation is enabled by default. Events are automatically logged to Rails.logger:
[TokenAuthority::Instrumentation] token_authority.session.create (15.2ms)
[TokenAuthority::Instrumentation] token_authority.jwt.encode (0.4ms) token_size=312
[TokenAuthority::Instrumentation] token_authority.client.resolve (0.5ms) client_type="registered"
See Instrumentation for the full event reference and custom subscriber examples.
- Installation Guide - Generator options, custom table names
- Configuration Reference - All configuration options
- User Authentication - Custom authentication setups
- Protecting API Endpoints - Error handling, validation details
- Customizing Views - Styling consent screens
- Event Logging - Structured events for monitoring
- Instrumentation - Performance monitoring with ActiveSupport::Notifications
Clone the repository and install dependencies:
git clone https://github.com/dickdavis/token-authority.git
cd token-authority
bundle installSet up git hooks:
bundle exec lefthook installRun the test suite:
bundle exec rspecRun the linter:
bundle exec standardrbGenerate documentation:
bundle exec yardFor manual testing with the dummy app, see Manual Testing.
- Update the version number in
lib/token_authority/version.rb - Commit the version change:
git commit -am "Bump version to X.Y.Z" - Run the release task:
rake release
This will create a git tag, push the tag to GitHub, and publish the gem to RubyGems.
Bug reports and pull requests are welcome on GitHub at https://github.com/dickdavis/token-authority.
The gem is available as open source under the terms of the MIT License.