パスワードレス認証

メールアドレスと検証コードでログイン

2025.07

当書は技術設計サービス向けのサンプル設計書です。

概要

UIの仕様

アカウントコンポーネント

トップバーの右端に配置します。

ログイン済みの場合、アカウント名とプロフィール写真を表示し、クリックするとプロフィール 画面へ移動する。

未ログインの場合、「ログイン」ボタンを表示し、クリックするとログイン画面へ移動する。

ログイン画面に移す直前に、現在のURLをsessionStoragelogin_redirect_url キーで保存し、ログイン成功後に復元できるようにする。

プロフィール画面

ユーザーの名前、メールアドレス、プロフィール画像を表示する。

ログアウトボタンを含む。

ログイン画面

2つのモードを持つログインフォームを表示する

メールアドレス入力モード

検証コード入力モード

認証後の遷移

sessionStoragelogin_redirect_urlキーを確認する。 設定された場合、値をクリアし、指定されたルートへ遷移。 設定されなかった場合、トップ画面へ遷移する。


DBテーブル

効率性向上のため、DBでは数値のuser_idを内部的に使用するが、UIでは非公開です。

login_codesemailstringPKcodestringfail_countintcreated_atdatetimesessionstokenstringPKuser_idintcreated_atdatetimeuser_accountsemailstringPKuser_idintFKcreated_atdatetimeuser_profilesuser_idintPKemailstringnamestringpicture_urlstringmodified_atdatetimecreated_atdatetime

セッション

BE側で16バイトのバッファを暗号学的に安全な疑似乱数生成器で埋め、base64でエンコードして セッショントークンを生成する。

FE側では、localStorage"session_token"キーでセッショントークンを保存する。

各APIリクエスト送信時に、"X-Session-Token"ヘッダーにセッショントークンを含めて 提示する。

FE側で、グローバルにアクセス可能なUserProfile型の単一インスタンスがあるようにする

type UserProfile = {
    email: string
    name: string
    picture_url: string
}

各処理の説明

注目する動作は以下の通り:

したがって、以下のプロセスを説明する:


ログイン検証コードの発行と送信

発生時:ユーザーがログイン画面にてメールアドレス入力し、「検証コードの送信」ボタンを 押したとき。

API:

POST /api/request_login_code

Request:
{
    email: string
}

OK Response (status 200)
{
}

Error Response (status 400)
{
}

FE側の流れ

BE側の流れ

以下に基本ケースのシーケンス図を示す

検証コードを送信ユーザーのメールサーバーユーザーフロントエンドバックエンドDB 「検証コードを送信」ボタンをクリックrequest_login_code{email}login_codes 挿入 メール送信OKコード入力モード表示 メールアドレスが形式的に無効ユーザーのメールサーバーユーザーフロントエンドバックエンドDB 「検証コードを送信」ボタンをクリックエラーメッセージ無効と判断

ログイン検証コードの確認

発生時:ユーザーが検証コードを入力し、「ログイン」ボタンを押したとき。

API:

POST /api/verify_login_code

Request:
{
    email: string
    code: string
}

OK Response (status 200)
{
    session_token: string
    user_profile: UserProfile
}

Error Response (status 400)
{
}

FE側の流れ

BE側の流れ:

以下に各種ケースのシーケンス図を示す。

ログインコードの確認 | FE側 | 有効メールサーバーユーザーFElocalStorageBE コード含むメール確認内容表示コード入力と「ログイン」クリックverify_login_code{email, code}OK{session_token, user_profile}session_token保存UserProfile更新get("login_redirect_url")リダイレクト先表示 ログインコードの確認 | BE側 | 有効FEBEDB verify_login_code{email, code}login_codesクエリ結果一致と有効確認login_codes削除user_profilesクエリ結果sessions挿入OK{session_token, user_profile} ログインコードの確認 | BE側 | 有効 + 新規登録FEBEDB verify_login_code{email, code}login_codesクエリ結果一致と有効確認login_codes削除user_profilesクエリなしuser_accounts/user_profiles作成sessions挿入OK{session_token, user_profile} ログインコードの確認 | BE側 | 不一致FEBEDB verify_login_code{email, code}login_codesクエリ結果コード不一致fail_count増加エラー ログインコードの確認 | BE側 | 無効FEBEDB verify_login_code{email, code}login_codesクエリ結果10分超削除エラー

セッショントークンの確認

発生時:ページ初回ロード時の初期化処理。

API:

POST /api/verify_session_token

Request:
{
    session_token: string
}

OK Response (status 200)
{
    session_token: string
    user_profile: UserProfile
}

Error Response (status 400)
{
}

FE側の流れ

BE側の流れ

以下に各種ケースのシーケンス図を示す。

セッショントークンの確認 | UI側 | トークン有効localStorageFEBE get("session_token")トークンverify_session_token{session_token}OKUserProfile設定set("session_token") セッショントークンの確認 | BE側 | トークン有効FEBEDB verify_session_token{session_token}sessionsクエリセッションuser_profilesクエリプロフィールOK セッショントークンの確認 | BE側 | トークン有効 + 更新FEBEDB verify_session_token{session_token}sessionsクエリセッション新トークン生成旧削除新保存user_profilesクエリプロフィールOK セッショントークンの確認 | BE側 | トークン無効FEBEDB verify_session_token{session_token}sessionsクエリなしエラー

セッショントークンの削除

発生時:ログアウトボタンクリック。

API:

POST /api/delete_session_token

Request:
{
    session_token: string
}

OK Response (status 200)
{
}

FE側の流れ

BE側の流れ

エラー対応不要、FE側はレスポンス確認しない。

Invalidate Session TokenlocalStorageFEBEDB delete_session_tokendelete("session_token")sessions削除トップリダイレクトとリロード待たない待たない

まとめ

パスワードレスログインの実装支援のために、以下を洗い出しました: