【Rails・Next.js】devise-token-authによるログイン認証 Part1

# はじめに
`Rails7`・`Next.js13`環境での、`devise-token-auth`によるログイン認証について手順について説明します。
今回は**Part1**ということで、`devise-token-auth`の導入までをまとめてみました。

# 開発環境
- Ruby on Rails APIモード 7.0.8
- Next.js 13.4
- Docker
- MySQL

# devise-token-authとは

`Rails API`モードにおいて、認証機能を持ったモデルを実装できる`gem`です。

https://github.com/lynndylanhurley/devise_token_auth

# devise-token-authの初期設定

```ruby:Gemfile
 gem "devise"
 gem "devise-i18n"
 gem "devise_token_auth"
```
`devise`をインストールします。

```ruby
rails g devise:install
```

`User`モデルを`devise_token_auth`に用いるモデルとして登録します。

```ruby
rails g devise_token_auth:install User auth
```
```ruby
rails db:migrate
```

`users`テーブルが正常に作成されていることを確認します。

```ruby:schema.rb
ActiveRecord::Schema[7.0].define(version: 2023_12_12_071155) do
  create_table "users", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
    t.string "provider", default: "email", null: false
    t.string "uid", default: "", null: false
    t.string "encrypted_password", default: "", null: false
    t.string "reset_password_token"
    t.datetime "reset_password_sent_at"
    t.boolean "allow_password_change", default: false
    t.datetime "remember_created_at"
    t.string "confirmation_token"
    t.datetime "confirmed_at"
    t.datetime "confirmation_sent_at"
    t.string "unconfirmed_email"
    t.string "name"
    t.string "nickname"
    t.string "image"
    t.string "email"
    t.text "tokens"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["confirmation_token"], name: "index_users_on_confirmation_token", unique: true
    t.index ["email"], name: "index_users_on_email", unique: true
    t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true
    t.index ["uid", "provider"], name: "index_users_on_uid_and_provider", unique: true
  end

end

```
次に`devise-token-auth`用のルーティングを追加します。

```ruby:routes.rb
  Rails.application.routes.draw do
    namespace :api do
      namespace :v1 do
        get "health_check", to: "health_check#index"
        mount_devise_token_auth_for "User", at: "auth"
      end
    end
  end
```

# メール認証への対応
今回は`letter_opener_web`を用いたメール認証をする為、作成されているモデルに対して`:confirmable`オプションを追加します。

```ruby:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable
  include DeviseTokenAuth::Concerns::User
end
```

# DisabledSessionErrorの回避

Rails7系の場合、認証時に`ActionDispatch::Request::Session::DisabledSessionError`が発生してしまいます。

これは、**APIのようにセッションを使用しない場合には、セッションへのアクセスがあるとエラーを発生させる仕組みがRails7から備わったことによるエラー**です。

`devise`を使った場合、内部的にセッションにアクセスしている為、該当のエラーが発生してしまいます。

エラー回避するために、こちらの[issue](https://github.com/heartcombo/devise/issues/5443)を参考に設定を行います。

```ruby:pp/controllers/concerns/devise_hack_fake_session.rb
module DeviseHackFakeSession
  extend ActiveSupport::Concern

  class FakeSession < Hash
    def enabled?
      false
    end

    def destroy
    end
  end

  included do
    before_action :set_fake_session

    private

      def set_fake_session
        if Rails.configuration.respond_to?(:api_only) && Rails.configuration.api_only
          request.env["rack.session"] ||= ::DeviseHackFakeSession::FakeSession.new
        end
      end
  end
end
```

`concerns`にモジュールを作成したら、`application_controller.rb`で`include`します。

```ruby:app/controllers/application_controller.rb
  class ApplicationController < ActionController::API
    include DeviseTokenAuth::Concerns::SetUserByToken
    include DeviseHackFakeSession
  end
```



https://github.com/heartcombo/devise/issues/5443



https://blog.furu07yu.com/entry/rails7-devise-token-auth#ActionDispatchRequestSessionDisabledSessionErrorについて

# おわりに
**Part1**はここまでです。お疲れ様でした。