AWS

Amplify×Cognito認証の実装手順:defineAuthと既存プールの参照

Amplify×Cognito認証の実装手順:defineAuthと既存プールの参照

AWS Amplify Gen 2では、amplify/auth/resource.tsにdefineAuthを書いてnpx ampx sandboxを実行すると、Amazon Cognitoのユーザープール・アプリクライアント・IDプールがまとめて作られます。本記事では、defineAuthが作るCognitoリソースの既定値をamplify-backendのソースコードで確かめたうえで、MFA・外部IdP・グループの追加、既存ユーザープールをreferenceAuthで取り込む手順、フロントエンドのsignInとfetchAuthSessionの実装をコード付きで整理する記事です。初回デプロイ後に変えられない設定と、ユーザープールを消してしまう既定の削除ポリシーへの備えも扱います。

まとめ:Amplify Gen 2でCognito認証を組む前に決める5つの設定

Amplify Gen 2のAuthは、Cognitoとは別の認証サービスではありません。defineAuthのTypeScriptコードがCDK経由でCognitoのリソースを生成し、フロントエンドは生成されたamplify_outputs.jsonを読んで接続する仕組みです。実装前に決めておくのは次の5点です。

  1. ログイン方式(メールか電話番号か)と必須属性は初回デプロイ前に確定する。後から追加も変更もできない
  2. ユーザープールの削除ポリシーは既定でDESTROY。本番ブランチだけ削除保護をCDKで上書きする
  3. MFAはmultifactor、外部IdPはexternalProviders、権限の束はgroupsで宣言する
  4. 既存のユーザープールを使うならreferenceAuthで参照する。Amplify側から設定は変えられない
  5. ログイン画面を自作するなら、signInが返すnextStepで画面を分岐し、トークンはfetchAuthSessionで取る

判断の軸は1つに絞れます。ユーザーデータをアプリと同じタイミングで消してよいならdefineAuthで新規作成し、アプリより長く残すならCognitoを別管理にしてreferenceAuthで参照します。

defineAuthとnpx ampx sandboxでCognitoリソースを作る手順

Amplify Gen 2全体の構成と料金はAWS Amplifyとは?Gen 2のバックエンド定義と料金・採用判断で整理しています。ここからは認証部分だけを掘り下げます。

resource.tsにdefineAuthを書きサンドボックスへ反映する手順

前提とする版は、バックエンド定義の@aws-amplify/backendが1.25系、フロントエンドのaws-amplifyが6.22系です(npmレジストリで2026年10月18日時点の最新はそれぞれ1.25.1と6.22.2)。npm create amplify@latestで作ったプロジェクトには、公式のSet up Amplify Authと同じ最小構成が入っています。

// amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
  },
});

// amplify/backend.ts
import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource';

export const backend = defineBackend({ auth });

この状態でnpx ampx sandboxを実行すると、開発者ごとのサンドボックス環境にCognitoのリソースがデプロイされ、接続情報を書いたamplify_outputs.jsonがプロジェクト直下に生成されます。フロントエンドはこのファイルをAmplify.configure(outputs)に渡すだけで接続できる仕組みです。サンドボックスの使い分けや後始末はAWS Amplify Gen 2の使い方:ampxで初期化からCI/CDまでに譲ります。

defineAuthが作るユーザープール・クライアント・IDプールの既定値

defineAuthの実体は、amplify-backendリポジトリのauth-constructパッケージです。construct.tsとdefaults.tsを読むと、何も指定しないときに作られる設定が分かります(2026年10月時点のmainブランチ)。

項目 既定値 実務上の意味
ログイン方式 メール ユーザー名ログインは作られない
セルフサインアップ 有効 招待制なら上書きが要る
パスワード 8文字以上・英大小・数字・記号 社内規程と照合する
認証フロー SRPとカスタム ブラウザから直接呼べる
存在エラーの抑止 有効 登録済みかを漏らさない
IDプールの未認証ID 許可 ゲスト用ロールが作られる
削除ポリシー DESTROY スタック削除でユーザーも消える
機能プラン 指定なし 新規作成ではEssentials

見落としやすいのは下の3行です。IDプールが未認証IDを許可しているので、ログイン前の利用者にもゲスト用のIAMロールが割り当たります。公開前にこのロールの権限を確認してください。機能プランはdefineAuthのコードで指定されておらず、CDKのUserPoolリファレンスでは新規作成時の既定がEssentialsとされています。Cognitoの料金はMAUと機能プランで決まるため、利用者数別の月額はCognitoで認証基盤を実装する手順の料金比較で確かめておくと見積もりがぶれません。

