はじめに

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

認証情報を登録するための最低限の実装例です。

追記

マストドンでログイン実装後に発覚した問題について以下の記事にまとめています。

Mastodon API Ruby Gem インストール時の注意点

omniauth-mastodonをForkしてカスタマイズ