🔥

Rails API(devise_token_auth)+Reactでのログイン時のメール本認証(comfirmable)実装

2022/01/24に公開
3

やったこと

  • サインアップページのフォームにメールアドレスとパスワードを入力
  • サインアップページの submit ボタンをクリック
  • 入力したメールアドレスにメールが届く(仮認証)
  • そのメール内のリンクをクリック(本認証)
  • ログインできるようになる

実装手順

Backend

  1. プロジェクト作成
  2. Devise と HTTP 通信用の gem を追加
  3. devise と devise_token_auth をインストール
  4. ログイン機能の設定を変更
  5. API コントローラー作成
  6. ルーティング設定
  7. confirmable を有効にする
  8. .env ファイルを設定
  9. gmail のメールアプリパスワードを取得
  10. メールの設定を追加
  11. API 通信確認

Frontend

  1. プロジェクト作成
  2. 必要パッケージをインストール
  3. API 設定ファイル作成
  4. コンポーネント作成
  5. ログイン状態と非ログイン状態でページを切り分ける
  6. サインアップページ作成
  7. サインインページ作成

API(Rails)

1. プロジェクト作成

terminal
$ rails new api --api
$ cd api
  • Rails のプロジェクト作成をします。api の部分はプロジェクト名になる。

  • --api → API モードで Rails アプリを作成するためのオプションコマンド

2. Devise と HTTP 通信用の gem を追加

Gemfile
# 追加
# Devise
gem 'devise'
gem 'devise_token_auth'
# HTTP通信
gem 'rack-cors'
  • devise
  • devise_token_auth

これは、API 通信でログイン機能を実装するために必要になる。

  • rack-cors

これで、HTTP 通信許可の設定ができる。この gem を追加して、HTTP 通信の設定をすることで、React からのリクエストを許可することができる。

gem をインストールする。

terminal
$ bundle install

3. devise と devise_token_auth をインストール

devise_token_auth を設定していく前に、devise をインストールしておく。手順が逆になるとエラーが出る可能性がある。

  1. devise のインストール
terminal
$ rails g devise:install

上のコマンドを実行すると下記のような表示が返ってくる。

create  config/initializers/devise.rb
      create  config/locales/devise.en.yml
===============================================================================

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:

       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

     In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:

       root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:

       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>

  4. You can copy Devise views (for customization) to your app by running:

       rails g devise:views

===============================================================================
  1. devise_token_auth のインストール
terminal
$ rails g devise_token_auth:install User auth

rails g devise_token_auth:install User auth コマンドで作成された db/migrate/日付_devise_token_auth_create_users.rb
ファイルに示された users テーブルを作成する。

db/migrate/日付_devise_token_auth_create_users.rb
class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.1]
  def change

    create_table(:users) do |t|
      ## Required
      t.string :provider, :null => false, :default => "email"
      t.string :uid, :null => false, :default => ""

      ## Database authenticatable
      t.string :encrypted_password, :null => false, :default => ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at
      t.boolean  :allow_password_change, :default => false

      ## Rememberable
      t.datetime :remember_created_at

      ## Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, :default => 0, :null => false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at

      ## User Info
      t.string :name
      t.string :nickname
      t.string :image
      t.string :email

      ## Tokens
      t.text :tokens

      t.timestamps
    end

    add_index :users, :email,                unique: true
    add_index :users, [:uid, :provider],     unique: true
    add_index :users, :reset_password_token, unique: true
    add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

migrate コマンドで、users テーブルを作成する。

terminal
$ rails db:migrate

4. ログイン機能の設定を変更

まずはログイン時に token を渡してログイン状態を維持するため、token 情報の設定をする。

devise_token_auth.rb を開き、下記の設定を変更する

config/initializers/devise_token_auth.rb

config.change_headers_on_each_request = false # コメントを外してtrueからfalseに変更する

config.token_lifespan = 2.weeks # コメントをはずす

