こんにちは。
アプリケーションサービス部、DevOps担当の兼安です。
今回はReactを用いたSPA(Single Page Application)に、Amazon Cognitoで認証を組み込む方法を説明します。
本記事のターゲット
本記事は、SPAの開発を行うエンジニアを対象としています。
SPAのフロントエンドはReactで実装、バックエンドはAPI GatewayとAWS Lambdaを使用することを想定しているので、これらの技術に関する知識があることが望ましいです。
今回の構成
本記事では、以下の構成を想定しています。

- フロントエンドはReactで、Vercelにデプロイ
- バックエンドはAWS Lambdaで、Amazon API Gatewayを介してフロントエンドと通信
- 認証はAmazon Cognitoを使用
Vercelを用いるのは、AWSリソース以外のサービスからでも、Amazon Cognitoを利用できることを示すためです。
フロントエンドとバックエンドは、同じアプリケーションクライアントを使用し、認証情報を共有します。
Amazon Cognitoのアプリケーションクライアント
Amazon Cognito(以降、Cognitoと略します)のアプリケーションクライアントは、ユーザープール内の設定です。
Cognitoのユーザープールが、認証と認可のためのユーザーディレクトリ(=ユーザー情報を保存する場所)として機能します。
そして、各アプリケーションは、アプリケーションクライアントを介してユーザープールにアクセスします。
同じアプリケーションクライアントを使用することで、フロントエンドとバックエンドは同じユーザープールを参照し、認証情報を共有することができます。
ReactアプリにAWS Amplify UIを使用して認証を組みこむ
まずは、フロントエンドのReactアプリに、AWS Amplify UIを使用して認証を組み込みます。
AWS Amplifyは、多数の機能を持つ開発プラットフォームです。
今回はこの中の一つ、Amplify UIを中心にしてReactアプリに認証を組み込みます。
最初からAmplify前提で作る方法もありますが、個人的に既存のReactアプリに後から組み込む方が必要な要素の把握には役立つと思いますので、後から組み込む方法を説明します。
手順自体はAWS公式のドキュメントに詳しく書かれていますので、こちらをベースにポイントを説明します。
サンプルコードを用いて説明していきます。
言語はTypeScriptを使用します。
設定ファイルの準備
まずは、Cognito用の設定ファイルを作成します。
ファイル名はsrc/config/aws-exports.tsとします。
// AWS Cognito configuration const awsExports = { aws_project_region: process.env.REACT_APP_AWS_REGION || process.env.NEXT_PUBLIC_AWS_REGION || 'ap-northeast-1', aws_cognito_region: process.env.REACT_APP_AWS_REGION || process.env.NEXT_PUBLIC_AWS_REGION || 'ap-northeast-1', aws_user_pools_id: process.env.REACT_APP_COGNITO_USER_POOL_ID || process.env.NEXT_PUBLIC_COGNITO_USER_POOL_ID || 'COGNITO_USER_POOL_ID', aws_user_pools_web_client_id: process.env.REACT_APP_COGNITO_CLIENT_ID || process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID || 'COGNITO_USER_POOL_WEB_CLIENT_ID', }; export default awsExports;
各種設定値は、環境変数から取得するようにしています。
環境変数名は、Vercelの命名規則に従っています。
Vercelの環境変数でこれらを設定することで、デプロイ時に自動的に値が埋め込まれます。
ユーザープールIDやクライアントIDは、AWSマネジメントコンソールから取得できます。
Cognitoのユーザープールやアプリケーションクライアントの設定については、こちらの記事を参考にしてください。
ユーザープールの作成画面で、リターンURLの入力欄があります。
ここは一般的にフロントエンド側で用意しているログインページまたはトップページのURLを指定します。
不正なURLを入れると、認証に失敗します。
一旦デプロイしてURLを発行しておき、そのURLを入力しておくとよいと思います。

ユーザープール、アプリケーションクライアントを作成すると、それぞれIDが発行されます。


