本文へ移動
cccskills
無料GitHub で公開

kb-demo-app-auth

デモアプリ・Webアプリの Cognito 認証のおすすめ構成。「Googleで続ける」か「メール+パスキー(パスワードも併用可)」の2経路をCDKとフロントでどう組むか、パスキーが動かない設定の罠、Google client secret の置き場、ログイン画面のUX規約、Googleの同意画面に出るアプリ名の扱い。

新しくデモアプリを作るとき、既存アプリの認証を作り直すとき、パスキーやGoogleログインが動かないときに読む。

インストール方法を見る

含まれるファイル(1)

  • SKILL.md14.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

デモアプリの Cognito 認証(おすすめ構成)

デモアプリ・Webアプリの認証は、特に指定がなければこの構成にする:「Googleで続ける」か「メール+パスキー」。

動く実物は minorun365/marp-agent。 迷ったら実物を読む。設計の背景は同リポジトリの docs/authentication-options.md。

ファイル中身
infra/lib/auth-stack.tsUser Pool / App Client / Google IdP / Cognito ドメイン
src/components/Auth/AuthScreen.tsxログイン画面(326行。移植元)
src/components/Auth/AuthScreen.css同スタイル
infra/lambda/auth/google-idp-manager/handler.tsGoogle IdP を作るカスタムリソース
infra/lambda/auth/google-link/handler.tspreSignUp。既存メールユーザーへGoogleを連携

1. 利用者から見た形

経路初回2回目以降
Google「Googleで続ける」で登録とログインが同時に終わるGoogle
メールメールアドレス+パスワードで登録し、確認コードでメールを確認パスキー(顔・指紋)。パスワードも使える
  • メールのワンタイムコードログインは採用しない。 SES の本番利用申請を認証の前提にしない。Cognito 標準メールは新規登録の確認とパスワード再設定だけに使う(AWSアカウントあたり1日50通)。
  • パスキーはパスワードの置き換えではない。 登録しなくても期限なくパスワードで使える。
  • Google 利用者へパスキー登録を案内しない。 本人確認は Google 側が担当している。

2. ログイン画面のUX規約

1画面目は 2択だけに絞る。「Googleで続ける」と、メールアドレス入力+「メールで続ける」。

メールを入れた次の画面では、パスキーとパスワードを常に並べて出す。

パスキー登録の有無で画面を出し分けない。 出し分けると「そのメールアドレスが登録済みか」を第三者へ教えることになる。同じ理由で、存在しないアドレスも認証失敗も表示は「メールアドレスまたは認証情報を確認してください。」に統一し、Cognito 側も preventUserExistenceErrors: true にする。

パスワードでログインした利用者には、成功後に一度だけパスキー登録を案内する。

  • 「パスキーを登録」と「あとで」の2つだけ
  • 「あとで」を押されたら 30日間は再案内しない(localStorage に押した時刻を持つ)
  • 専用の設定画面は作らない。ログイン後のメイン画面も変えない

3. CDK(User Pool)

パスキーは設定が1つでも欠けるとエラーにならず、ただ使えない形で失敗する。次の5点をまとめて入れる。

this.userPool = new cognito.UserPool(this, 'UserPool', {
  featurePlan: cognito.FeaturePlan.ESSENTIALS,   // ① LITE ではパスキーを使えない
  mfa: cognito.Mfa.OFF,                          // ② 明示しないとOPTIONALへ補完されることがある
  selfSignUpEnabled: true,
  signInAliases: { email: true },
  signInCaseSensitive: false,
  autoVerify: { email: true },
  standardAttributes: { email: { required: true, mutable: true } },
  accountRecovery: cognito.AccountRecovery.EMAIL_ONLY,
  signInPolicy: {
    allowedFirstAuthFactors: { password: true, passkey: true },   // ③ パスキーを第1認証要素に
  },
  passkeyRelyingPartyId: props.appDomain,                          // ④ 配信ドメインと完全一致させる
  passkeyUserVerification: cognito.PasskeyUserVerification.PREFERRED,
  passwordPolicy: { minLength: 8, requireDigits: false, requireLowercase: false, requireSymbols: false, requireUppercase: false },
});

