本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

Next.js のログイン実装。最小構成サンプル

ログインの骨格はファイル5つで立ちます。

動いているものを触る/demo/login

ファイル構成

並んでいるのは、上の画面をいま動かしている本物のファイルです。名前を押すと中身が出ます。

ファイル構成
  • app/
  • mypage/
app/layout.tsxBuild

全ページの外側。本物のプロジェクトでは html と body をここで書きます

import type { Metadata } from "next";
 
export const metadata: Metadata = {
  title: "ログインの最小構成",
};
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return <main>{children}</main>;
}
.tsx
画面を返すファイル。HTML のような書き方ができます
.ts
画面を返さないファイル。処理とデータだけを置きます。ここに画面を書くと原因を名指ししないエラーで落ちます
Build
ビルド時に一度だけ動きます
Server
アクセスのたびにサーバーで動きます
Browser
利用者の手元で動きます

ログインは3つの部品でできている

パスワードもメールも外して残るのは、この3つです。

ログインの骨格。どれが欠けても成立しない
部品置き場所役目
セッションサーバー誰なのかを覚えておく
Cookieブラウザそのセッションの鍵を持ち歩く
守りページごと鍵が無ければ入れないようにする

このサンプルはこの3つだけで組んであります。足りないものは意図的に外してあります(下の「入れていないもの」)。

ブラウザへ渡すのは鍵だけ

ログイン中に、どちら側が何を持っているか
サーバーに残るもの
名前
有効期限
セッションの一覧
ブラウザが持つもの
推測できない鍵(セッションID)

越えられる: 鍵だけ

越えられない: 名前・権限・有効期限

Cookie に入れているのは crypto.randomUUID() で作った鍵だけです。名前は app/session.ts の中に残ります。

Cookie の設定は3つとも意味があります。

設定何を防ぐか
httpOnlyページの JavaScript から読めなくする
sameSite: 'lax'他所のサイトからの送信で使わせない
secure暗号化されていない通信に乗せない

守るのはページ自身の仕事

app/mypage/page.tsx は、自分でセッションを見て、無ければ追い返します。

const session = readSession(jar.get(COOKIE)?.value)
if (!session) redirect('/demo/login')

ログアウトで消すものは2つ

Cookie を消すだけでは足りません。サーバー側の記録も消します。

destroySession(jar.get(COOKIE)?.value)
jar.delete(COOKIE)

片方だけだと、鍵を控えておいた人が後から入れてしまいます。この2行は必ず組で書きます。

誰でも呼べる入口だという前提

app/actions.ts の関数は、画面を経由せずに呼べます。だからその中で、値を絞ることと、回数を絞ることの両方をやっています。

ログインを押してから、入れるようになるまで
  1. Browser
    名前を送る

    普通の form の送信。

  2. Server
    回数と値を確かめる

    誰でも呼べる入口なので、まずここで絞る。

  3. Server
    セッションを作って鍵を渡す

    名前はサーバーに残し、Cookie には鍵だけを入れる。

  4. Server
    守られたページへ送る

    そのページが自分で鍵を確かめる。

ここから足していくとき

  • パスワードかメールを足す。このサイト本体は、パスワードを持たずにメールのリンクで確認する形にしています。理由はこのサイトについてにあります
  • セッションをデータベースへ移す。いまはプロセスの中なので、入れ替えると全員ログアウトになります
  • 権限を足す。readSession の戻り値に役割を持たせて、ページ側で見ます

どれを足しても、鍵と中身の分け方は変わりません。そこが崩れると、あとから足した守りは全部効かなくなります。

入れていないもの

このまま本番に持っていかないでください。省いてあるのは次の点です。

  • パスワードとメール送信。誰でも押せる画面なので、この稿では入れていません
  • データベース。セッションはプロセスの中に置いてあり、入れ替えで消えます
  • CSRF 対策の追加実装。Server Function と SameSite で足りる範囲に留めています
  • 権限の区別。ログインしているかどうかだけを見ています

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

このページには use client がありません。フォームの action に Server Function を渡しています。ビルドはどうなりますか。

この問題を解くこのテーマの問題 3 問