初回デプロイ前に決めるべきCognitoの変更不可設定と削除保護

defineAuthは何度でもデプロイできますが、Cognito側には作成後に変えられない設定があります。

loginWithと必須属性は初回デプロイ後に追加も変更もできない

公式のAmplify Authの概念ページは、サインイン方法(username・email・phone)を初期設定後に追加・変更できないこと、必須属性も同じ扱いであることを明記しています。loginWithのemail: trueをphone: trueに書き換えても、既存のユーザープールの設定は差し替わりません。利用者を新しいユーザープールへ移す作業が発生します。

初回デプロイ前に決めるのは次の3点です。

  • ログインIDをメールにするか電話番号にするか。両方の可能性があるなら最初から両方を有効にする
  • 必須属性に何を置くか。外部IdPを使う場合、必須属性は外部IdPの属性から必ずマッピングできるものに限る
  • 将来増える項目はカスタム属性として後から追加する前提にし、標準属性の必須化で先取りしない

迷ったら必須属性はメールだけにとどめます。必須属性は後から外せない一方、任意の項目は登録後のプロフィール画面で集められるからです。

ユーザープールの削除ポリシーDESTROYと本番ブランチの削除保護

construct.tsはユーザープールをremovalPolicy: RemovalPolicy.DESTROYで作成しています。npx ampx sandbox deleteでサンドボックスを消したときに残骸が残らない利点がある反面、ブランチ環境のスタックを削除すると、そのブランチの利用者もまとめて消えます。Cognitoは既存ユーザーのパスワードを書き出せないため、消えた利用者は元に戻せません。

本番ブランチだけは、公式のModify Amplify-generated Cognito resources with CDKが示すcfnResourcesからCfnUserPoolを取り出し、CloudFormationのAWS::Cognito::UserPoolにあるDeletionProtectionを有効にします。

// amplify/backend.ts
import { defineBackend } from '@aws-amplify/backend';
import { RemovalPolicy } from 'aws-cdk-lib';
import { auth } from './auth/resource';

const backend = defineBackend({ auth });
const { cfnUserPool } = backend.auth.resources.cfnResources;

// 本番ブランチに設定した環境変数でだけ有効にする(サンドボックスは削除できる状態を保つ)
if (process.env.PROTECT_USER_POOL === 'true') {
  cfnUserPool.deletionProtection = 'ACTIVE';
  cfnUserPool.applyRemovalPolicy(RemovalPolicy.RETAIN);
}

PROTECT_USER_POOLは本記事で置いた変数名で、Amplifyコンソールで本番ブランチの環境変数として設定します。削除保護だけを掛けるとスタック削除そのものが失敗し、RETAINだけではコンソールからの手作業の削除を防げません。両方を掛ければ、スタックを消してもユーザープールは残り、誤ってDeleteUserPoolを呼んでもInvalidParameterExceptionで止まります。

MFA・外部IdP・グループをdefineAuthに追加してCognitoを広げる

いずれもCognitoの同名機能をTypeScriptで宣言する設定です。

multifactorでTOTPとメールMFAを有効にする設定と前提条件

// amplify/auth/resource.ts
import { defineAuth } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: { email: true },
  multifactor: {
    mode: 'OPTIONAL',
    totp: true,
    email: true,
  },
  senders: {
    email: {
      fromEmail: '[email protected]',
      fromName: 'My App',
    },
  },
});

公式のMulti-factor authenticationによると、メールMFAには前提が3つあります。機能プランがEssentialsかPlusであること、Amazon SESから送信すること、アカウント復旧の配信方法をメールのみにしないことです。senders.email.fromEmailを書くとconstruct.tsはSES経由の送信設定を作るので、送信元アドレスはSESで検証を済ませておきます。SMSを使う場合は発信番号の申請が別途必要です。MFAとパスワードレスサインインは併用できません。

modeは'OPTIONAL'から始めるのが無難です。'REQUIRED'は全員に方式の登録を強制するため、端末を紛失した利用者の設定を管理者がAdminSetUserMFAPreferenceで戻す手順まで用意してから切り替えます。

外部IdPをexternalProvidersで連携しsecretを登録する手順

// amplify/auth/resource.ts
import { defineAuth, secret } from '@aws-amplify/backend';