this.userPoolClient = this.userPool.addClient('WebClient', {
  generateSecret: false,
  preventUserExistenceErrors: true,
  authFlows: { user: true, userPassword: true, userSrp: true },    // ⑤ user:true = USER_AUTH。無いとパスキーを選べない
  accessTokenValidity: cdk.Duration.minutes(60),
  idTokenValidity: cdk.Duration.minutes(60),
  refreshTokenValidity: cdk.Duration.days(30),
});
  • ④ の RP ID は「利用者がアクセスするドメイン」。dxxxx.cloudfront.net のような配信基盤の既定ドメインでもよいが、後からカスタムドメインへ移すと登録済みのパスキーは全部使えなくなる(RP ID が変わるため)。カスタムドメインを付ける予定があるなら、パスキーを入れる前に先に付ける。
  • パスワードポリシーを厳しくしない。 パスキーを入れる目的は入力を減らすこと。記号必須・12文字のような設定はデモの初回登録を重くするだけ。
  • featurePlan: ESSENTIALS は MAU 課金が発生する。デモ規模なら無視できるが、LITE からの変更なので認識しておく。

フロント側(aws-amplify v6)

// パスキーでログイン
await signIn({ username: email, options: { authFlowType: 'USER_AUTH', preferredChallenge: 'WEB_AUTHN' } });

// パスワードでログイン
await signIn({ username: email, password, options: { authFlowType: 'USER_PASSWORD_AUTH' } });

// ログイン後にパスキーを登録
await associateWebAuthnCredential();

Amplify.configure の Auth.Cognito に userPoolId / userPoolClientId を渡すだけでよい。Google を使うときだけ loginWith.oauth を足す(次節)。

4. Google ログイン

OAuth クライアントはデモごとに作らず、共通の1つを使い回す

同意画面のアプリ名は GCP プロジェクト単位で1つなので、デモごとにクライアントを作っても名前は分けられない。 デモ用の中立な名前でプロジェクトとクライアントを1つ用意し、以後のデモは全部これを使い回す。

項目決め方
GCP プロジェクトデモ専用に1つ作る
同意画面のアプリ名利用者に見えるのはこれ。特定のデモ名にせず、中立な名前にする
公開ステータス本番環境(テストユーザーの登録なしで誰でもログインできる)
Client IDCDK のコンテキストで渡す(秘密ではない)
Client Secretデプロイ先の AWS アカウントへ置く(下の「client secret の置き場」)

新しいデモを足すときの作業は2つだけ。

  1. Google Cloud Console でそのクライアントを開き、承認済みリダイレクト URI に新しい Cognito ドメインの /oauth2/idpresponse を1行足す
  2. そのデモの AWS アカウントへ Secret を入れ、CDK に googleClientId を渡す

組織の Google Workspace 配下の GCP プロジェクトは、同意画面が「内部」(orgInternalOnly)になっていることがある。 その場合は組織のアカウントしかログインできず、外部の人が触るデモでは機能しない。プロジェクトを選ぶ前に同意画面のユーザータイプを確かめる。