# コメントを外す
config.headers_names = {:'access-token' => 'access-token',
                        :'client' => 'client',
                        :'expiry' => 'expiry',
                        :'uid' => 'uid',
                        :'token-type' => 'token-type' }
  • config.change_headers_on_each_request → true の場合、リクエストごとに token を新しくする必要がある、という設定になる。毎回、毎回、トークンが変更されるという動きは今回は期待していないので、false に変更。

  • token_lifespan → 名前の通り、token の有効期間。今回は、2週間に設定。

  • headers_names → 認証用ヘッダーの名前の定義。必要でない限り、変更する必要はない。

次に、application_controller.rb に設定を追加する。(devise_token_auth をインストールした際に自動で追加されているかも)

app/controllers/application_controller.rb
class ApplicationController < ActionController::API
  # 下記一行を追加
  include DeviseTokenAuth::Concerns::SetUserByToken
end
  • この一文で、SetUserByTokenという拡張機能を使える様になる。これは、Cookie や CORS の設定ができるようになるということ。

次に application.rb に Cookie や CORS の設定をしていく。

config/application.rb
require_relative 'boot'

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "active_storage/engine"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
# require "sprockets/railtie"
# require "rails/test_unit/railtie"

# Require the gems listed in Gemfile, including any gems
# you've limited to :test, :development, or :production.
Bundler.require(*Rails.groups)

module DeviseTokenAuthTwitter
  class Application < Rails::Application
    # Initialize configuration defaults for originally generated Rails version.
    config.load_defaults 5.2

    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration can go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded after loading
    # the framework and any gems in your application.

    # Only loads a smaller set of middleware suitable for API only apps.
    # Middleware like session, flash, cookies can be added back manually.
    # Skip views, helpers and assets when generating a new resource.
    config.api_only = true

    # ここからコピペする
    config.session_store :cookie_store, key: '_interslice_session'
    config.middleware.use ActionDispatch::Cookies # Required for all session management
    config.middleware.use ActionDispatch::Session::CookieStore, config.session_options
    config.middleware.use ActionDispatch::Flash
    config.middleware.insert_before 0, Rack::Cors do
      allow do
        # 今回はRailsのポートが3001番、Reactのポートが3000番にするので、Reactのリクエストを許可するためにlocalhost:3000を設定
        origins 'localhost:3000'
        resource '*',
                 :headers => :any,
                 # この一文で、渡される、'access-token'、'uid'、'client'というheaders情報を用いてログイン状態を維持する。
                 :expose => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
                 :methods => [:get, :post, :options, :delete, :put]
      end
    end
    # ここまで
  end
end

最後に Rails のポート番号がデフォルトで 3000 番になっているのを 3001 番に変更しておく。

config/puma.rb
# 3000→3001に修正
port ENV.fetch("PORT") { 3001 }

5. API コントローラー作成

今回はログイン機能の API とログインユーザー情報取得 API のコントローラーを作成していく。

terminal
$ rails g controller auth/registrations
$ rails g controller auth/sessions

app/controllers/auth/registrations_controller.rbはサインアップ、サインイン、サインアウトを実行する API コントローラー

app/controllers/auth/registrations_controller.rb
# Auth::RegistrationsControllerクラスはDeviseTokenAuth::RegistrationsControllerを継承する
class Auth::RegistrationsController < DeviseTokenAuth::RegistrationsController

  private

  def sign_up_params
    # サインアップ時に登録できるカラムを指定
    params.permit(:email, :password, :password_confirmation)
  end
end

app/controllers/auth/sessions_controller.rbはログイン時のユーザーを取得するための API コントローラー

app/controllers/auth/sessions_controller.rb
class Auth::SessionsController < ApplicationController
    def index
        if current_user
            render json: {is_login: true, data: current_user }
        else
            render json: {is_login: false, message: "ユーザーが存在しません"}
        end
    end
end

6. ルーティング設定

作成したコントローラーを基に、ルーティングを設定していく。

config/routes.rb
Rails.application.routes.draw do
  # ログイン機能のルーティング
  mount_devise_token_auth_for 'User', at: 'auth', controllers: {
    registrations: 'auth/registrations'
  }
  # ログインユーザー取得のルーティング
  namespace :auth do
    resources :sessions, only: %i[index]
  end
