前回の記事では、Nuxt × Amplify 認証の仕組みを整理しつつ、最後に「AWS Amplify と HttpOnly Cookie 対応について」という補足を書きました。
🔗 前回の記事
今回は、その補足として触れた 「Cookie ベースのサーバーセッション方式」 を実際に Nuxt へ実装した話をまとめます。
AWS Amplify(Cognito User Pool)を使った認証はとても便利ですが、実のところ SSR(サーバーサイドレンダリング)と相性が悪い という制約があります。
- Amplify の認証は SPA(CSR)前提 に設計されている
- 認証情報(idToken / accessToken)は ブラウザの JavaScript からしか取得できない
- SSR 中は
fetchAuthSession()が実行できない - 結果、SSR ページは「ログイン状態」を判定できない
- server/api から Amplify Data や Backend を呼ぶ場合も token が取れず認証が崩れがち
❗なぜ Amplify は SSR と相性が悪いのか?
Amplify のログイン状態は以下のように管理されています:
ログイン → fetchAuthSession() → idToken, accessToken を JS で保持
しかし SSR では JS が動作しないため、
という根本的問題が起きます。
つまり SSR の世界で「認証情報が存在しない」 のです。
この問題を解決しない限り、Nuxt の SSR はまともに動きません。
🔑 そこで必要なのが「サーバー側セッション」です
Nuxt は SSR 中に Cookie のみを自動で送信できます。
この性質を活かし、認証方式を以下のように再設計します:
1. クライアントで Cognito にログイン(CSR) 2. idToken をサーバーの API に送る 3. サーバーで検証 → 署名済みの JWT に作り直し、HttpOnly Cookie として保存 4. SSR / server API は Cookie を読むだけで認証可能
ポイントは idToken をそのまま Cookie に入れない こと。
攻撃面を減らすため、
- サーバー側で署名した独自 JWT
- HttpOnly + secure + sameSite=Lax
- 有効期限は Cognito の exp に合わせる
というセキュアな形へ変換します。
これにより、
すべてが自然にログイン状態を扱えるようになります。
🏗️ 実際のフロー(全体図)
[CSR] Amplify Auth でログイン
│
▼
fetchAuthSession() で idToken を取得
│
▼
POST /api/auth/session
(idToken を送る)
│
▼
[Server] Cognito 公開鍵で idToken を検証
│
▼
user情報 + idToken を含む JWT を生成
│
▼
HttpOnly Cookie 'app_session' として保存
│
└───────────┐
▼
SSR / server/api / Middleware
Cookie を参照 → 認証が成立
🧩 セッション Cookie の構造
サーバー側が発行する Cookie(app_session)は次のような情報を含みます:
- sub(ユーザーID)
- cognito:groups
- idToken(Amplify Data の認可に使用)
- exp(Cognito の期限に合わせる)
これらを jsonwebtoken で署名し、HttpOnly Cookie として保存します。
🎯 この方式のメリット
✔ SSR と認証が自然に動く
SSR 中の API 呼び出しやページ描画で、常にログイン状態を復元できます。
✔ XSS に強い(HttpOnly Cookie)
idToken を JavaScript で保持する必要がないため、攻撃面が大きく減ります。
✔ Amplify 特有の制約を回避
Amplify の “CSR でしか動かない問題” をバイパスし、SSR 時代の Amplify を可能にするアーキテクチャになります。
✔ server/api でも Amplify Data が実行できる
Amplify Data は authToken が必要ですが、
idToken を cookie から安全に取り出すことで SSR でも使えます。
🆚 Bearer トークン vs HttpOnly Cookie
Nuxt + Amplify では、Cookie 方式が圧倒的に合理的です。
| 観点 | Bearer トークン | HttpOnly Cookie |
|---|---|---|
| XSS 耐性 | ❌ 弱い | ◎ 強い |
| SSR での利用 | ❌ ほぼ不可 | ◎ 自然に動く |
| server/api | トークン必須で煩雑 | Cookie だけで認証 |
| クロスドメイン | ◎ 強い | △ 設計が必要 |
| 管理の复杂性 | 高い | 低い |
🔨 実装ポイントまとめ
1. CSR:Amplify でログイン
const session = await fetchAuthSession() const idToken = session.tokens.idToken.toString()
2. idToken をサーバーへ送信
await fetch('/api/auth/session', {
method: 'POST',
credentials: 'include',
body: JSON.stringify({ idToken }),
})
3. サーバーで Cookie へ変換(要点)
- verifyIdToken で正当性を確認
- 必要な user 情報を抽出
- JWT に署名して cookie に保存
- HttpOnly / secure / sameSite=Lax を徹底
4. SSR では session middleware が Cookie を復元
event.context.user = {
sub,
email,
groups,
idToken,
}
🧠 Nuxt × Amplify で SSR を使う人の“新しい定石”へ
今回紹介した方式は、実は Amplify Auth を SSR で扱うための最適解にかなり近い と考えています。
Amplify の制約(CSR 前提)を踏まえながら:
現実的で実装しやすい認証アーキテクチャです。
Nuxt で本格的に SSR と認証を両立させたい人には、ぜひ試してみてほしいやり方です。
