Rails 7のアプリにAuth0を利用したユーザー認証を搭載
はじめに
私がRailsでアプリを開発する時は、Deviseでユーザー認証の機能を作成するか、OmniAuthでソーシャルログインを利用することがほとんどでした。Deviseでも適切にユーザー認証を管理していれば大丈夫だと思うのですが、将来的にMFA対応が必要となる可能性もありそうなアプリがあり、今回はAuth0を採用することにしました。
ライブラリのインストール
Gemfile
に必要となるライブラリを追加して、bundle
コマンドを実行してインストールします。
gem "omniauth-auth0"
gem "omniauth-rails_csrf_protection"
% bundle
Auth0でアプリケーションを作成して設定
Auth0でアプリケーションを作成します。アプリケーションの種類にはRegular Web Applications
を選択します。アプリケーションが作成されたら、Allowed Callback URLs
にhttp://localhost:3000/auth/auth0/callback
を追加しておきます。
EDITOR=vi rails credentials:edit
を実行してClient ID
とClient Secret
を保存します。
auth0:
domain: ******.**.auth0.com
client_id: ********
client_secret: ****************
omniauth.rbを作成します。
Rails.application.config.middleware.use OmniAuth::Builder do
provider :auth0,
Rails.application.credentials.auth0.client_id,
Rails.application.credentials.auth0.client_secret,
Rails.application.credentials.auth0.domain,
callback_path: "/auth/auth0/callback",
scope: "openid email"
OmniAuth.config.on_failure =
Proc.new { |env| OmniAuth::FailureEndpoint.new(env).redirect_to_failure }
end
scope
にはopenid email
を指定しました。name
nickname
picture
を利用する場合はprofile
も指定します。
ユーザーモデルとセッションコントローラーの作成
ユーザーモデル
% rails g model User provider:string uid:string email:string
class User < ApplicationRecord
def self.find_or_create_from_auth(auth)
provider = auth[:provider]
uid = auth[:uid]
self.find_or_create_by(provider: provider, uid: uid) do |user|
user.email = auth[:info][:email]
end
end
end
セッションコントローラー
% rails g controller sessions
class SessionsController < ApplicationController
def create
user = User.find_or_create_from_auth(request.env["omniauth.auth"])
session[:user_id] = user.uid
redirect_to request.env["omniauth.origin"] || root_url
end
def destroy
reset_session
request_params = {
returnTo: root_url,
client_id: Rails.application.credentials.auth0.client_id,
}
redirect_to URI::HTTPS.build(
host: Rails.application.credentials.auth0.domain,
path: "/v2/logout",
query: request_params.to_query,
).to_s,
allow_other_host: true
end
def failure
redirect_to root_url
end
end
ルーティングを追加します。
get "/auth/:provider/callback", to: "sessions#create"
get "/auth/failure", to: "sessions#failure"
get "/sign_out", to: "sessions#destroy"
アプリ全体で利用するメソッドの作成
application_controller.rb
にメソッドを追加します。Deviseのメソッド名と同じようにしてみました。
class ApplicationController < ActionController::Base
helper_method :current_user, :user_signed_in?
private
def authenticate_user!
redirect_to root_path unless session[:user_id]
end
def current_user
return unless session[:user_id]
@current_user ||= User.find_by(uid: session[:user_id])
end
def user_signed_in?
!!session[:user_id]
end
end
動作確認
ログインとログアウトの状態に応じて表示するボタンを切り替える例です。
<% if user_signed_in? %>
<%= link_to "Sign out", sign_out_path, data: { turbo: false } %>
<% else %>
<%= button_to "Sign in", "/auth/auth0", method: :post,
data: { turbo: false } %>
<% end %>
before_action
にauthenticate_user!
を指定して、ログインしているときのみ表示する例です。
class ContentsController < ApplicationController
before_action :authenticate_user!
end
おわりに
Rails 7のアプリでAuth0を利用したユーザー認証ができるようになりました。次はAuth0のAPIを利用して、Rails側の操作に応じたAuth0のデータ管理をしていきたいと思います。
参考
Discussion