end

ルーティングを確認する

$ rails routes

設定したルーティングから考えられる API エンドポイント

  • サインアップ →http://localhost:3001/auth
  • サインイン →http://localhost:3001/auth/sign_in
  • サインアウト →http://localhost:3001/auth/sign_out
  • ログインユーザー取得 →http://localhost:3001/auth/sessions

7. confirmable を有効にする

Confirmable の設定をしていく。

  • confirmable を設定すると、ユーザが新たにアカウント登録すると、登録したメールアドレスにメールが送信され、そのメール内の「アカウント確認」を押すまで本登録が完了しない様にできる。

User テーブルで confirmable を有効にする。

app/models/user.rb
class User < ActiveRecord::Base
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :confirmable # ← confirmableを追加する
  include DeviseTokenAuth::Concerns::User
end

これを追加することで、confirmable を有効にできる。

これは users テーブルを作成するさいに、migration ファイルにあった、confirmable と書いてある部分が有効になるということ。

db/migrate/日付_devise_token_auth_create_users.rb
## Confirmable
t.string   :confirmation_token
t.datetime :confirmed_at
t.datetime :confirmation_sent_at
t.string   :unconfirmed_email # Only if using reconfirmable

8. gmail のメールアプリパスワードを取得

Action Mailer で G メールを利用するには、アプリパスワードを取得する必要がある。

Gmail で2段階認証をオンにし、アプリパスワードを取得する。

https://accounts.google.com/signin/v2/challenge/pwd?continue=https%3A%2F%2Fmyaccount.google.com%2Fapppasswords&service=accountsettings&osid=1&rart=ANgoxccVr9suYl7GzWv-ZjatyHtjXe1QrhYMrXcFNpo0mr31JFPzr_rVIrpf9OlpNrKdD299LUoHkP1NK7-doFdlRwBL0gU8NA&TL=AM3QAYam4TsACWwtCgIK_RPwqjjCCXIMxDUIYi6JxwoTCzGZXOC61mRHG_iOXuxc&flowName=GlifWebSignIn&cid=1&flowEntry=ServiceLogin

取得したパスワードは環境変数に設定するため控えておく。

9. .env ファイルを設定

Rails プロジェクトで env ファイルを使用する際は、以下の gem を追加する必要があります。

Gemfile
group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: [:mri, :mingw, :x64_mingw]
  gem 'dotenv-rails' # 追加する
end
$ bundle install

.envファイルを作成する。

terminal
$ touch .env

この env ファイルを隠しファイルにするために、.gitignoreファイルに.envファイルを追加する。

.gitignore
# 追加
/.env

これで隠しファイルになり、外からは見られなくなった。

そして、Action Mailer で Gmail を利用するための環境変数を.envファイルに記述していく。

.env
EMAIL_ADDRESS=<送信元になる自分のメールアドレス>
EMAIL_PASSWORD=<生成されたアプリのパスワード>

10. メールの設定を追加

devise.rb に mailer の設定を追加

config/initializers/devise.rb
Devise.setup do |config|
  config.mailer_sender = ENV['EMAIL_ADDRESS'] # コメントアウトをはずして変更
  config.mailer = 'Devise::Mailer' # コメントアウトを外す
end

次に、config/environments/development.rbに下記の設定を追加

config/environments/development.rb
Rails.application.configure do
  # 下記を追加
  config.action_mailer.default_options = { from: ENV['EMAIL_ADDRESS'] }
  # hostにはデフォルトでlocalhost3000になっているので、Railsのポート番号である3001に変更する。
  config.action_mailer.default_url_options = { host: 'localhost:3001' }
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address: 'smtp.gmail.com',
    port: 587,
    domain: 'gmail.com',
    user_name: ENV['EMAIL_ADDRESS'],
    password: ENV['EMAIL_PASSWORD'],
    authentication: 'plain',
    enable_starttls_auto: true
  }
end

11. API 通信確認

ポストマンなどで API 通信の確認をしてみる。