gcloud でも API でも、クライアントの作成も編集もできない。リダイレクトURIの追記も含めて Console のブラウザ操作が唯一の手段(2026-08 時点)。根拠は3つ:

  • gcloud alpha iap oauth-clients は IAP 専用で、ヘルプ自身が「プロジェクト内の全 OAuth クライアントの管理 API としては使えない」と明記。加えて IAP OAuth Admin API は 2026-03-19 に完全停止
  • iap v1 の discovery を見ると projects.brands.identityAwareProxyClients の method は create/get/list/delete/resetSecret だけで、更新系が無い。停止していなくてもURIは足せない
  • Google の公開 API 一覧(https://www.googleapis.com/discovery/v1/apis)に、OAuth クライアントを管理する API 自体が存在しない

人に操作を頼むときは、クライアントの編集画面まで開けるURLを渡す。 URLはこの形: https://console.cloud.google.com/auth/clients/<クライアントID>?project=<プロジェクトID>

実装に必要なもの

Cognito ドメイン(Hosted UI 用)、Google の OAuth クライアント ID / Secret、IdP 登録、App Client の OAuth 設定。

supportedIdentityProviders: [cognito.UserPoolClientIdentityProvider.COGNITO, cognito.UserPoolClientIdentityProvider.GOOGLE],
oAuth: {
  flows: { authorizationCodeGrant: true },
  scopes: [cognito.OAuthScope.OPENID, cognito.OAuthScope.EMAIL, cognito.OAuthScope.PROFILE],
  callbackUrls: [`https://${appDomain}/`, 'http://localhost:5173/'],
  logoutUrls:   [`https://${appDomain}/`, 'http://localhost:5173/'],
},

フロントは signInWithRedirect({ provider: 'Google' }) を呼ぶだけ。

Amplify Gen2 の defineAuth では「スコープ」が2か所にあり、書き方が逆になる。 ここを取り違えると デプロイも構成検査も通ったうえで、Googleのログイン画面が invalid_scope で開かない。

場所何のスコープか書き方
externalProviders.scopesCognito のアプリクライアントが出すトークンの範囲大文字の列挙(['EMAIL','PROFILE','OPENID'])
externalProviders.google.scopesGoogle へそのまま渡る生の文字列小文字(['openid','email','profile'])

後者に大文字を書くと authorize_scopes が "EMAIL PROFILE OPENID" として IdP に入り、Google が invalid=[OPENID] を返す(EMAIL / PROFILE は通ってしまうので、症状が OPENID だけに出て気づきにくい)。

この種の失敗は AWS 側をいくら見ても分からない。 デプロイ後に Cognito の認可エンドポイントへ リクエストを投げ、accounts.google.com のログイン画面へ着地するかを確かめる(サインインは不要)。 エラー時は authError クエリが base64 で理由を持っている:

curl -s -o /dev/null -L -w '%{url_effective}\n' \
  "https://<Cognitoドメイン>.auth.<region>.amazoncognito.com/oauth2/authorize?identity_provider=Google&client_id=<アプリクライアントID>&response_type=code&scope=openid+email+profile&redirect_uri=https%3A%2F%2F<配信ドメイン>%2F"

.../signin/oauth/error?authError=... へ着地したら失敗。authError を base64url デコードすると invalid_scope / redirect_uri_mismatch などの理由が平文で読める。

client secret の置き場

cognito.UserPoolIdentityProviderGoogle の L2 は secret を CloudFormation テンプレートへ平文で残す。marp-agent は、秘密値を state に残さないカスタムリソース(google-idp-manager)で IdP を作る形にしている。

組織の管理下にある AWS アカウントでは、SCP で secretsmanager:CreateSecret が拒否されていることがある。 marp-agent の handler は Secrets Manager から読む実装なので、その場合は SSM Parameter Store の SecureString に置き換える。Lambda 実行ロールに ssm:GetParameter と、SecureString を復号する kms:Decrypt を付ける。

段階的に入れてよい

Google は GCP 側の作業(OAuth クライアント作成、承認済みリダイレクトURIの追加)が要るので、「クライアントIDが渡されたときだけ Google を有効にする」実装にしておくと、パスキーだけ先にリリースできる。marp-agent は this.node.tryGetContext('googleClientId') の有無で分岐している。

同じメールアドレスの重複プロフィール

Cognito は、メールアドレスが同じでもローカルユーザーと Google ユーザーを自動で統合しない。放置すると同じ人に2つのプロフィールができる。marp-agent は preSignUp トリガー(google-link)で、確認済みメールアドレスが一致する既存プロフィールへ AdminLinkProviderForUser でリンクしている。デモアプリで既存利用者がいないなら、初期は省いてよい。

5. デモアプリでの判断(外部の人が触る場合)

  • Google の同意画面に出るアプリ名は GCP プロジェクトのブランディングで決まる。クライアントIDを別に作っても、同じプロジェクトなら名前は同じ。外部の人に見せるデモで、無関係な別アプリの名前が出る状態にしない。
  • 管理を楽にするなら、デモ共通の中立な名前でプロジェクトとクライアントを1つ用意し、以後のデモはリダイレクトURIを1行足すだけにする。デモごとに作らない。
  • セキュリティ要件の厳しい組織の利用者は、業務用 Google アカウントを外部アプリへ繋ぐことに抵抗がある。Google を出しても、メール経路を同格で並べる(片方だけにしない)。

6. 検証(実装完了と言う前に)

パスキーは「画面が出た」では動作確認にならない。次を実操作で通す。

  1. メールで新規登録 → 確認コード → ログイン
  2. パスキー登録 → いったんサインアウト → パスキーでログイン
  3. パスキー未登録の状態でパスキーを押し、共通エラーが出てパスワードへ戻れる
  4. Google ログイン(有効にした場合)
  5. PC と iPhone の両方(iOS Simulator か実機の Safari)

localhost は RP ID が localhost になるため、本番ドメインで登録したパスキーはローカルでは使えない。ローカルではパスワード経路で確認する。

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

Deploy, diff, bootstrap, inspect, roll back, or destroy AWS CDK applications with the community CDKD CLI while preserving safe production and state-management boundaries. Use when the user mentions cdkd or CDK Direct, asks for faster CDK deployments in development or test environments, or wants to evaluate whether an existing CDK app can use CDKD. Also use for CDKD import, export, state, events, and deployment troubleshooting. Prefer the upstream AWS CDK CLI for production and for existing CloudFormation-managed stacks unless the user explicitly approves a management migration.

日本語の概要は準備中です。原文の説明を表示しています。

minorun365/agent-builder-skills412026年9月28日 更新

kb-agentcore-cdk

無料日本語概要

AgentCore CDK・デプロイ・ランタイム統合のナレッジ。Runtime作成、JWT認証、SSE、Dockerfile、コンテナ管理、Browser Tool等

minorun365/agent-builder-skills412026年9月28日 更新

kb-agentcore-identity

無料日本語概要

AgentCore Identity(アウトバウンド認証)のナレッジ。3LO/M2M/デコレータ分離/callback等

minorun365/agent-builder-skills412026年9月28日 更新

kb-agentcore-observability

無料日本語概要

AgentCore の Observability ナレッジ。OpenTelemetry 必須4点セット(OTEL_EXPORTER設定・StrandsTelemetry・traceable デコレータ・Langfuse連携)、EMF メトリクス、Jaeger/コンソールエクスポーターでのトレース確認、トレースが出ない・繋がらない場合のデバッグ手順等

minorun365/agent-builder-skills412026年9月28日 更新

kb-frontend-sse

無料日本語概要

SSEストリーミング処理のナレッジ。基本パターン/タイムアウト/リトライ/モック/PDF生成等

minorun365/agent-builder-skills412026年9月28日 更新

kb-lambda-web-adapter-cdk

無料日本語概要

AIエージェントのWebアプリを「AWS CDK(デプロイはCDKD)+ Lambda Web Adapter + CloudFront + AgentCore Runtime」で組むときの全体構成。スタックの分け方、画面を配信するLambdaコンテナのDockerfileと配信サーバー、Function URL を CloudFront の OAC で守る設定と追加で要る権限、runtime-config.json で環境値を渡す型、フロントから AgentCore を直接呼ぶ配線、ローカル開発、デプロイ前後の検証。新しくエージェントのWebアプリを作るとき、Amplify Hosting 以外の配信基盤を選ぶとき、CloudFront 経由の Function URL が 403 になるときに読む。

minorun365/agent-builder-skills412026年9月28日 更新

minorun365 のスキルをすべて見る

このスキルの問題を報告する