Amazon Cognitoのユーザープールは、パスキー(WebAuthn)でのサインインを標準機能として備えています。指紋や顔認証、セキュリティキーでサインインでき、パスワードを入力させずに済む方式です。この記事では、有効化に必要な機能プランと選択式認証の前提、コンソールとAWS CLIでの設定、自作画面からパスキーを登録してサインインさせるSDKコード、MFA設定との衝突条件までを、2026年10月時点の公式ドキュメントに沿って示します。最後に、新規の会員サービスと既存のプールのそれぞれで採用するかどうかを決める条件をまとめました。
まとめ:Cognitoのパスキーは機能プラン・RP ID・MFAの3点を先に決める
結論から書くと、Cognitoのパスキーは設定項目こそ少ないものの、後から変えにくい値が3つあります。1つ目は機能プランで、パスキーはLiteでは使えずEssentials以上が必要です。2つ目はRP ID(リライングパーティID)で、変更すると利用者全員がパスキーを登録し直すことになります。3つ目はMFAとの関係で、MFAを設定済みの利用者は、追加の設定をしない限りパスキーでサインインできません。
実装面では、サインインは選択式認証のUSER_AUTHフローでしか使えず、パスキーだけを唯一のサインイン手段にもできません。パスワードかワンタイムコードでサインインした後に登録させる流れが前提になります。この3点を設計段階で決めておけば、APIの呼び出し自体は登録2回・サインイン2回の往復で済みます。
Cognitoでパスキーを使う前に確認する機能プランと選択式認証の前提
ユーザープールとアプリクライアントがまだ無い場合は、Cognitoで認証基盤を実装する手順:ユーザープール構築からJWT検証までで土台を作ってから本稿に進んでください。パスキーの設定は既存のプールにも後から追加できます。
Essentials以上のプランと選択式認証USER_AUTHが必須になる条件
認証フローの公式ガイドによると、パスキーはLite以外のすべての機能プランで使えるオプトイン機能で、選択式認証フローでのみ利用できます。選択式認証とは、InitiateAuthにAuthFlow: "USER_AUTH"を指定し、パスワード・メールやSMSのワンタイムコード・パスキーのどれでサインインするかを利用者ごとに選ばせる方式です。従来のUSER_PASSWORD_AUTHやUSER_SRP_AUTHのフローからはパスキーを呼べません。
プランごとの料金と機能差はAmazon Cognito(コグニート)とは?料金・できること・使い方をCLIとコード例で解説【2026年10月】にまとめています。Liteのプールでパスキーを使いたい場合は、先にプランを引き上げる必要があります。
公開鍵だけをCognitoに保存し秘密鍵は端末に残すパスキーの仕組み
パスキーの登録時、認証器(スマートフォンやPC、セキュリティキー)は鍵ペアを作り、公開鍵だけをCognitoへ送ります。サインイン時はCognitoが発行したチャレンジに認証器が秘密鍵で署名し、Cognitoが公開鍵で検証します。アプリ側が秘密鍵や生体情報を受け取ることはありません。Cognitoが受け付ける署名アルゴリズムはES256とRS256の2種類です。登録・認証フローやRPの考え方をもう少し詳しく知りたい場合は、WebAuthnとは?パスキー認証を実装する仕組みと登録・認証フロー・RP実装の要点を先に読むと本稿のAPIが追いやすくなります。
ユーザープールとアプリクライアントでパスキーを有効化する手順
有効化に必要な設定は、ユーザープールのサインインポリシー、パスキーの構成、アプリクライアントの認証フローの3か所です。
コンソールの選択式サインインにパスキーを加えて検証方式を選ぶ
コンソールでは、ユーザープールの「サインイン」メニューで「選択式サインインのオプション」を編集し、利用できる選択肢にパスキーを加えます。続いて「認証方法」メニューでパスキーを編集し、ユーザー検証(生体認証やPINによる本人確認)を「優先」と「必須」のどちらにするかと、RP IDに使うドメインを選びます。最後に「アプリケーションクライアント」でクライアントを編集し、認証フローにALLOW_USER_AUTHを加えれば完了です。
ユーザー検証の既定は「優先」で、この場合は検証機能のないセキュリティキーでも登録とサインインが通ります。業務システムなどで端末の持ち主本人であることを確かめたいなら「必須」を選びます。
AWS CLIのSignInPolicyとWebAuthnConfiguration設定
同じ設定をCLIで行う例です。オプション名はupdate-user-poolのCLIリファレンスとset-user-pool-mfa-configのCLIリファレンスで確認できます。
# 1. 現在の設定を退避する(update系は未指定の項目を既定値に戻す)
aws cognito-idp describe-user-pool \
--user-pool-id ap-northeast-1_EXAMPLE > userpool-backup.json
# 2. 第1要素にパスワードとパスキーを許可する(PasswordPolicyは退避した値を渡す)
aws cognito-idp update-user-pool \
--user-pool-id ap-northeast-1_EXAMPLE \
--policies 'PasswordPolicy={MinimumLength=8,RequireUppercase=true,RequireLowercase=true,RequireNumbers=true,RequireSymbols=false},SignInPolicy={AllowedFirstAuthFactors=[PASSWORD,WEB_AUTHN]}'
# 3. RP IDとユーザー検証を設定する(MFAの現在値はget-user-pool-mfa-configで確認して合わせる)
aws cognito-idp get-user-pool-mfa-config --user-pool-id ap-northeast-1_EXAMPLE
aws cognito-idp set-user-pool-mfa-config \
--user-pool-id ap-northeast-1_EXAMPLE \
--mfa-configuration OFF \
--web-authn-configuration RelyingPartyId=example.com,UserVerification=required,FactorConfiguration=SINGLE_FACTOR
# 4. アプリクライアントで選択式認証を許可する
aws cognito-idp update-user-pool-client \
--user-pool-id ap-northeast-1_EXAMPLE \
--client-id 1example23456789 \
--explicit-auth-flows ALLOW_USER_AUTH ALLOW_REFRESH_TOKEN_AUTH
AllowedFirstAuthFactorsにWEB_AUTHNだけを指定することはできず、ほかの要素を最低1つ併記する必要があります。またupdate-user-poolとupdate-user-pool-clientは、指定しなかった属性を既定値に戻すとリファレンスで警告されています。本番では退避したJSONの値をすべて渡すか、CloudFormationやTerraformで管理する方が安全です。
RP IDの決め方:カスタムドメイン・プレフィックス・自前ドメインの違い
RP IDは、パスキーがどのドメインで使えるかを決める値です。ブラウザは、表示中のURLがRP IDのドメインかそのサブドメインでなければパスキー認証を拒否します。公式ガイドが示す既定値と選択肢は次のとおりです。
| 構成 | RP IDの値 | 向いている場面 |
|---|---|---|
| カスタムドメインあり | カスタムドメインのFQDN | マネージドログインを使う |
| プレフィックスのみ | Cognitoのプレフィックスドメイン | 検証環境 |
| 自前のドメイン | 公開サフィックス外の任意ドメイン | SDKで自作画面を作る |
WebAuthnConfigurationTypeのAPIリファレンスによると、マネージドログインかクラシックのホストUIを使い、プールにカスタムドメインがある場合、RP IDはそのカスタムドメインのFQDNでなければなりません。一方、自作画面だけで認証するならexample.comのような親ドメインを指定でき、app.example.comとadmin.example.comの両方で同じパスキーを使えます。モバイルアプリで使う場合は、RP IDのドメインに.well-knownの関連付けファイルを置くことも必要です。RP IDを変えると既存のパスキーはすべて使えなくなるため、公開前に確定させてください。
自作画面でパスキーを登録するSDKコード:StartとCompleteの2段階
マネージドログインを使う場合は、新規登録の直後にCognitoがパスキー登録を促す画面を出します。ここで示すのは、AWS SDK for JavaScript v3とブラウザのWebAuthn APIで、自作画面から登録させる実装です。登録はサインイン済みの利用者しか行えないため、パスワードかワンタイムコードでサインインした後のアクセストークンを使います。
アクセストークンでStartWebAuthnRegistrationを呼ぶ登録手順
import {
CognitoIdentityProviderClient,
StartWebAuthnRegistrationCommand,
CompleteWebAuthnRegistrationCommand,
} from "@aws-sdk/client-cognito-identity-provider";
const client = new CognitoIdentityProviderClient({ region: "ap-northeast-1" });
// サインイン済みの利用者のアクセストークンでパスキーを登録する
export async function registerPasskey(accessToken) {
// 手順1:Cognitoから登録オプション(チャレンジ・RP ID・ユーザー情報)を受け取る
const { CredentialCreationOptions } = await client.send(
new StartWebAuthnRegistrationCommand({ AccessToken: accessToken })
);
const json = typeof CredentialCreationOptions === "string"
? JSON.parse(CredentialCreationOptions)
: CredentialCreationOptions;
// 手順2:ブラウザの認証器に鍵ペアを作らせる
const publicKey = PublicKeyCredential.parseCreationOptionsFromJSON(json);
const credential = await navigator.credentials.create({ publicKey });
// 手順3:認証器の応答をCognitoへ返す(成功時は空の200)
await client.send(
new CompleteWebAuthnRegistrationCommand({
AccessToken: accessToken,
Credential: credential.toJSON(),
})
);
}
StartWebAuthnRegistrationのAPIリファレンスのとおり、アクセストークンにはaws.cognito.signin.user.adminスコープが必要です。マネージドログイン経由で発行したトークンを使う場合は、アプリクライアントの許可スコープにこの値が含まれているか確認してください。CompleteWebAuthnRegistrationは成功すると空の本文で200を返します。
ブラウザ側のparseCreationOptionsFromJSONは2025年3月に主要ブラウザの最新版で使えるようになった比較的新しいAPIで、古い端末では動かない可能性があります。対象端末に古いOSが残る場合は、関数の有無を判定し、無ければbase64urlの変換を自前で行うライブラリに切り替える分岐を入れておきます。credential.toJSON()も同じ扱いです。
登録済みパスキーの一覧と削除:端末の買い替えや紛失に備える管理画面
パスキーは1人あたり20件まで登録できます。端末を買い替えたり紛失したりした利用者のために、登録済みのパスキーを一覧して削除できる管理画面を用意しておいてください。ListWebAuthnCredentialsは、認証器の種類や作成日時、RP IDなどを返します。DeleteWebAuthnCredentialには一覧で得たクレデンシャルIDを渡します。どちらも利用者本人のアクセストークンで認可するAPIで、IAMの権限では呼べません。
パスキーでサインインする実装:USER_AUTHとWEB_AUTHNチャレンジへの応答
サインインは、USER_AUTHフローで認証を始め、返ってきたWEB_AUTHNチャレンジに認証器の署名を返す2往復です。Cognitoはユーザー名を受け取ってからパスキー認証を始めるため、画面ではユーザー名の入力が先に必要になります。
PREFERRED_CHALLENGEにWEB_AUTHNを指定して認証を始める
import {
CognitoIdentityProviderClient,
InitiateAuthCommand,
RespondToAuthChallengeCommand,
} from "@aws-sdk/client-cognito-identity-provider";
const client = new CognitoIdentityProviderClient({ region: "ap-northeast-1" });
const CLIENT_ID = "1example23456789"; // シークレット無しのアプリクライアント
export async function signInWithPasskey(username) {
// 手順1:パスキーを希望して選択式認証を始める
const start = await client.send(
new InitiateAuthCommand({
AuthFlow: "USER_AUTH",
ClientId: CLIENT_ID,
AuthParameters: { USERNAME: username, PREFERRED_CHALLENGE: "WEB_AUTHN" },
})
);
if (start.ChallengeName !== "WEB_AUTHN") {
// パスキー未登録などで使えない場合は選べる方式の一覧が返る
return { fallback: start.AvailableChallenges, session: start.Session };
}
// 手順2:認証器にチャレンジへ署名させる
const options = JSON.parse(start.ChallengeParameters.CREDENTIAL_REQUEST_OPTIONS);
const publicKey = PublicKeyCredential.parseRequestOptionsFromJSON(options);
const assertion = await navigator.credentials.get({ publicKey });
// 手順3:署名をCognitoへ返してトークンを受け取る
const res = await client.send(
new RespondToAuthChallengeCommand({
ClientId: CLIENT_ID,
ChallengeName: "WEB_AUTHN",
Session: start.Session,
ChallengeResponses: {
USERNAME: username,
CREDENTIAL: JSON.stringify(assertion.toJSON()),
},
})
);
return { tokens: res.AuthenticationResult };
}
InitiateAuthのAPIリファレンスの例では、CREDENTIAL_REQUEST_OPTIONSはJSON文字列で返り、チャレンジ、RP ID、利用者が登録済みのクレデンシャルIDの一覧、ユーザー検証の設定が入っています。変換に使うのはparseRequestOptionsFromJSONです。希望したチャレンジが使えない利用者にはAvailableChallengesが返るため、パスワード入力やメールのワンタイムコードへ切り替える画面を用意しておきます。
マネージドログインとAmplifyで登録・認証の実装を省く場合の設定
マネージドログインを使うなら、サインイン画面がユーザー名を受け取り、パスキーの登録有無を確かめてから認証を促すところまでCognitoが処理します。既存の利用者には、サインイン後に/passkeys/addのパスにclient_idとredirect_uriを付けて遷移させると、登録画面を出せます。管理者が作成した利用者や、パスキーを使わずに登録を済ませた利用者には登録を促す画面が出ないため、この導線が必要です。画面の見た目はAWS Cognito Hosted UI(マネージドログイン)のカスタマイズ・日本語化と実装手順で調整できます。
Amplify Gen 2では、パスワードレスの公式ガイドのとおりdefineAuthにwebAuthnを加えるだけで、上記の設定がまとめて作られます。
// amplify/auth/resource.ts
import { defineAuth } from "@aws-amplify/backend";
export const auth = defineAuth({
loginWith: {
email: true, // 初回のサインアップ手段(パスキーだけでは登録できない)
webAuthn: { relyingPartyId: "example.com" },
},
});
フロントエンドでは、サインイン後にassociateWebAuthnCredentialで登録させ、signInのpreferredChallengeにWEB_AUTHNを渡してサインインさせます。Amplifyの全体構成はAmplify×Cognito認証の実装手順:defineAuthと既存プールの参照で解説しています。
MFA設定とパスキーが衝突する条件と多要素認証として数える設定
パスキーの導入でつまずきやすいのが、既存のMFA設定との関係です。公式ドキュメントは、MFAとパスワードレスの要素は原則として両立しないと明記しています。
MFAが任意のプールで設定済みの利用者がパスキーでサインインできない制約
MFAの公式ガイドの表によると、組み合わせごとの挙動は次のとおりです。
| プールのMFA | 利用者のMFA | パスキーでのサインイン |
|---|---|---|
| オフ | 問わない | 可 |
| 任意 | 未設定 | 可 |
| 任意 | 設定済み | 登録できるが使えない |
| 必須 | 設定済み | 不可 |
| 任意・必須で検証付きパスキーをMFA扱い | パスキーMFA | 可 |
見落としやすいのは3行目です。TOTPを設定済みの利用者がパスキーを登録すると、登録は成功するのに、次のサインインではパスキーの選択肢が出ません。問い合わせの原因になりやすいため、MFAを任意で運用しているプールでは次のh3の設定を合わせて検討してください。MFA方式そのものの選び方はCognito MFAの設定手順:TOTP・SMS・メールの有効化と必須化の判断で扱っています。
FactorConfigurationで検証付きパスキーを多要素認証として扱う
WebAuthnConfigurationのFactorConfigurationをMULTI_FACTOR_WITH_USER_VERIFICATIONにすると、ユーザー検証付きのパスキーはそれ単独でMFAの要件を満たします。端末の所持と生体認証やPINを同時に確かめるためです。この設定ならMFA必須のプールでもAllowedFirstAuthFactorsにWEB_AUTHNを加えられます。ただし、メールやSMSのワンタイムコードはMFA必須のプールで第1要素に加えられず、パスキーをパスワードサインインの2要素目に使うこともできません。前述のCLIならFactorConfiguration=MULTI_FACTOR_WITH_USER_VERIFICATIONに変え、あわせてUserVerification=requiredにしておくと、検証機能のない認証器が紛れ込みません。
Cognitoのパスキーを採用する条件と見送るべき場面の判断
ここまでの仕様を踏まえ、案件ごとの判断を条件付きで言い切ります。
新規の会員サービスでの採用判断:パスワード併用で始めて登録を促す
新規に立ち上げる一般消費者向けの会員サービスで、Essentials以上のプランを選べるなら、パスキーは採用してよい機能です。サインアップはメールアドレスで受け、初回のサインイン後にパスキー登録を促し、パスワードとメールのワンタイムコードを予備の手段として残します。パスワードを忘れた利用者がパスキーで戻れるため、Cognitoのパスワードリセット実装:ForgotPasswordと管理者リセット・ロックアウト設計で扱うリセット経路の負担も下がります。MFAを使うなら、最初からMULTI_FACTOR_WITH_USER_VERIFICATIONにしておくと前章の衝突は起きません。
既存のパスワード利用者を段階的に移す進め方や、パスキーを持たない利用者の扱いは、製品に依存しない形でパスキー移行の実装手順:パスワード併存からSignal API・CXPでの鍵移行までにまとめています。
既存のMFA必須プールや複数ドメイン運用で見送る・作り直す場面
見送るか慎重に進めるべきなのは、次の3つの場面です。1つ目は、Liteプランのまま運用しており、利用者数から見てEssentialsへの引き上げ費用が合わない場合に当たります。2つ目は、MFA必須かつ利用者が既にTOTPを設定済みのプールで、FactorConfigurationを変えてもパスキーを持たない利用者の扱いを整理しきれない場合です。3つ目は、マネージドログインとカスタムドメインを使いながら、別ドメインの複数サービスでパスキーを共有したい場合で、RP IDがカスタムドメインのFQDNに固定されるため要件を満たせません。
また、Cognitoは認証器の種類を証明書で検証するアテステーションの強制に対応していません。特定のセキュリティキーだけを許可する、といった社内規程がある業務システムでは、要件を満たせる別の認証基盤を検討する方が確実です。パスワードレスの方式全体の比較はパスワードレス認証とは?方式4分類の実装難度と移行判断を実装者向けに解説を参照してください。既存プールのMFA設定やRP IDの見直しを含めてパスキー導入を進めたい場合は、認証基盤・ID管理システム開発でご相談いただけます。
よくある質問
Cognitoのパスキーについて、実装前によく確認される点をまとめました。
パスキーだけでサインアップさせることはできますか?
できません。パスキーの登録には既存の認証セッションが必要で、利用者は少なくとも1回、パスワードやメールのワンタイムコードなどほかの手段でサインインしている必要があります。サインインポリシーでもWEB_AUTHNは単独で指定できず、ほかの要素を最低1つ併記する必要がある仕様です。メールのワンタイムコードを併用すれば、利用者にパスワードを設定させずに運用できます。
RP IDを後から変更するとどうなりますか?
変更前のRP IDで登録されたパスキーは、新しいRP IDでは使えなくなります。公式ガイドも、RP IDを変えた場合は利用者が新しいRP IDで登録し直す必要があると説明しています。変更が避けられない場合は、パスワードかワンタイムコードでのサインインを残したうえで、再登録を案内する期間を設けてください。
1人の利用者が登録できるパスキーの数に上限はありますか?
1人あたり20件までです。スマートフォン、PC、セキュリティキーを複数持つ利用者でも通常は足ります。上限に達した場合は、ListWebAuthnCredentialsで一覧し、使っていないものをDeleteWebAuthnCredentialで削除してから登録し直します。
クラシックのホストUIでもパスキーは使えますか?
マネージドログインの公式ガイドのとおり、Cognitoが用意するサインイン画面でパスキーを使えるのはマネージドログインだけで、クラシックのホストUIは対象外です。クラシックのまま運用したい場合は、本稿のSDKコードで自作画面にパスキーを組み込むことになります。マネージドログインへの切り替えでは画面デザインの作り直しが発生する点も踏まえて判断してください。
パスキーを有効にすると料金は変わりますか?
パスキーはEssentials以上の機能プランに含まれる機能として提供されており、Lite以外のプランが前提です。Liteで運用しているプールでは、Essentials以上へ引き上げた分の月間アクティブユーザー単価が変わります。プランの単価は改定されることがあるため、採用前にAWSの料金ページで時点の値を確認してください。
関連記事
- Cognitoで認証基盤を実装する手順:ユーザープール構築からJWT検証まで:パスキー設定の前提になるユーザープールとトークン検証の全体像。
- Cognito MFAの設定手順:TOTP・SMS・メールの有効化と必須化の判断:パスキーと衝突しないMFA方式の選び方。
- Cognitoのパスワードリセット実装:ForgotPasswordと管理者リセット・ロックアウト設計:パスワードを残す場合の復旧経路の設計。
- WebAuthnとは?パスキー認証を実装する仕組みと登録・認証フロー・RP実装の要点:登録と認証の仕組みとRP IDの考え方。
- パスキー移行の実装手順:パスワード併存からSignal API・CXPでの鍵移行まで:既存利用者をパスキーへ移す進め方。