サインアップ →POST http://localhost:3001/auth

{
    "email": "送信先のメールアドレス",
    "password": "パスワード",
    "password_confirmation": "パスワード確認",
    "confirm_success_url": "メール内のリンクからのリダイレクト先のURL"
}
  • email→ 送信先のメールアドレスを設定(サインアップ時に入力した際にそのメールアドレスに認証メールが届く)
  • confirm_success_url→ 本認証が完了した際にリダイレクトする URL を指定する。今回のアプリではログインページに遷移するようにするが、フロントはこれから作るので、API 確認の際は適当にhttps://google.comなどと入力しておけばいい。ちゃんとそのページに遷移したら成功ということになる。

サインイン →POST http://localhost:3001/auth/sign_in

{
    "email": "送信先のメールアドレス",
    "password": "パスワード",
}
  • ちゃんとメール内のリンクからリダイレクト先に遷移したら、サインアップ時に指定したメールアドレスとパスワードを指定して、ログインできる。

サインアウト →DELETE http://localhost:3001/auth/sign_out

  • Headers の中に、サインアップ、サインイン時にヘッダー情報に入っていたaccess-token、client、uid情報を入力する。

ログインユーザー取得 →GET http://localhost:3001/auth/sessions

  • サインアウト時と同様、サインアップ、サインイン時にヘッダー情報に入っていたaccess-token、client、uid情報を入力する。

Frontend(React)

1. プロジェクト作成

まずはルートディレクトリに移動して、create-react-appで React プロジェクト作成する。

terminal
$ cd my_app
$ npx create-react-app frontend
$ cd frontend

2. 必要パッケージをインストール

今回のログイン機能に必要なパッケージをインストールしていきます。

terminal
$ npm i axios axios-case-converter react-router-dom@5.2.0 js-cookie
  • axios→HTTP 通信
  • axios-case-converter→axios で受け取ったレスポンスの値をスネークケース → キャメルケースに変換、または送信するリクエストの値をキャメルケース → スネークケースに変換してくれるライブラリ
  • react-router-dom→ ルーティング設定用のライブラリ
  • js-cookie→Cookie を操作するためのライブラリ

axios-case-converter を使う理由は、Rails は Ruby なので、スネークケース(例:password_confirmation)であり、React は JavaScript なので、キャメルケース(例:passwordConfirmation)であり、API で送られてきた Rails 側のデータと React 側のデータの記述を合わせるため。

Cookie を使う理由は、Cookie を操作してaccess-token、client、uidを渡すため。

3. API 設定ファイル作成

API 設定ファイルを作成します。

$ mkdir src/api
$ touch src/api/client.js
$ touch src/api/auth.js

client.jsでルートエンドポイントを設定する。

src/api/client.js
import applyCaseMiddleware from 'axios-case-converter'
import axios from 'axios'

const options = {
    ignoreHeaders: true,
}

const client = applyCaseMiddleware(
    axios.create({
        baseURL: 'http://localhost:3001',
    }),
    options
);

export default client;

auth.jsで、client.js で作成した client を使って、これまで Rails で作成してきた API を設定していく。

src/api/auth.js
import client from "./client";
import Cookies from "js-cookie";

// サインアップ
export const signUp = (params) => {
  return client.post("/auth", params);
};

// サインイン
export const signIn = (params) => {
  return client.post("/auth/sign_in", params);
};

// サインアウト
export const signOut = () => {
  return client.delete("/auth/sign_out", {
    headers: {
      "access-token": Cookies.get("_access_token"),
      client: Cookies.get("_client"),
      uid: Cookies.get("_uid"),
    },
  });
};

// ログインユーザーの取得
export const getCurrentUser = () => {
  if (
    !Cookies.get("_access_token") ||
    !Cookies.get("_client") ||
    !Cookies.get("_uid")
  )
    return;

  return client.get("/auth/sessions", {
    headers: {
      "access-token": Cookies.get("_access_token"),
      client: Cookies.get("_client"),
      uid: Cookies.get("_uid"),
    },
  });
};