export const auth = defineAuth({
  loginWith: {
    email: true,
    externalProviders: {
      google: {
        clientId: secret('GOOGLE_CLIENT_ID'),
        clientSecret: secret('GOOGLE_CLIENT_SECRET'),
        attributeMapping: { email: 'email' },
      },
      oidc: [
        {
          name: 'MicrosoftEntraID',
          clientId: secret('MICROSOFT_ENTRA_ID_CLIENT_ID'),
          clientSecret: secret('MICROSOFT_ENTRA_ID_CLIENT_SECRET'),
          issuerUrl: '<your-issuer-url>',
        },
      ],
      callbackUrls: ['http://localhost:3000/profile', 'https://mywebsite.com/profile'],
      logoutUrls: ['http://localhost:3000/', 'https://mywebsite.com'],
    },
  },
});

secret()の値はコードに書きません。サンドボックスではnpx ampx sandbox secret set GOOGLE_CLIENT_IDを実行して値を入力し、ブランチ環境ではAmplifyコンソールで登録します(公式のExternal identity providersとCLI commands)。

詰まりやすいのはCognitoドメインです。外部プロバイダーを設定すると、Amplifyはドメインのプレフィックスをバックエンド固有のハッシュから自動生成し、ユーザープールにドメインを追加します。GoogleやEntra IDのアプリ登録に書くリダイレクトURIhttps://<ユーザープールのドメイン>/oauth2/idpresponseは、初回デプロイが終わるまで確定しません。一度デプロイしてamplify_outputs.jsonのドメインを確かめ、IdP側に書き戻す2段階の作業になります。フロントエンドからはsignInWithRedirect({ provider: { custom: 'MicrosoftEntraID' } })で各IdPへ遷移させます。

groupsとpostConfirmationトリガーで登録者を自動でグループに入れる

groups: ['ADMINS', 'EDITORS']を書くと、グループごとにIAMロールの付いたCognitoのグループが作られ、所属はIDトークンとアクセストークンのcognito:groupsクレームに入ります(公式のUser groups。上限はユーザープールあたり10,000グループ)。登録直後の利用者を既定グループへ入れるには、公式のAdd user to groupのとおり、postConfirmationトリガーのLambdaからAdminAddUserToGroupCommandを呼びます。

// amplify/auth/post-confirmation/handler.ts
import type { PostConfirmationTriggerHandler } from 'aws-lambda';
import {
  CognitoIdentityProviderClient,
  AdminAddUserToGroupCommand,
} from '@aws-sdk/client-cognito-identity-provider';
import { env } from '$amplify/env/post-confirmation';

const client = new CognitoIdentityProviderClient();

export const handler: PostConfirmationTriggerHandler = async (event) => {
  await client.send(new AdminAddUserToGroupCommand({
    GroupName: env.GROUP_NAME,
    Username: event.userName,
    UserPoolId: event.userPoolId,
  }));
  return event;
};

// amplify/auth/resource.ts(抜粋。postConfirmationはdefineFunctionで定義し環境変数GROUP_NAMEを渡す)
export const auth = defineAuth({
  loginWith: { email: true },
  groups: ['EVERYONE'],
  triggers: { postConfirmation },
  access: (allow) => [
    allow.resource(postConfirmation).to(['addUserToGroup']),
  ],
});

accessの付与を書き忘れると、Lambdaの実行ロールにAdminAddUserToGroupの権限が付かず、呼び出しが拒否されます。公式の注記どおり、ソーシャルサインインの利用者はこのトリガーの対象外です。外部IdPを併用するなら、グループを付与する経路を別に用意します。

既存のCognitoユーザープールをreferenceAuthで取り込む手順

Amplify Gen 1や別のCDK・Terraformで作ったユーザープールは、作り直さずにreferenceAuthで参照します。

referenceAuthに渡す5つのIDとARNの調べ方と環境変数での切替

公式のUse existing Cognito resourcesが求めるのは、ユーザープールID、アプリクライアントID、IDプールID、IDプールの認証済みロールARN、未認証ロールARNの5つです。ユーザープール単体では足りません。

// amplify/auth/resource.ts
import { referenceAuth } from '@aws-amplify/backend';

export const auth = referenceAuth({
  userPoolId: process.env.MY_USER_POOL_ID,
  identityPoolId: process.env.MY_IDENTITY_POOL_ID,
  authRoleArn: process.env.MY_AUTH_ROLE_ARN,
  unauthRoleArn: process.env.MY_UNAUTH_ROLE_ARN,
  userPoolClientId: process.env.MY_USER_POOL_CLIENT_ID,
});

2つのロールARNはaws cognito-identity get-identity-pool-rolesの出力にあるRoles.authenticatedとRoles.unauthenticatedから取れます。環境変数はサンドボックスなら手元のシェルに、ブランチ環境ならAmplifyコンソールに設定するため、開発用と本番用で別のユーザープールを指定できる仕組みです。既存のグループを使う場合は、groupsにグループ名とそのIAMロールARNの対応を追加します。

