AWS Amplify で Amazon Cognito のパスワードレス認証が利用できるようになりました
こんにちは、森田です。
以下のアップデートで AWS Amplify で Amazon Cognito のパスワードレス認証が利用できるようになりました。
本記事では、実際にメールを利用したパスワードレス認証を試してみたいと思います。
やってみた
前提条件
以下のクイックスタート(Next.js App Router)を実施済みとします。
Amplify のバージョン変更
クイックスタートの Amplify のバージョンは最新でないため、以下を実行して変更します。
npm i aws-amplify@6.10.0
Amazon Cognito でパスワードレス認証の有効化
次に、コンソールで Amazon Cognito のパスワードレス認証を有効にします。」
通常、Cognitoの設定値は、defineAuthから変更できるのですが、現在はサポートしていないようです。
Warning: Passwordless configuration is currently not available in defineAuth
Amplifyで作成されたユーザープールを選択し、サインインの設定ページを開きます。
デフォルトでは、以下のようにパスワードレス認証は無効なので、有効化します。
今回は、「メールメッセージのワンタイムパスワード」を選択します。
コードの作成
続いて、サインインページを作成します。
コード全文
"use client";
import { useState } from "react";
import { Amplify } from "aws-amplify";
import { signIn, confirmSignIn } from "aws-amplify/auth";
import outputs from "@/amplify_outputs.json";
Amplify.configure(outputs);
export default function App() {
const [email, setEmail] = useState(""); // メールアドレスの状態
const [otpCode, setOtpCode] = useState(""); // OTPコードの状態
const [isCodeSent, setIsCodeSent] = useState(false); // コード送信済みかどうか
const [isSignedIn, setIsSignedIn] = useState(false); // サインイン済みかどうか
const [error, setError] = useState(""); // エラーメッセージ
// メールアドレスでサインイン開始(OTP送信)
const handleSendCode = async () => {
try {
const { nextStep: signInNextStep } = await signIn({
username: email,
options: {
authFlowType: "USER_AUTH",
preferredChallenge: "EMAIL_OTP",
},
});
if (signInNextStep.signInStep === "CONFIRM_SIGN_IN_WITH_EMAIL_CODE") {
setIsCodeSent(true); // コード送信済み状態に
setError(""); // エラーをリセット
}
} catch (err) {
setError("コード送信中にエラーが発生しました");
}
};
// 確認コードでサインイン完了
const handleConfirmSignIn = async () => {
try {
const { nextStep: confirmSignInNextStep } = await confirmSignIn({
challengeResponse: otpCode,
});
if (confirmSignInNextStep.signInStep === "DONE") {
setIsSignedIn(true); // サインイン済み状態に
setError("");
}
} catch (err) {
setError("サインイン中にエラーが発生しました");
}
};
const styles = {
container: {
fontFamily: "Arial, sans-serif",
textAlign: "center",
backgroundColor: "#f3f4f6",
padding: "50px",
borderRadius: "10px",
width: "350px",
margin: "100px auto",
boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)",
},
heading: {
marginBottom: "20px",
fontSize: "24px",
color: "#333",
},
inputGroup: {
display: "flex",
alignItems: "center",
marginBottom: "20px",
gap: "10px",
},
input: {
flex: 1,
padding: "10px",
borderRadius: "5px",
border: "1px solid #ccc",
},
button: {
padding: "10px 20px",
backgroundColor: "#4CAF50",
color: "white",
border: "none",
borderRadius: "5px",
cursor: "pointer",
fontWeight: "bold",
},
successMessage: {
color: "green",
fontSize: "18px",
fontWeight: "bold",
},
error: {
color: "red",
marginTop: "10px",
},
};
return (
<div>
<h1 style={styles.heading}>Passwordless Sign In</h1>
{!isSignedIn ? (
!isCodeSent ? (
<div style={styles.inputGroup}>
<input
style={styles.input}
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="メールアドレスを入力"
/>
<button
style={styles.button}
onClick={handleSendCode}
disabled={!email}
>
コードを送信
</button>
</div>
) : (
<div style={styles.inputGroup}>
<input
style={styles.input}
type="text"
value={otpCode}
onChange={(e) => setOtpCode(e.target.value)}
placeholder="確認コードを入力"
/>
<button
style={styles.button}
onClick={handleConfirmSignIn}
disabled={!otpCode}
>
サインイン
</button>
</div>
)
) : (
<p style={styles.successMessage}>サインインに成功しました!</p>
)}
{error && <p style={styles.error}>{error}</p>}
</div>
);
}
パスワードレスの指定
signIn関数のpreferredChallenge
にどのタイプのパスワードレスを利用するかを指定します。
const { nextStep: signInNextStep } = await signIn({
username: email,
options: {
authFlowType: "USER_AUTH",
preferredChallenge: "EMAIL_OTP",
},
});
他にも以下が指定できます。
- SMS OTP
- WebAuthn Passkeys
動作確認
では、実際にアプリケーションを動かして、動作確認してみます。
npm run dev
アプリケーション起動後、http://localhost:3000/signin
にアクセスします。
メールアドレスを入力し、「コードを送信」をクリックします。
しばらくすると、メールアドレスに認証コードが送信されます。
このコードをアプリケーション上で入力し、「サインイン」をクリックします。
無事にサインインできました!
さいごに
かなり簡単にパスワードレス認証を試すことができました。
現状は、手動で Cognito でパスワードレス認証の有効化を行う必要があるため、今後defineAuth
でサポートされることを期待しています。