この設定ファイルは以下のように使用します。
// Amplify設定をインポート import { Amplify } from 'aws-amplify'; import awsExports from './config/aws-exports'; // Amplifyクライアントを設定 Amplify.configure({ ...awsExports });
Amplify UIのAuthenticatorコンポーネント
Amplify UIのAuthenticatorは<Authenticator>タグで挟んだ部分をログイン済みならその中身を、ログインしていなければログイン画面を表示します。
例えば、src/pages/Login.tsxに以下のように記述すれば、未ログインならログイン画面が表示され、ログイン後は認証が必要なページに転送させることができます。
import React from 'react'; import { useNavigate } from 'react-router-dom'; import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react'; import '@aws-amplify/ui-react/styles.css'; const AuthenticatedContent = () => { const { user, signOut } = useAuthenticator(context => [context.user]); const navigate = useNavigate(); React.useEffect(() => { const timer = setTimeout(() => { navigate('/member'); }, 2000); return () => clearTimeout(timer); }, [navigate]); return ( <div> <h2>ログイン成功!</h2> <p>ユーザー: {user?.username}</p> <p>リダイレクトします...</p> <button onClick={signOut} style={{ padding: '8px 16px', background: '#f44336', color: 'white', border: 'none', borderRadius: '4px', cursor: 'pointer', marginTop: '10px', }} > ログアウト </button> </div> ); }; const Login: React.FC = () => { return ( <div style={{ maxWidth: '600px', margin: '0 auto', padding: '20px', boxShadow: '0 4px 6px rgba(0,0,0,0.1)', borderRadius: '8px', marginTop: '50px', }} > <h1>ログイン / 新規登録</h1> <Authenticator initialState="signIn" services={{ handleSignUp: async formData => { return { isSignUpComplete: false, nextStep: { signUpStep: 'CONFIRM_SIGN_UP', codeDeliveryDetails: { deliveryMedium: 'EMAIL', destination: formData.username, attributeName: 'email', }, }, }; }, }} > {() => <AuthenticatedContent />} </Authenticator> </div> ); }; export default Login;
URLパスで認証の要否を制御する
<Authenticator>タグと、Reactのルーティングライブラリを組み合わせることで、URLパスに応じて認証の要否を制御できます。
例えば、React Routerを使用している場合、以下のようにルーティングを設定できます。
return ( <div className="app"> <main> <Routes> <Route path="/about" element={<About />} /> <Route path="/member/*" element={ <Authenticator> <Member isLoggedIn={isLoggedIn} /> </Authenticator> } /> </Routes> </main> </div> );
これで/member以下のURLにアクセスしたときは認証が必要になり、/aboutでは認証なしでアクセスできるようになります。
認証済みかどうかの判定
認証済みかどうかは、fetchAuthSession関数を使用して判定できます。
この関数は、AmplifyのAuthモジュールからインポートでき、認証済みの場合はトークン文字が返却されます。
import { fetchAuthSession } from 'aws-amplify/auth'; const checkAuthState = async () => { try { const { tokens } = await fetchAuthSession(); setIsLoggedIn(tokens !== undefined); } catch (error) { console.log('Not signed in'); setIsLoggedIn(false); } };
HTTPリクエストに認証情報を付与する
fetchAuthSessionで取得した認証情報をHTTPリクエストに付与すれば、認証済みのユーザーとしてAPIにアクセスできます。
BearerトークンをAuthorizationヘッダーに追加することで、認証情報を付与できます。
try { // Amplify v6 method usage const { tokens } = await fetchAuthSession(); const token = tokens?.idToken?.toString(); if (!token) { throw new Error('No token available'); } console.info('Token obtained from Amplify:', token ? 'Valid token' : 'No token'); const response = await fetch(apiConfig.endpoints.member, { headers: { Authorization: `Bearer ${token}`, 'Content-Type': 'application/json', }, }); console.info(response); if (!response.ok) { throw new Error(`API request failed with status ${response.status}`); } console.info('HTTP API endpoint succeeded'); } catch (error) { console.error('HTTP API endpoint failed:', error); }
Amazon API GatewayにCognito認証を組み込む
今度は、バックエンドのAmazon API Gateway(以降、API Gatewayと略します)にCognito認証を組み込みます。
API Gatewayは、Cognitoをオーソライザーとして使用することで、認証を行うことができます。
オーソライザーを使用しなければそのAPIは認証が不要となります。
API Gatewayは、AWSマネジメントコンソールから設定できます。
ナビゲーションペインのAuthenticationをクリック。
オースライザーを作成してアタッチをクリック。

オーソライザーの作成画面が表示されるので、以下のように設定します。
- オーソライザーのタイプ:JWT
- 発行者URL:ユーザープールのトークン署名キーURLから、末尾の/.well-known/jwks.jsonを削除したものを入力
- 対象者:(対象者を追加をクリックしてから)アプリケーションクライアントのクライアントIDを入力



ポイントは、発行者URLはユーザープールのトークン署名キーURLから、末尾の/.well-known/jwks.jsonを削除したものを入力すること。
対象者は一度追加をクリックしてから、アプリケーションクライアントのクライアントIDを入力することです。
また、クライアントIDはReactアプリのsrc/config/aws-exports.tsで設定したものと同じものを指定します。
オーソライザーを作成すると、JWT認証が付与されます。
後はデプロイして完成です。

最後に
本記事は以上です。
認証が必要なAPI Gatewayのエンドポイントにアクセスすると、Cognitoで認証されたユーザーのみがアクセスできるようになります。
シンプルな内容ではありますが、皆様の参考になれば幸いです。
兼安 聡(執筆記事の一覧)
アプリケーションサービス部 DS3課所属
2025 Japan AWS Top Engineers (AI/ML Data Engineer)
2025 Japan AWS All Certifications Engineers
2025 AWS Community Builders
Certified ScrumMaster
PMP
広島在住です。今日も明日も修行中です。
X(旧Twitter)