NTT東日本の中村です。
Amplify Gen1では、認証のログインにユーザ名を指定することができます、 Amplify Gen2では、ユーザ名を指定できないように見えますが、CDKを使えば実現できるようです。
概要
AmplifyのGen1,Gen2のどちらも、ユーザ認証のシステムに、内部でAmazon Cognitoを使用しています。
Amazon Cognitoは、認証のオプションにユーザ名、Eメール、電話番号を選択することができます。 マネジメントコンソールからAmazon Cognitoを作成すると、選択肢からユーザ名を選ぶことができます。
Amplify Gen1でも、amplify add Authを実行した時、選択肢にユーザ名(Username)を選ぶことができます。
Amplify Gen2は、auth/resource.tsの中で認証方法を定義しますが、emailとphoneのみが許可されており、ユーザ名を選ぶことができません。 Cognitoでは選べるが、Amplify Gen2では意図的にユーザ名でのログインが隠されている事が分かります。
ただし、移行ガイドを見ると「CDKで実現可能」と書かれています。 何故隠されているのか?と、どのように実現出来るのか?を調査しました。
調査してみた
ユーザ名の取り扱いについて、こちらで書かれています。
何故隠されているのか
Amazon Cognito では、ユーザー名は不変です。つまり、最初のサインアップ後は、ユーザーはユーザー名を変更できません。一部のアプリケーションでは、これは望ましくない場合があり、その場合はエイリアス属性を使用することをお勧めします。エイリアス属性を使用すると、不変のユーザー名に加えて、変更可能な「優先ユーザー名」を定義できます。
Username属性は不変であり、一度設定すると変更できません。この値をログインに使用すると、リスクが発生する場合がある、という判断を行っているようです。
ただし、Gen1からGen2へのマイグレーションを行う場合、既存ではユーザ名でログインを行っていたシステムも多く、ユーザ名でどうしてもログインしたい、というニーズは存在します。
どの様に実現できるのか
ドキュメントを見ると、CDKのオーバーライドで、usernameAttributes属性からEメール、電話番号を取り除き、空配列で定義することで、ユーザ名でログインができるようです。
amplify/backend.ts
import { defineBackend } from "@aws-amplify/backend";
import { auth } from "./auth/resource.js";
import { data } from "./data/resource.js";
const backend = defineBackend({
auth,
data,
});
const { cfnUserPool } = backend.auth.resources.cfnResources;
// an empty array denotes "email" and "phone_number" cannot be used as a username
cfnUserPool.usernameAttributes = [];
ちなみに、usernameAttributesに、preferred_username等の他のユーザー属性を設定することはできませんでした。
usernameAttributes' failed to satisfy constraint: Member must satisfy constraint: [Member must satisfy enum value set: [phone_number, email]]
適当なログイン画面を用意します。
app/page.tsx
"use client";
import { Authenticator } from '@aws-amplify/ui-react'
import { Amplify } from "aws-amplify";
import outputs from "@/amplify_outputs.json";
import '@aws-amplify/ui-react/styles.css'
Amplify.configure(outputs);
export default function App() {
return (
<Authenticator>
{({ signOut, user }) => (
<main>
login successful
</main>)}
</Authenticator>
);
}
ログインに成功しました。
ログイン属性にユーザ名が使用されていることが分かります。
上の画像ではエイリアス属性と書かれていますが、実際には不変のUsername属性が使われており、変更することができません。
aws cognito-idp admin-get-user --user-pool-id ap-northeast-1_hogehoge --username test
{
"Username": "test",
"UserAttributes": [
{
"Name": "email",
"Value": "hoge@hoge.jp"
},
{
"Name": "email_verified",
"Value": "true"
},
{
"Name": "sub",
"Value": "d7748af8-a081-70c7-0671-2b11432e3b71"
}
],
"UserCreateDate": "2024-06-26T06:48:48.017000+00:00",
"UserLastModifiedDate": "2024-06-26T06:49:30.916000+00:00",
"Enabled": true,
"UserStatus": "CONFIRMED"
}
ユーザ名で問題なくログインできることも確認できました。
まとめ
Gen2では、ユーザ名とパスワードでのログインを勧めておらず、エイリアス属性のEmailや電話番号を勧めています。ユーザ名は、一度設定すると変更ができない為です。
しかしながら、CDKからオーバーライドを行うことで、ユーザ名でのログインは可能なので、マイグレーション等で必須の対応がある時は検討できる選択肢だと思います。