マストドンでログインをRailsで実装する
はじめに
omniauth-mastodonというgemを使ってマストドンでログインをRailsで実装する手順についてまとめました。また、ベースとなっているomniauthで必要な項目についても触れています。
omniauth-mastodon
インストール
# Gemfile
gem 'mastodon-api', require: 'mastodon'
gem 'omniauth-mastodon'
gem 'omniauth'
モデルの作成
後述する設定で使用するモデルを作成します。
$ rails generate model MastodonClient domain:string client_id:string client_secret:string
設定
マストドンはtwitter等と違ってドメインの異なる複数のインスタンスが存在します。twitterの場合は別途設定画面からアプリケーションを登録してその情報を使用するのですが、マストドンでは動的に取得してDBに保持します。
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :mastodon, scope: 'read write follow', credentials: lambda { |domain, callback_url|
Rails.logger.info "Requested credentials for #{domain} with callback URL #{callback_url}"
existing = MastodonClient.find_by(domain: domain)
return [existing.client_id, existing.client_secret] unless existing.nil?
client = Mastodon::REST::Client.new(base_url: "https://#{domain}")
app = client.create_app('OmniAuth Test Harness', callback_url, 'read write follow')
MastodonClient.create!(domain: domain, client_id: app.client_id, client_secret: app.client_secret)
[app.client_id, app.client_secret]
}
end
本家のREADMEでは
app = client.create_app('OmniAuth Test Harness', callback_url, 'read write follow')
に'read write follow'
の指定はありませんが、省略したままだと
invalid_scope: 要求されたアクセス権は無効であるか、不明、または不正なフォーマットです。
のエラーとなります。また、第4引数として@param website [String]
を渡すこともできます。認証済みアプリ一覧にWebsiteへのリンクを貼ることが出来ますので必要に応じてWebsiteのアドレスを入れます。
/auth/mastodon
にアクセスするとマストドンでログインが始まります。
omniauth
設定
ここではUser
モデルに保持する想定です。まずルーティングの設定をします。
# config/roues.rb
get '/auth/:provider/callback', to: 'sessions#create'
マストドンでログインが完了した時に返ってくる画面になります。
実装
# app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
def create
@user = User.find_or_create_from_auth(request.env['omniauth.auth'])
self.current_user = @user
redirect_to '/'
end
end
# app/models/user.rb
class User < ApplicationRecord
def self.find_or_create_from_auth(auth)
provider = auth[:provider]
uid = auth[:uid]
token = auth[:credentials].token
self.find_or_create_by(provider: provider, uid: uid) do |user|
user.token = token
end
end
end
認証情報を登録するための最低限の実装例です。
追記
マストドンでログイン実装後に発覚した問題について以下の記事にまとめています。