4. コンポーネント作成

  • ログイン時と非ログイン時を判断するためのコンポーネントを作成する。

  • 今回は、ログイン時は Home コンポーネントに遷移するようにして、SignUp コンポーネントと SignIn コンポーネントが非ログイン時として作成していく。

src/components/Home.jsx
export const Home = () => {
    return <p>Homeページです</p>
}
src/components/SignUp.jsx
export const SignUp = () => {
    return <p>SignUpページです</p>
}
src/components/SignIn.jsx
export const SignIn = () => {
    return <p>SignInページです</p>
}

5. ログイン状態と非ログイン状態でページを切り分ける

  • それでは、実際にログイン時は Home コンポーネント、非ログイン時は SignUp、SignIn コンポーネントにを表示するようにしていく。

  • App.jsx でそれぞれのコンポーネントのルーティングを作成して、そのルーティングをログイン時と非ログイン時で切り分けていく。

src/App.jsx
import { createContext, useEffect, useState } from "react";
import { BrowserRouter, Switch, Route, Redirect } from "react-router-dom";
import { getCurrentUser } from "./api/auth";
import { Home } from "./components/Home";
import { SignIn } from "./components/SignIn";
import { SignUp } from "./components/SignUp";

export const AuthContext = createContext();

function App() {
  const [loading, setLoading] = useState(true);
  const [isSignedIn, setIsSignedIn] = useState(false);
  const [currentUser, setCurrentUser] = useState();

  const handleGetCurrentUser = async () => {
    try {
      const res = await getCurrentUser();

      if (res?.data.isLogin === true) {
        setIsSignedIn(true);
        setCurrentUser(res?.data.data);
        console.log(res?.data.data);
      } else {
        console.log("no current user");
      }
    } catch (e) {
      console.log(e);
    }
    setLoading(false);
  };

  useEffect(() => {
    handleGetCurrentUser();
  }, [setCurrentUser]);

  const Private = ({ children }) => {
    if (!loading) {
      if (isSignedIn) {
        return children;
      } else {
        return <Redirect to="signin" />;
      }
    } else {
      return <></>;
    }
  };
  return (
    <AuthContext.Provider
      value={{
        loading,
        setLoading,
        isSignedIn,
        setIsSignedIn,
        currentUser,
        setCurrentUser,
      }}
    >
      <BrowserRouter>
        <Switch>
          <Route exact path="/signup">
            <SignUp />
          </Route>
          <Route exact path="/signin">
            <SignIn />
          </Route>
          <Private>
            <Route exact path="/">
              <Home />
            </Route>
          </Private>
        </Switch>
      </BrowserRouter>
    </AuthContext.Provider>
  );
}

export default App;

6. サインアップページ作成

  • ここでは、サインアップページを作成して、Submit ボタンをクリックしたら本認証するためのメールが、入力したメールアドレスに送信されるようになる。

  • 送信されたかがコンソールを見ないとわからないため、成功したら「confirm email」というアラートを表示するようにしている。

src/components/SignUp.jsx
import Cookies from "js-cookie";
import { useContext, useState } from "react";
import { Link } from "react-router-dom";
import { signUp } from "../api/auth";
import { AuthContext } from "../App";

export const SignUp = () => {
  const { setIsSignedIn, setCurrentUser } = useContext(AuthContext);

  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [passwordConfirmation, setPasswordConfirmation] = useState("");
  const confirmSuccessUrl = "http://localhost:3000";

  const generateParams = () => {
    const signUpParams = {
      email: email,
      password: password,
      passwordConfirmation: passwordConfirmation,
      confirmSuccessUrl: confirmSuccessUrl,
    };
    return signUpParams;
  };

  const handleSignUpSubmit = async (e) => {
    e.preventDefault();
    const params = generateParams();
    try {
      const res = await signUp(params);
      console.log(res);
      alert("confirm email");
    } catch (e) {
      console.log(e);
    }
  };
  return (
    <>
      <h1>サインアップページです</h1>
      <form>
        <div>
          <label htmlFor="email">メールアドレス</label>
          <input
            type="email"
            id="email"
            name="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            type="password"
            id="password"
            name="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>
        <div>
          <label htmlFor="password_confirmation">パスワード確認</label>
          <input
            type="password"
            id="password_confirmation"
            name="password_confirmation"
            value={passwordConfirmation}
            onChange={(e) => setPasswordConfirmation(e.target.value)}
          />
        </div>
        <div>
          <input
            type="hidden"
            id="confirm_success_url"
            name="confirm_success_url"
            value={confirmSuccessUrl}
          />
        </div>
        <button type="submit" onClick={(e) => handleSignUpSubmit(e)}>
          Submit
        </button>
      </form>
      <Link to="/signin">サインインへ</Link>
    </>
  );
};