既存のユーザープールにIDプールが無い構成も珍しくありません。その場合は先にIDプールを作り、ユーザープールとアプリクライアントを認証プロバイダーとして登録してからreferenceAuthを書きます。

referenceAuthで取り込んだ場合にAmplifyから変更できない範囲

referenceAuthは参照であって管理ではありません。公式ページは次の制約を挙げています。

  • Amplifyは参照先リソースの設定を変更できない。MFAや外部IdPはCognito側で設定する
  • Amplifyが取り込むのは参照した時点の設定で、その後のCognito側の変更は自動では反映されない
  • Amplifyアプリ固有のIAMポリシーが認証済み・未認証の両ロールに追加され、アプリからユーザープールへのユーザー作成やIDプールへのID作成ができる状態になる
  • それ以上の権限が要る場合は、ロールへ手作業でポリシーを足す

3つ目は、ほかのシステムとIDプールを共有している場合に効いてきます。同じロールを使う別システムの利用者にも、Amplifyアプリ用のポリシーが付くからです。共有しているユーザープールを参照するなら、Amplify専用のIDプールとロールを切り出してからreferenceAuthに渡すと、権限の境界が明確になります。

フロントエンドでsignInとfetchAuthSessionを呼びログイン状態を扱う

Amplify UIのAuthenticatorなら数行でログイン画面を出せます。日本語化を含むAuthenticatorの使い方はCognito Hosted UI(マネージドログイン)のカスタマイズ・日本語化と実装手順で扱っているので、ここでは自社デザインの画面をaws-amplify/authのAPIで組む場合を解説します。

Authenticatorを使わずsignInのnextStepで画面遷移を分ける実装

自作画面の要は、signInが返すnextStep.signInStepで次の画面を決めることです(公式のSign-in)。

import { signIn, confirmSignIn } from 'aws-amplify/auth';

export async function login(email: string, password: string) {
  const { nextStep } = await signIn({ username: email, password });

  switch (nextStep.signInStep) {
    case 'DONE':
      return 'home';
    case 'CONFIRM_SIGN_IN_WITH_TOTP_CODE':
    case 'CONFIRM_SIGN_IN_WITH_EMAIL_CODE':
      return 'mfa-code';        // コード入力画面へ
    case 'CONFIRM_SIGN_UP':
      return 'confirm-sign-up'; // 登録確認が終わっていない
    case 'RESET_PASSWORD':
      return 'reset-password';
    default:
      return 'unsupported';     // 画面を用意していないステップは明示的に止める
  }
}

export async function submitMfaCode(code: string) {
  const { nextStep } = await confirmSignIn({ challengeResponse: code });
  return nextStep.signInStep === 'DONE';
}

公式ページの表には、signInStepが14種類並んでいます(2026年10月時点)。MFAを'OPTIONAL'にしただけでも、TOTPを登録した利用者にはCONFIRM_SIGN_IN_WITH_TOTP_CODEが返ります。'DONE'だけを見る実装は、MFAを有効にした日にログインできない利用者を生む原因です。default節で未対応のステップを止めておけば、Cognito側の設定変更に画面が追いついていないことにすぐ気付けます。

fetchAuthSessionで得たcognito:groupsで画面を出し分ける

ログイン後のトークンはfetchAuthSessionで取得します(公式のManage user sessions)。期限切れでもリフレッシュトークンが有効なら自動で更新され、forceRefresh: trueで明示的に更新することもできます。外部IdPのセッションは既定では更新できない点に注意してください。

import { fetchAuthSession } from 'aws-amplify/auth';

export async function isAdmin(): Promise<boolean> {
  const { tokens } = await fetchAuthSession();
  const groups = tokens?.accessToken.payload['cognito:groups'];
  return Array.isArray(groups) && groups.includes('ADMINS');
}

この判定は管理メニューの表示切替までに使い、APIの認可には使いません。API側ではアクセストークンの署名を検証してからcognito:groupsを見ます。API Gatewayで受ける方式はAPI Gatewayの認証:Cognito・JWT・Lambdaオーソライザー・IAM認可の使い分け、自前のバックエンドでの署名検証はCognitoで認証基盤を実装する手順のJWT検証の章で解説しています。

Amplify Gen 2でCognitoを管理する構成を採用する条件と見送る場面

defineAuthとreferenceAuthのどちらを選ぶかは、コードの書きやすさではなく、ユーザープールの寿命で決めます。

