はじめに
先日、Amplify Gen2のAuthを使って、認証機能を実装してみました。
認証画面にはAmplifyが提供するAuthenticator
を使い、デフォルトの画面を表示していました。
↓ 以下がデフォルトのサインイン画面なのですが、寂しくないですか!
というこで今回は、Authenticator
で表示できるサインイン画面をどこまカスタマイズできるか試したいと思います。
最終的なソースコードはこちら
import { ThemeProvider, Authenticator, translations, useTheme, useAuthenticator } from '@aws-amplify/ui-react';
import type { Theme } from '@aws-amplify/ui-react';
import { I18n } from "aws-amplify/utils";
import { View, Flex, Image, Text, Heading, Card, Divider, Link } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
import '../lib/amplify';
import AppIconSVG from '../assets/app_icon.svg';
I18n.putVocabularies(translations);
I18n.setLanguage('ja');
I18n.putVocabularies({
ja: {
'Sign In': 'ログイン',
'Sign in': "ログイン",
'Enter your Email': "メールアドレスを入力してください",
'Enter your Password': "パスワードを入力してください",
'Create Account': "新規ユーザー登録",
},
});
const theme: Theme = {
name: 'custom-theme',
tokens: {
components: {
button: {
primary: {
backgroundColor: { value: '{colors.blue.60}' },
_hover: {
backgroundColor: { value: '{colors.purple.80}' },
},
},
},
authenticator: {
router: {
borderStyle: 'none',
boxShadow: 'none',
},
},
},
},
};
export default function AuthProvider({
children,
}: {
children: React.ReactNode;
}) {
const components = {
// 共通ヘッダー
Header(): any {
const { tokens } = useTheme();
return (
<Card
variation="elevated"
borderRadius="1.5rem 1.5rem 0 0"
display="flex"
style={{ flexDirection: 'column', alignItems: 'center', justifyContent: 'center' }}
>
<Image src={AppIconSVG} alt="App Icon" height="60px" margin={tokens.space.xs}/>
<Heading level={3} textAlign={"center"}>
ようこそ
</Heading>
</Card>
);
},
// 共通フッター
Footer() {
const { tokens } = useTheme();
return (
<Card
variation="elevated"
borderRadius="0 0 1.5rem 1.5rem"
padding={tokens.space.md}
boxShadow="none"
>
<Text
variation='info'
textAlign={"center"}
fontSize={tokens.fontSizes.xs}
>
© 2025 Takenoko4594. All rights reserved.
</Text>
</Card>
);
},
SignIn: {
// ログイン画面のヘッダー
Header(): any {
const { tokens } = useTheme();
return (
<Text
textAlign="center"
color={tokens.colors.font.tertiary}
>
アカウントにログインしてください
</Text>
);
},
// ログイン画面のフッター
Footer() {
const { tokens } = useTheme();
const { toForgotPassword, toSignUp } = useAuthenticator();
return (
<>
<View
textAlign="center"
marginTop={tokens.space.xs}
>
<Link
onClick={toForgotPassword}
color={tokens.colors.blue[60]}
>
パスワードをお忘れですか?
</Link>
</View>
<Divider size="small"/>
<Flex justifyContent="center">
<Text>アカウントをお持ちでない方は</Text>
<Link
onClick={toSignUp}
color={tokens.colors.blue[60]}
>
新規ユーザー登録
</Link>
</Flex>
</>
);
}
}
}
const formFields = {
signIn: {
username: {
isRequired: true,
},
},
}
// 画面の背景デザイン
const AuthenticatorBackground = ({ children }: { children: React.ReactNode }) => {
return (
<div
className="
relative
h-screen
w-screen
flex
items-center
justify-center
overflow-hidden
bg-gradient-to-br
from-[#667eea]
to-[#764ba2]
"
>
<style>{`
@keyframes float {
0%, 100% { transform: translate(0, 0) rotate(0deg); }
33% { transform: translate(100px, -100px) rotate(120deg); }
66% { transform: translate(-50px, 50px) rotate(240deg); }
}
`}</style>
{/* 浮遊する水玉 */}
<div
className="
absolute
-top-24
-left-24
w-[300px]
h-[300px]
rounded-full
bg-white/10
pointer-events-none
"
style={{ animation: 'float 20s ease-in-out infinite' }}
/>
<div
className="
absolute
-bottom-12
-right-12
w-[200px]
h-[200px]
rounded-full
bg-white/10
pointer-events-none
"
style={{ animation: 'float 20s ease-in-out infinite', animationDelay: '5s' }}
/>
<div
className="
absolute
top-1/2
right-[10%]
w-[150px]
h-[150px]
rounded-full
bg-white/10
pointer-events-none
"
style={{ animation: 'float 20s ease-in-out infinite', animationDelay: '10s' }}
/>
{children}
</div>
);
}
const AuthenticatorStyleWrapper = ({ children }: { children: React.ReactNode }) => {
return (
<div
className='
[&_[role="tablist"]]:!hidden
[&_div[data-amplify-router-content]]:!py-0
[&_div[data-amplify-container]]:!shadow-2xl
'
>
{children}
</div>
);
}
return (
<ThemeProvider theme={theme}>
<AuthenticatorBackground>
<AuthenticatorStyleWrapper>
<Authenticator
formFields={formFields}
components={components}
>
{children}
</Authenticator>
</AuthenticatorStyleWrapper>
</AuthenticatorBackground>
</ThemeProvider>
);
}
概要
Auth機能を使えばサクッと認証機能が実装できる
Amplify Gen2には、Authという機能があります。
Authを使用することで、TypeScriptのコードから簡単にAmazon Cognito
をデプロイできます。
以下のコードはAmplifyのセットアップ時に作成されますが、このコードだけでAmazon Cognitoのユーザープールも作成されます。
import { defineAuth } from "@aws-amplify/backend"
export const auth = defineAuth({
loginWith: {
email: true,
},
})
フロントエンドとの連携もバッチリサポート
Amplifyは、フロントエンドとAuthで構築したAmazon Cognitoとの連携もサポートしています。
フロントエンド側では、Amplifyが提供するAuthenticator
を組み込むことで、簡単に連携が完了します。これで先ほどのデフォルトのサインイン画面を表示出来ちゃいます。
import { Authenticator } from '@aws-amplify/ui-react';
import '@aws-amplify/ui-react/styles.css';
export default function AuthProvider({
children,
}: {
children: React.ReactNode;
}) {
return (
<Authenticator>
{children}
</Authenticator>
);
}
だけど、デフォルトの画面だと味気ない...
ということで今回いろいろとカスタマイズしてみよう!という話になります。
やってみる
前提
- フロントエンドは
Vite
+React
+TypeScipt
で構築します - デザインは一部
tailiwindcss
を使ってスタイルを指定しています - 既にAuth機能でAmazon Cognitoがセットアップ済み状態をスタートとします
カスタム1. 表示言語を日本語化したい
Authenticator
の表示言語は、デフォルトだと英語
で表示されます。
これを日本語に変更します。
Amplify UIは、多言語対応のためI18n
という機能を提供しています。
I18n
の設定を変更すれば、日本語でも表示できます。
+ import { Authenticator, translations } from '@aws-amplify/ui-react'; // translationsを追加
+ import { I18n } from "aws-amplify/utils";
import '@aws-amplify/ui-react/styles.css';
import '../lib/amplify';
+ I18n.putVocabularies(translations);
+ I18n.setLanguage('ja');
export default function AuthProvider({
children,
}: {
children: React.ReactNode;
}) {
return (
<Authenticator>
{children}
</Authenticator>
);
}
カスタム2:日本語の表示文言を変更したい
日本語には出来たけど、文言が気に入らない...
そんなときはI18n
を使用すれば文言も変更できます。
I18n.putVocabularies
を設定することで、任意の文言に上書きすることが出来ます。
import { Authenticator, translations } from '@aws-amplify/ui-react';
import { I18n } from "aws-amplify/utils";
import '@aws-amplify/ui-react/styles.css';
import '../lib/amplify';
I18n.putVocabularies(translations);
I18n.setLanguage('ja');
+ I18n.putVocabularies({
+ ja: {
+ 'Sign In': 'ログイン',
+ 'Sign in': "ログイン",
+ 'Enter your Email': "メールアドレスを入力してください",
+ 'Enter your Password': "パスワードを入力してください",
+ 'Create Account': "新規ユーザー登録",
+ },
+ });
export default function AuthProvider({
children,
}: {
children: React.ReactNode;
}) {
return (
<Authenticator>
{children}
</Authenticator>
);
}
putVocabulariesで変更できるキー(日本語向け)の一覧は以下になります。
ここから変更したい文言のキーを探して、任意に変更します。
カスタム3. 入力フィールドをカスタムしたい
サインイン画面は、入力フィールドにメールアドレスとパスワードがあります。
この入力フィールドをカスタマイズしたいことがあると思います。
そんなときはAuthenticator
のformFields
プロパティで変更できます。
今回は試しにメールアドレスを必須入力に設定してみました。
const formFields = {
signIn: {
username: {
isRequired: true,
},
},
}
あとはreturnに追加してあげると、画面にも反映されます。
// 省略
return (
<Authenticator
+ formFields={formFields}
>
{children}
</Authenticator>
);
// 省略
他に変更できること
詳細はこちら
実装(Authenticator.d.ts、form.d.ts)を見たところ、以下の項目をカスタマイズできるようです。
変更項目 | 説明 |
---|---|
defaultValue | HTMLの defaultValue 属性に対応。入力フィールドの初期値を設定するために使用します。 |
isReadOnly | HTMLの readonly 属性に対応。入力フィールドを読み取り専用にする場合に使用します。 |
pattern | HTMLの pattern 属性に対応。入力値の形式を正規表現で制限するために使用します。 |
minLength | HTMLの minLength 属性に対応。入力値の最小文字数を指定します。 |
maxLength | HTMLの maxLength 属性に対応。入力値の最大文字数を指定します。 |
labelHidden | true に設定すると、入力フィールドの上に表示されるラベルを非表示にします。 |
label | 入力フィールドに表示するラベルのテキストを指定します。 |
placeholder | 入力フィールドに表示するプレースホルダー(入力例など)を指定します。 |
required(非推奨) | 非推奨のプロパティ。内部利用向けで、代わりに isRequired を使用してください。 |
isRequired | このフィールドがフォーム送信時に必須かどうかを指定します。 |
dialCode | 電話番号入力時のデフォルトの国コード(例:+81)を指定します。 |
totpIssuer | TOTP(Time-based One-Time Password)QRコードのセットアップ時に使用される発行者名を指定します。 |
totpUsername | TOTP QRコードのセットアップ時に使用されるユーザー名を指定します。 |
dialCodeList | 電話番号入力フィールドで表示する国コードのリストを指定します。 |
order | このフィールドの表示順序を指定する整数値です。 |
type | HTMLの input タグの type 属性に対応。例:text, email, password など。 |
autocomplete | HTMLの autocomplete 属性に対応。ブラウザによる自動入力の挙動を制御します。 |
autocapitalize | 入力の最初の文字を自動的に大文字にするかどうかを指定します。 |
フィールド名を変更したい場合は、以下の一覧にあるものは変更できるようです。
https://ui.docs.amplify.aws/react/connected-components/authenticator/customization#input-form-field-names-table
カスタム4. 共通なヘッダーとフッターを追加したい
Authenticator
の基本的な画面構成ですが、以下のヘッダー・フッターがあります。
- 認証画面間で共通のヘッダー・フッター (下図の赤枠)
- 機能固有のヘッダー・フッター (下図の黄枠)
まずは認証画面間で共通のヘッダーとフッターを追加します。
ヘッダーとフッター追加した画面
※アイコン画像は生成AIで生成してます。
Authenticator
は、components
プロパティを指定することで、ヘッダーやフッターを自由にカスタマイズすることが出来ます。
以下のようにcomponents
に渡すヘッダー・フッターを定義します。
// 省略
const components = {
// 共通ヘッダー
Header(): any {
const { tokens } = useTheme();
return (
<Card
variation="elevated"
borderRadius="1.5rem 1.5rem 0 0"
display="flex"
style={{
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
}}
>
<Image
src={AppIconSVG}
alt="App Icon"
height="60px"
margin={tokens.space.xs}
/>
<Heading
level={3}
textAlign="center"
>
ようこそ
</Heading>
</Card>
);
},
Footer() {
const { tokens } = useTheme();
return (
<Card
variation="elevated"
borderRadius="0 0 1.5rem 1.5rem"
padding={tokens.space.md}
boxShadow="none"
>
<Text
variation="info"
textAlign="center"
fontSize={tokens.fontSizes.xs}
>
© 2025 Takenoko4594. All rights reserved.
</Text>
</Card>
);
},
}
// 省略
あとはreturnに追加してあげると、画面にも反映されます。
// 省略
return (
<Authenticator
formFields={formFields}
+ components={components}
>
{children}
</Authenticator>
);
// 省略
Amplify UIについて
Amplify UIは、Amplifyが提供するUIライブラリです。
このライブラリを使って構築することで、一貫性のあるUIデザインやUXを実現することが出来ます。
今回の実装では、Card
、Text
、Heading
、Image
といったUIコンポーネントを使っています。
const { tokens } = useTheme();の補足
Amplify UIは、色・フォント・間隔などのスタイル要素をデザイントークン
として定義されています。
useTheme
フックからデザイントークンへアクセスすることができ、統一したスタイルにすることが出来ます。
例えば、以下のようにフォントサイズをトークンから設定できます。
fontSize={tokens.fontSizes.xs}
カスタム5. サインイン画面用のヘッダーとフッターを変更したい
次はサインイン画面専用のヘッダー・フッターを変更してみます。
先ほどのcommponentsの設定を追加します。
// 省略
const components = {
// 共通ヘッダー・フッターは省略
+ SignIn: {
+ // ログイン画面のヘッダー
+ Header(): any {
+ const { tokens } = useTheme();
+ return (
+ <Text
+ textAlign="center"
+ color={tokens.colors.font.tertiary}
+ >
+ アカウントにログインしてください
+ </Text>
+ );
+ },
+ // ログイン画面のフッター
+ Footer() {
+ const { tokens } = useTheme();
+ const { toForgotPassword, toSignUp } = useAuthenticator();
+ return (
+ <>
+ <View
+ textAlign="center"
+ marginTop={tokens.space.xs}
+ >
+ <Link
+ onClick={toForgotPassword}
+ color={tokens.colors.blue[60]}
+ >
+ パスワードをお忘れですか?
+ </Link>
+ </View>
+ <Divider size="small"/>
+ <Flex justifyContent="center">
+ <Text>アカウントをお持ちでない方は</Text>
+ <Link
+ onClick={toSignUp}
+ color={tokens.colors.blue[60]}
+ >
+ 新規ユーザー登録
+ </Link>
+ </Flex>
+ </>
+ );
+ }
+ }
}
// 省略
カスタム6. 自前のUIでサインイン画面をカスタムしたい
例えば、デフォルトのボタンは使いたくない、自由にUIをカスタムしたい!といった場合もあるのではないでしょうか。
そんなときはuseAuthenticator
フックが使えます。
const { toForgotPassword, toSignUp } = useAuthenticator();
このフックは、任意の認証機能(サインイン、サインアップ、パスワード再設定など)への画面遷移を関数として呼び出すことができ、現在の認証状態やユーザー情報(例:メールアドレス)にもアクセスできます。他にもやれることはモリモリです。
今回は、toForgotPassword
とtoSignUp
を使って、パスワード再設定画面とサインアップ画面への遷移関数を呼び出しています。
<Link
onClick={toSignUp}
color={tokens.colors.blue[60]}
>
新規ユーザー登録
</Link>
カスタム7. 切り替えタブを非表示にしたい (無理やり)
デフォルトだと、サインイン画面とサインアップ画面を切り替えるタブが表示されてます。
今回は、カスタム6で実装した自前のボタンを使って切り替えるので、個のタブを非表示にしてみます。
やり方は大きく2つあります。
- 1つ目は、サインアップ機能ごと非表示にする方法です
- 2つ目は、CSSで無理やり非表示にする方法です
1は、Authenticator
のプロパティにhideSignUp
フラグを指定するだけなのですが、今回はサインアップ画面が使えなくなるのは困るので、2つめの方法で非表示にします。
↓ 1つ目の方法は以下を参照
ブラウザの開発者ツールを開き、切り替えタブの
本当はclassで指定したかったのですが上手く適用されなかったので、role
に対して非表示のスタイルを設定しています。
(以下は、tailwindcssの指定なので、素のCSSならdisplay: none
を指定が必要です)
// 省略
const AuthenticatorStyleWrapper = ({ children }: { children: React.ReactNode }) => {
return (
<div
className='
+ [&_[role="tablist"]]:!hidden
[&_div[data-amplify-router-content]]:!py-0
[&_div[data-amplify-container]]:!shadow-2xl
[&_div[data-amplify-container]]:!rounded-2xl
'
>
{children}
</div>
);
}
// 省略
共通のデザインテーマを変更したい場合
先ほどAmplify UIには、デザイントークンというものがあり、useThme()から引き出せるという説明をしました。
このデザイントークンは、Amplify UIの方でデフォルト値が定義されているのですが、ThemeProvider
を使用して任意にカスタマイズできます。
const theme: Theme = {
name: 'custom-theme',
tokens: {
components: {
+ button: {
+ primary: {
+ backgroundColor: { value: '{colors.blue.60}' },
+ _hover: {
+ backgroundColor: { value: '{colors.purple.80}' },
+ },
+ },
+ },
},
},
};
</details>
その他. 背景のデザインを変更する
最後に背景のデザインを変更します。
ただし、Authenticator
コンポーネントはあくまで中央のパネル部分のみを構成するUI部品です。そのため、背景全体のデザインを変更したい場合は、別で設定する必要があります。
ということで今回は、tailwindcss
を使って、背景デザイン用コンポーネントを自作します。
スタイルさえ適用できればやり方は問わないので、あくまで参考程度で。
背景デザイン用コンポーネント ソースコード
// 省略
// 画面の背景デザイン
const AuthenticatorBackground = ({ children }: { children: React.ReactNode }) => {
return (
<div
className="
relative
h-screen
w-screen
flex
items-center
justify-center
overflow-hidden
bg-gradient-to-br
from-[#667eea]
to-[#764ba2]
"
>
<style>{`
@keyframes float {
0%, 100% { transform: translate(0, 0) rotate(0deg); }
33% { transform: translate(100px, -100px) rotate(120deg); }
66% { transform: translate(-50px, 50px) rotate(240deg); }
}
`}</style>
{/* 浮遊する水玉 */}
<div
className="
absolute
-top-24
-left-24
w-[300px]
h-[300px]
rounded-full
bg-white/10
pointer-events-none
"
style={{ animation: 'float 20s ease-in-out infinite' }}
/>
<div
className="
absolute
-bottom-12
-right-12
w-[200px]
h-[200px]
rounded-full
bg-white/10
pointer-events-none
"
style={{ animation: 'float 20s ease-in-out infinite', animationDelay: '5s' }}
/>
<div
className="
absolute
top-1/2
right-[10%]
w-[150px]
h-[150px]
rounded-full
bg-white/10
pointer-events-none
"
style={{ animation: 'float 20s ease-in-out infinite', animationDelay: '10s' }}
/>
{children}
</div>
);
}
// 省略
作成した背景デザイン用コンポーネントをretrunに追加すると、画面に反映されます。
// 省略
return (
<ThemeProvider theme={theme}>
+ <AuthenticatorBackground>
<AuthenticatorStyleWrapper>
<Authenticator
formFields={formFields}
components={components}
>
{children}
</Authenticator>
</AuthenticatorStyleWrapper>
+ </AuthenticatorBackground>
</ThemeProvider>
);
まとめ
今回は、AWS AmplifyのAuthenticatorで表示できるサインイン画面を好き勝手にカスタマイズしてみました。
Goodポイント
設定が充実しているので、フロントエンドに詳しくなくとも、設定値を把握すればある程度の実装はできる印象でした。
Amplifyのコンセプト自体が「フロントエンド開発者でもバックエンドを簡単に扱える」だと思うので、Amazon Cognitoを意識せずに実現できるのは良いですね。
Badポイント
逆にAuthenticator独特の設定がモリモリなので、慣れていない人は苦戦しそうなイメージです。
あと調べても意外と使い込んでる人もあまりいないので、情報が少ないのも難点かもです。
最後に
どうやら他にも、Amazon Cognito「マネージドログイン」など認証画面を実現できる機能があるようなので、今度はそちらも試してみたいと思います。