7. サインインページ作成

  • サインアップした際に届くメール内のリンクをクリックしたらサインインページに遷移される。

  • このサインインページで、サインアップ時に登録したメールアドレスとパスワードを入力して Home コンポーネントに遷移したら成功。

  • サインアップコンポーネントで Submit ボタンをクリックして、メール内のリンクをクリックする前にサインインコンポーネントからログインしようとしても失敗する。

src/components/SignIn.jsx
import Cookies from "js-cookie";
import { useContext, useState } from "react";
import { Link, useHistory } from "react-router-dom";
import { signIn } from "../api/auth";
import { AuthContext } from "../App";

export const SignIn = () => {
  const { setIsSignedIn, setCurrentUser } = useContext(AuthContext);
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");

  const history = useHistory();

  const generateParams = () => {
    const signInParams = {
      email: email,
      password: password,
    };
    return signInParams;
  };

  const handleSignInSubmit = async (e) => {
    e.preventDefault();
    const params = generateParams();

    try {
      const res = await signIn(params);
      if (res.status === 200) {
        Cookies.set("_access_token", res.headers["access-token"]);
        Cookies.set("_client", res.headers["client"]);
        Cookies.set("_uid", res.headers["uid"]);

        setIsSignedIn(true);
        setCurrentUser(res.data.data);

        history.push("/");
      }
    } catch (e) {
      console.log(e);
    }
  };
  return (
    <>
      <p>サインインページです</p>
      <form>
        <div>
          <label htmlFor="email">メールアドレス</label>
          <input
            type="email"
            id="email"
            name="email"
            value={email}
            onChange={(e) => setEmail(e.target.value)}
          />
        </div>
        <div>
          <label htmlFor="password">パスワード</label>
          <input
            type="password"
            id="password"
            name="password"
            value={password}
            onChange={(e) => setPassword(e.target.value)}
          />
        </div>
        <button type="submit" onClick={(e) => handleSignInSubmit(e)}>
          Submit
        </button>
      </form>
      <Link to="/signup">サインアップへ</Link>
    </>
  );
};

以上で Rails + React でのメール本認証のログイン機能が完成。

Discussion

しゅうしゅう

まつしょー様
記事の内容を大変参考にさせて頂いております。
気になる部分がありましたので質問させて頂きます。

サインイン時(SignUp.jsx)のhandleSignUpSubmitという関数内でCookiesへの値のセットと
setIsSignedIn(true);setCurrentUser(res.data.data);を行われておられますがメール認証を行う前のユーザーでログインもしていない状態で値をセットすることがこのコードで可能でしょうか。
何度か試したのですがCookiesの値は全てundifinedcurrent_userの値はnilとなってしまいます。
ご教授いただけると幸いです。

まつしょーまつしょー

記事をご覧いただきありがとうございます。
そして、ご指摘ありがとうございます。
私も今確認させてもらったのですが、このメール認証の作りだとsetIsSigneIn(true) とsetCurrentUser(res.data.data)の値をセットすることはできません
メールで送ったリンクからログインページに遷移して、ログインをすることで値をセットすることができます。
以前作ったRailsAPIとReactでのログイン機能のコードを使いまわしていて確認不足でした!
私の完全な記述ミスなので申し訳ないです🙇
記述を修正したのでご確認ください!