Next.jsでCookieを利用したユーザ認証情報の保持について

Cookieを利用してユーザ認証情報を保持する

Cookieとは?

Cookieは、Webブラウザに保存される小さなデータの断片で、Webサイトがユーザの状態を保存し、後続のリクエストで再利用するために使用される。

Cookieは、セッション管理、パーソナライズ、トラッキングなど、さまざまな用途に利用できる。

Cookieを利用するメリット

Cookieには以下の3つのようなメリットがある。

  • セッションの維持
    ユーザがログイン状態を維持するためにCookieを使用します。これにより、再度ログインすることなく連続してリクエストを行うことができます。
  • パーソナライズ
    ユーザの設定や好みを保持し、次回の訪問時に再適用することで、よりパーソナライズされた体験を提供できる。
  • セキュリティ
    Cookieにセキュアな情報を保存し、HTTPOnly属性を使用することで、クライアントサイドのスクリプトからのアクセスを制限できる。

実装例:ユーザ認証情報をCookieに保持する

以下のコードは、ユーザ認証情報をCookieに保存するための実装例です。この例では、ユーザのUUIDをCookieに保存して、認証状態を維持するために使用します。

また、ここでは認証についての説明は省かせていただきます。この記事の本質であるCookieの活用においては、UUIDを返してくれれば、どの認証サービスを使用していても問題ありません。

Cookieの設定オプション

まず、Cookieの設定オプションを定義します。これにより、Cookieの属性を指定し、セキュリティや有効期限を設定することができます。

import { CookieOptions } from "@supabase/ssr";
import { cookies } from "next/headers";

// Cookieの設定オプション
const cookieOptions: CookieOptions = {
  path: "/",
  httpOnly: true,
  secure: process.env.NODE_ENV === "production",
  sameSite: "lax",
};

各オプションで設定していることは以下のようになっています。

  • path
    Cookieが有効なパスを指定する。デフォルトではWebサイト全体で有効にするために「/」を設定する。これにより、サイト内のどのページからでもCookieにアクセスできるようになる。
  • httpOnly
    このオプションを設定すると、JavaScriptからのアクセスを防ぐ。クライアントサイドのスクリプトがCookieにアクセスできないため、Cookieの内容が悪意のあるスクリプトによって盗まれるリスクを減らせる。
  • secure
    Secureオプションは、CookieがHTTPS接続でのみ送信されることを保証する。process.env.NODE_ENV === "production"を設定することで、本番環境ではセキュアな接続を強制し、開発環境では柔軟性を持たせることができる。
  • sameSite
    SameSiteオプションは、Cookieがクロスサイトリクエスト(異なるドメインからのリクエスト)に対してどのように扱われるかを制御する。laxを設定すると、ユーザがリンクをクリックして同じサイトに移動する場合にはCookieが送信されますが、他のサイトからのリクエスト(フォーム送信など)にはCookieが送信されない。これにより、クロスサイトリクエストフォージェリ(CSRF)攻撃と呼ばれる悪意のある攻撃から保護する。

UUIDをCookieに保存する関数

次に、UUIDをCookieに保存するための関数を定義します。この関数は、ユーザがログインした際にUUIDをCookieに保存するために使用します。

// UUIDをクッキーに保存する関数
const setUuidCookie = (uuid: string) => {
  const cookieStore = cookies();
  cookieStore.set({ name: "user_uuid", value: uuid, ...cookieOptions });
};

UUIDをCookieから取得する関数

次に、CookieからUUIDを取得するための関数を定義します。この関数は、ユーザの認証状態を確認するために使用します。

// UUIDをクッキーから取得する関数
export const getUuidFromCookie = () => {
  const cookieStore = cookies();
  return cookieStore.get("user_uuid")?.value;
};

UUIDをCookieから削除する関数

最後に、UUIDをCookieから削除するための関数を定義します。

// UUIDをクッキーから削除する関数
export const deleteUuidCookie = () => {
    const cookieStore = cookies();
    cookieStore.set({ name: "user_uuid", value: "", ...cookieOptions });
};

認証アクションの実装

これらの3つの関数を使用して、認証自体のロジック部分は省略すると、実装は以下のようになります。

ログイン

export const loginAction = async (provider: Provider) => {
  try {
    // ここにログインの実装

    const user = <ログインしてるユーザを取得する>
    if (ユーザが存在している) {
      setUuidCookie(ユーザのUUIDの値);
    }

    return (正常)
  } catch (error) {
    return (エラー);
  }
};

サインアウト

export const signOutAction = async () => {
  try {
    // ここにサインアウトの実装

    deleteUuidCookie();

    return (正常);
  } catch (error) {
    return (エラー);
  }
};

サインイン

export const signInAction = async (email: string, password: string) => {
  try {
    // ここにサインインの実装

    if (ユーザが存在している) {
      setUuidCookie(ユーザのUUIDの値);
    }

    return (正常);
  } catch (error) {
    return (エラー);
  }
};

サインアップ

export const signUpAction = async (email: string, password: string) => {
  try {
    // ここにサインアップの実装

    if (ユーザが存在している) {
      setUuidCookie(ユーザのUUIDの値);
    }

    return (正常);
  } catch (error: any) {
    return (エラー);
  }
};

まとめ

Cookieを利用することで、ユーザ認証情報を安全かつ効率的に保持することができる。便利!

特に、HTTPOnlyやsecure属性を使用することで、セキュリティを高めることもできる。

この方法は、特定の認証方法に依存せずに、一般的なCookieの利用方法として幅広く応用することができると思いました。