はじめに
Cognito(AWS)にGoogleログインを連携する案件で、マンチーが3つの罠を全部踏み抜いた話です。
ECサイトに会員機能(SSO)を実装する時に発生した詰まりポイントなんですが、公式ドキュメント通りやってるのに動かないっていう、よくあるパターン。
ハマってる人の検索でこの記事に辿り着いてくれたら嬉しいので、解決策を共有します。
構成の前提
実装した構成はざっくり以下:
[ユーザー]
↓
[CloudFront(AWS) (+ CloudFront Functions)]
↓
[S3(AWS) (静的ホスティング)]
↓ ログインボタン押下
[Cognito Hosted UI]
↓ Continue with Google
[Google OAuth 2.0]
↓ 認可コード返却
[サイト:PKCE でトークン交換]
↓
[ログイン完了]
ECサイトを CloudFront + S3 で配信して、会員機能は Cognito で Google フェデレーション。 よくある構成です。
💢 罠その1:Cognitoの “name” 属性が空になる
何が起きた?
ユーザーが Google ログインを完了した瞬間に、Cognito 側でエラー:
attributes required: [name]
「name属性が必須なのに空です」と弾かれる。
設定は問題ないはず
Google IdP の属性マッピングを見ると:
| Cognito属性 | ← | Google属性 |
|---|---|---|
| ← | ||
| name | ← | name |
公式ドキュメント通りに name ← name で設定済み。何も間違ってない。
原因
Google が返す Open ID Connect(以降:OIDC)レスポンスに、name(フルネーム)が含まれないケースがあるんです。
理由は色々:
- ユーザーが Google アカウントで本名を非公開設定
- Workspace アカウントで管理者がフルネーム表示を制限してる
- ニックネームのみ登録の人
→ つまり、Googleの仕様上、name は必ず返る保証がない。
それなのに Cognito User Pool 側は name を必須属性にしてた。作成後は変更不可なので、ここが詰まる。
🔑 解決策
属性マッピングを変更:
| Cognito属性 | ← | Google属性 |
|---|---|---|
| name | ← | given_name |
given_name(名のみ)は、Google 側で必ず返るフィールド。
姓・名のフルネームじゃなくなるけど、確実に動く。
学び
OIDC の「標準仕様」と「実装の挙動」は乖離する。
特にフェデレーション(Google・Facebook・Apple等)を使う場合は:
- name(フルネーム)に依存しない
- given_name / family_name(個別フィールド)へフォールバック設計
- 必須属性は最小限にする(後で追加できないため)
💢 罠その2:CloudFront Functions JS-2.0 で set-cookie 仕様が変わってた
何が起きた?
CloudFront Functions で認証Cookieを発行する処理を実装。 レスポンスヘッダーに set-cookie を入れて返したら、エラー:
The CloudFront function returned an invalid value:
response.headers cannot contain 'set-cookie' header.
Use response.cookies instead.
(MisplacedCookies)
「set-cookie ヘッダーは使うな、response.cookies を使え」と弾かれる。
でも昔のサンプルでは動いてた
CloudFront Functions の古い情報をネットで調べると、set-cookie ヘッダーで書いてるコードがいっぱい出てくる。
// 昔のやり方(JS-1.0)
return {
statusCode: 302,
headers: {
'location': { value: '/' },
'set-cookie': { value: 'munchie_unlock=valid; Path=/; ...' }
}
};
→ これだと MisplacedCookies エラー。
原因
CloudFront Functions のランタイムが JS-1.0 → JS-2.0 で仕様変更されてた。
| バージョン | Cookie の渡し方 |
|---|---|
| JS-1.0 | headers['set-cookie'] でOK |
| JS-2.0 | cookies フィールドに分離。set-cookie ヘッダーは禁止 |
🔑 解決策
response.cookies の独立フィールドで書く:
// 新しいやり方(JS-2.0)
return {
statusCode: 302,
headers: {
'location': { value: '/' }
},
cookies: {
'munchie_unlock': {
value: 'valid',
attributes: 'Path=/; Max-Age=2592000; Secure; HttpOnly; SameSite=Lax'
}
}
};
→ これでエラー解消。
学び
新ランタイムを使う時はリリースノート確認が必須。
特に AWS のサーバーレス系は、バージョン違いで仕様が破壊的に変わることがある。
MisplacedCookies というエラーメッセージで検索したら一発で原因特定できたので、エラーメッセージはそのまま Google に投げるのが最速ルート。
💢 罠その3:OAuthコールバック URL のスラッシュ不一致
何が起きた?
Cognito Hosted UI で Google ログインを完了 → リダイレクト処理が動かない。 URL に ?code=xxx の認可コードが付かない。
Cognito 側の登録URL
https://xxx.cloudfront.net
末尾スラッシュなしで登録。
JS 側の redirect_uri
const redirectUri = window.location.origin + window.location.pathname;
// → "https://xxx.cloudfront.net/"
末尾スラッシュありになる(CloudFront のデフォルトドメインがそうなってるから)。
原因
OAuth 2.0 の仕様上、redirect_uri は完全一致を要求する。
| 場所 | URL |
|---|---|
| Cognito登録 | https://xxx.cloudfront.net |
| JS生成 | https://xxx.cloudfront.net/ ← 末尾スラッシュ |
→ 1文字違いで認証失敗。
これ、エラーメッセージが出ないケースもあるので、原因特定に時間かかった。
🔑 解決策
Cognito の許可コールバック URLに、両方の表記を登録:
https://xxx.cloudfront.net

https://xxx.cloudfront.net/
→ どっちで来ても通る。
学び
OAuth 2.0 のURIマッチングは厳密。
特に CloudFront のデフォルトドメイン(*.cloudfront.net)は末尾スラッシュ付きでアクセスされる挙動なので、スラッシュあり/なし両方を許可URLに登録しておくのが安全です。カスタムドメインを使う場合や、パス付きURLでも、同じ罠が発生します。
まとめ
Cognito と Google OAuth 連携で踏んだ罠と対策:
| 罠 | 原因 | 対策 |
|---|---|---|
| 1. name属性が空でエラー | Googleが name を返さないケースあり | given_name にマッピング変更 |
| 2. set-cookie ヘッダー禁止 | CloudFront Functions JS-2.0 仕様 | response.cookies に分離 |
| 3. redirect_uri 不一致 | スラッシュ1文字の差 | 両方の表記を登録 |
教訓
公式ドキュメント通り設定しても、仕様外の挙動で詰まることはある。
特にフェデレーション認証は:
- IdP(Google等)の挙動が標準仕様と乖離
- AWSサービスのランタイムバージョンで仕様変更
- URI完全一致の罠
エラーメッセージをそのまま検索するのが、解決の最短ルートでした。


コメント