🐈

RailsでつくるOpenID Provider 入門

に公開

Rails でつくる OpenID Provider 入門

はじめに

こんにちは、Rails エンジニアの 安田 です。業務で OpenID Provider(OP) をゼロから試作する機会がありました。ただ、当初は OAuth 2.0OpenID Connect(OIDC) に触れたことがなく、その概念の多さに圧倒されました。

そこで、実際に手元で動く プロトタイプ版 OP を構築してみると、特に「認可コードフロー」や「ID トークン」の流れをスムーズに理解できました。本記事では、その体験を基に Rails で “理解用プロトタイプ” を構築する手順を紹介します。

⚠️ 注意事項

本稿は学習用に 最小限の実装 を示します。秘密鍵管理や HTTPS、PKCE 強制など、実運用で必須となるセキュリティ対策は割愛しています。実環境に導入する際は必ず最新のベストプラクティスを参照してください。


1. 概念整理

1‑1 OpenID Connect(OIDC)とは?

  • OAuth 2.0 を拡張し、ユーザーの 認可(リソースアクセス可否)に加えて 認証(誰がログインしたか)の結果を ID トークン として提供する仕様。

1‑2 OpenID Provider(OP)

  • アクセストークンや ID トークンを発行するサーバー。今回の記事で構築する対象です。

1‑3 Relying Party(RP)

  • OP に認可/認証を委譲し、返されたトークンを用いてサービスを提供するクライアント。

2. 実装

2‑1 動作環境 & 依存 Gem

ソフトウェア / Gem バージョン 役割
Ruby 3.4.3
Rails 8.0.2 Web アプリケーションフレームワーク
devise 4.9.4 ユーザー認証(ログイン)
doorkeeper 5.8.2 OAuth 2.0 Provider
doorkeeper‑openid_connect 1.8.11 OIDC 拡張

2‑2 セットアップ手順

Step 1 devise 導入(ユーザー認証)

OIDCのユーザー認証用にRailsではよく使われている、deviseを使います。

rails generate devise:install     # 初期設定
rails generate devise User        # User モデル生成
rails db:migrate

Step 2 Doorkeeper 導入(OAuth 2.0 サーバー)

Oauth2 Provider として、Doorkeeperを導入します。他にも候補はありましたが、ドキュメントが一番充実していたので採用しています。

rails generate doorkeeper:install
rails generate doorkeeper:migration
rails db:migrate

Step 3 doorkeeper‑openid_connect 導入(OIDC 拡張)

OpenID Provider としてDoorkeeper を使うために、doorkeeper-openid_connectを使います。

rails generate doorkeeper:openid_connect:install
rails generate doorkeeper:openid_connect:migration
rails db:migrate

署名鍵を固定で用意

署名鍵を設定します。今回はID トークンの検証はスコープ外としているので、適当な固定値が入っていれば問題ありません。

# サンプル: 2048bit RSA 鍵を生成
openssl genrsa -out config/jwt_rsa.pem 2048
# config/initializers/doorkeeper_openid_connect.rb
Doorkeeper::OpenidConnect.configure do
  signing_key File.read(Rails.root.join("config/jwt_rsa.pem"))
end

Step 4 devise と Doorkeeper の連携

DoorKeepr のモデルを Devise の Userモデルと紐付けます。

# app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable

  has_many :access_grants,
           class_name:  'Doorkeeper::AccessGrant',
           foreign_key: :resource_owner_id,
           dependent:   :delete_all
  has_many :access_tokens,
           class_name:  'Doorkeeper::AccessToken',
           foreign_key: :resource_owner_id,
           dependent:   :delete_all
end

Doorkeeperのユーザー認証にdeviseを使うようにします。

認可リクエストが来たら

  1. 未ログインならログイン画面へリダイレクト

  2. ログイン済みならそのまま同意画面へ遷移

    という流れになります。

# config/initializers/doorkeeper.rb
resource_owner_authenticator do
  current_user || warden.authenticate!(scope: :user)
end

Step 5 OIDC 用スコープ

OIDC用のスコープを追加します。認証時にscopeとしてopenidを受け取れるようになり、OIDCが使えるようになります。

# config/initializers/doorkeeper.rb
Doorkeeper.configure do
  default_scopes :openid           # OIDC は必須
end

Step 6 保護リソース(API) の作成

テスト用のエンドポイントを作成します。OIDCで得たアクセストークンがあるとアクセスできるエンドポイントです。

# app/controllers/credentials_controller.rb
class CredentialsController < ApplicationController
  before_action :doorkeeper_authorize!

  def me
    render json: current_resource_owner
  end

  private

  def current_resource_owner
    User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
  end
end

Step 7 ルーティング

Doorkeeper, devise のエンドポイントを追加します。

# config/routes.rb
Rails.application.routes.draw do
  use_doorkeeper
  use_doorkeeper_openid_connect 
  devise_for :users

  get :me, to: 'credentials#me'
end

Step 8 クライアントアプリ登録

Rails console で実行して、クライアントを登録しておきます。

Doorkeeper::Application.create!(
  name:         'test_app',
  uid:          'test_uid',
  redirect_uri: 'http://localhost:4000/callback', # ローカル開発用
  scopes:       'openid',
  confidential: false
)

3. 動作確認

以下では 認可コードフロー を試します。ブラウザ / cURL の 2 ステップで完了します。

3‑1 認可コード取得

ブラウザで以下にアクセスし、ログイン→同意するとリダイレクト先 URI に code= が付与されます。

http://localhost:3000/oauth/authorize?response_type=code&client_id=test_uid&redirect_uri=http://localhost:4000/callback&scope=openid

3‑2 アクセストークン & ID トークン取得

curl -X POST http://localhost:3000/oauth/token \
  -F grant_type=authorization_code \
  -F client_id=test_uid \
  -F code=<ブラウザで得た code> \
  -F redirect_uri=http://localhost:4000/callback

レスポンスとして、アクセストークン、ID トークンが得られます。アクセストークンの有効期限はdoorkeeper のデフォルト値が設定されています。

{
  "access_token": "kiYNazG5XWBcLv...",
  "token_type":   "Bearer",
  "expires_in":   7200,
  "scope":        "openid",
  "id_token":     "eyJ0eXAiOiJKV1QiLCJraWQiOiJC..."
}

ここでは、ID トークンの検証はしません

3‑4 保護リソースへアクセス

取得したアクセストークンで保護リソースにアクセスします。

curl -H "Authorization: Bearer <access_token>" \
     -H "Content-Type: application/json" \
     http://localhost:3000/me

このエンドポイントでは、ユーザー情報を取得できれば成功です。

{
  "id": 1,
  "email": "user1@example.com",
  "created_at": "2025-02-27T05:37:38.177Z",
  "updated_at": "2025-02-27T05:37:38.177Z"
}

これで OP の動作を確認できました。

4. 振り返り

OIDC は OAuth 2.0 に「誰がログインしているか」という認証機能を加えた拡張仕様で、ID トークンを介してユーザー情報を安全に伝達できます。Rails では devise(ログイン)、doorkeeper(OAuth 2.0)、doorkeeper-openid_connect(OIDC)の 3 つの Gem だけで OP を構築できます。ただし、運用する際は鍵管理や HTTPS の導入、PKCE の必須化、トークン検証といったセキュリティ対策を必ず入れましょう。

最後までお読みいただきありがとうございました!

We are hiring!

ブルーモでは、次世代の金融プロダクトを一緒に開発する仲間を募集中です。興味のある方はぜひ採用ページもご覧ください。

https://careers.bloomo.co.jp/

ブルーモ証券 プロダクトチームブログ

Discussion