defineAuthでCognitoを新規作成してよいプロジェクトの条件

defineAuthで作ってよいのは、ユーザープールの寿命がそのAmplifyアプリと一致するプロジェクトです。次の条件がすべてそろうなら、defineAuthを選びます。

  • 認証を使うのがそのAmplifyアプリだけで、ほかのシステムから同じユーザープールを使う予定がない
  • ログイン方式と必須属性を初回デプロイ前に確定できる
  • 本番ブランチに削除保護の上書きを入れる運用を受け入れられる

PoCや社内向けの小規模アプリは、たいていこの条件に収まります。

Cognitoを別管理にしてreferenceAuthで参照すべき場面

次のどれかに当てはまるなら、defineAuthでの新規作成は見送ります。

  • 会員基盤を複数のアプリ(Webとスマホアプリ、顧客画面と管理画面など)で共有する
  • 既に利用者が登録済みのユーザープールがあり、作り直すと全員にパスワードの再設定を求めることになる
  • TerraformなどAmplify以外のIaCでAWS環境全体を管理している

この場合はCognitoをアプリより長く残るインフラとして別スタックで管理し、AmplifyからはreferenceAuthで参照します。DESTROYによる消失も、loginWithの書き換えでユーザープールの作り直しを迫られる事態も、構成の段階で避けられる仕組みです。既存の会員基盤の移行やSSO連携を含めて設計を相談したい場合は、一創の認証基盤・ID管理システム開発でユーザープールの分け方から実装まで対応しています。

よくある質問

Amplify Gen 2とCognitoの組み合わせで、実装時によく出る疑問をまとめました。

Amplify Gen 1で使っていたCognitoはGen 2でもそのまま使えますか?

使えます。Gen 2のプロジェクトでreferenceAuthに、Gen 1が作ったユーザープール・アプリクライアント・IDプールのIDと2つのロールARNを渡します。ユーザーとパスワードはCognito側に残るため、利用者の移行は発生しません。参照したリソースの設定はAmplifyから変えられないので、MFAや外部IdPの追加はCognitoのコンソールかIaCで行います。

defineAuthで作ったユーザープールのパスワードポリシーは変えられますか?

作成後でも変更が可能です。amplify/backend.tsでbackend.auth.resources.cfnResources.cfnUserPoolを取り出し、policies.passwordPolicyを上書きします。公式の例では最小文字数を10、一時パスワードの有効日数を20日に設定しています。ログイン方式や必須属性とは違い、ユーザープールの作り直しは要りません。

サンドボックスを削除すると、登録したテストユーザーはどうなりますか?

ユーザープールごと消えるため、テストユーザーも残りません。使い回したい場合は、作成手順をスクリプト化しておくか、開発用のユーザープールを別に作ってreferenceAuthで参照する方法があります。

AmplifyでもCognitoのマネージドログイン画面は使えますか?

マネージドログイン画面も利用可能です。externalProvidersを設定するとユーザープールにCognitoドメインが追加され、signInWithRedirectでCognitoの画面へ遷移する構成を取れます。ロゴや配色の調整、日本語化の範囲はマネージドログイン側の機能で決まります。

AuthenticatorとsignInのAPIはどちらを使うべきですか?

見た目と文言をAmplify UIの範囲に収められるならAuthenticatorです。登録・ログイン・MFA・パスワード再設定の画面遷移を自前で書かずに済みます。自社のデザインシステムに合わせる、独自の入力項目を足すといった要件があるなら、signInとconfirmSignInで画面を組み、MFA設定を変える前に全ステップの画面を用意してください。

関連記事

お気に入りに入れた記事の一覧

この記事は以下の記事からリンクされています

資料請求

今日のトレンド記事 直近 24 時間で、いつもより多く読まれている記事

  1. 2026.10.15 テックブログ リゾートトラスト不正アクセス:会員2.6万件・カハラ横浜3.6万件の対象確認と窓口
  2. 2026.10.16 テックブログ バーガーキング不正アクセスで約1,118万件の情報漏洩|対象確認・案内メールの真偽と運営側のログ点検
  3. 2026.10.16 テックブログ ソースネクスト不正アクセスで最大2,252万件流出|ログインできない理由・パスワード再設定と会員APIの点検
  4. 2026.10.15 テックブログ 銀のさら不正アクセス:最大650万件の対象確認と窓口、パスワード変更の手順
  5. 2026.10.16 テックブログ ワラウ不正アクセスで連携トークン流出|Yahoo! JAPAN ID再連携と対象確認

RELATED POSTS 関連記事

目次