Skip to Content

ステップ2:ユーザー認証システムの構築 - Amazon CognitoとJWTトークン実装

今回のステップの概要とモバイルアプリとの関連について

このステップでは、ステップ1で構築したAPI基盤にユーザー認証システムを追加します。具体的には、Amazon Cognito、JWTトークン、ユーザー管理、セキュリティ機能を実装してモバイルアプリのセキュアな認証基盤を構築します。

モバイルアプリにとって、ユーザー認証システムは「会員証や入場パス」のような役割を果たします。Cognitoは受付で本人確認を行い、JWTトークンは会員証のような存在で、アプリ内のさまざまな機能を安全に使えるようにします。これにより、ユーザーの個人情報や位置情報を適切に保護できます。

このステップで学ぶこと

リソースの関わりと構成説明

ステップ2で作成するリソースは、モバイルアプリケーションのセキュリティ基盤を構築するものです。それぞれのリソースがモバイルアプリにどのように関わるのかを説明します。

Amazon Cognito User Poolとモバイルアプリの関わり

Amazon Cognito User Pool「ユーザー認証プール」は、モバイルアプリケーションの「会員管理システム」のような役割を果たします。ユーザーの登録、ログイン、パスワード管理、メール認証などを一元的に管理し、セキュアな認証機能を提供します。これにより、独自の認証システムを構築する必要がなく、セキュリティリスクを大幅に軽減できます。

JWTトークンとモバイルアプリの関わり

JWTトークン「認証トークン」は、モバイルアプリケーションの「デジタル身分証明書」のような役割を果たします。ユーザーがログイン後に発行されるトークンを使って、APIアクセス時に身元を証明します。これにより、毎回ユーザー名とパスワードを送信する必要がなく、安全で効率的な認証が可能になります。

API Gateway Authorizerとモバイルアプリの関わり

API Gateway Authorizer「認証ゲート」は、モバイルアプリケーションの「セキュリティゲート」のような役割を果たします。APIへのリクエストごとにJWTトークンを検証し、有効なユーザーのみがAPIにアクセスできるようにします。これにより、不正なアクセスを防止し、ユーザーデータを保護できます。

実際の手順

実際の手順では、たくさんの設定値を入力することになります。 本文中に設定値が指定されていない場合は、デフォルト値のまま作業を進めてください。

1. Amazon Cognito User Poolの作成

ユーザー登録・ログイン機能を提供するUser Poolを作成します。

Note

AWSでの役割

Amazon Cognitoは、ユーザー認証・認可を提供するマネージドサービスです。

特徴:

  • ユーザー登録・ログイン機能の提供
  • パスワードポリシーとアカウント検証
  • 多要素認証(MFA)のサポート
  • JWTトークンの自動発行・検証

オンプレミスでの対応

オンプレミス環境では「LDAP + OAuth2サーバー」が対応します。

  • Active DirectoryやOpenLDAPでのユーザー管理
  • 独自のOAuth2/OpenID Connectサーバー構築
  • セッション管理とトークン検証の実装

1-1.Cognito User Pool Clientの作成

  1. AWSマネジメントコンソールでCognitoサービスを開きます
  2. 左側メニューで「ユーザープール」を選択します
  3. 「ユーザープールを作成」をクリックします
  4. アプリケーションタイプで「モバイルアプリ」を選択する
  5. アプリケーションに名前を付けるで「mobile-app-client」と入力します
  6. サインイン識別子オプションで「メールアドレス」にチェックを入れます
  7. 自己登録で「自己登録を有効化」にチェックを入れます
  8. サインアップのための必須属性は選択しません
  9. 「ユーザーディレクトリを作成する」をクリックします

1-2.Cognito User Pool Client認証フローの変更

  1. 左側メニューで「ユーザープール」を選択します
  2. 作成されたユーザープールをクリックします
  3. 左側メニューで「アプリケーションクライアント」を選択します
  4. 「mobile-app-client」をクリックします
  5. アプリケーションクライアントに関する情報の「編集」をクリックします
  6. 認証フローで以下を選択します:
    • ALLOW_USER_AUTH
    • ALLOW_USER_PASSWORD_AUTH
    • ALLOW_USER_SRP_AUTH
    • ALLOW_REFRESH_TOKEN_AUTH
  7. 「変更を保存」をクリックします
  8. アプリケーションクライアントに関する情報のクライアントIDをメモしておきます
Tip

【解説】4つのアプリケーションタイプとPublic/Confidentialクライアントの関係

Amazon Cognitoでアプリケーションクライアントを作成する際、実行環境の特性に応じて4つのアプリケーションタイプから選択します。この選択によって、OAuth 2.0の標準仕様に基づいた「パブリッククライアント」または「コンフィデンシャルクライアント」のオプションが事前設定されます。具体的には、選択したアプリケーションタイプに応じてクライアントシークレットの生成有無が決まり、それによってPublic/Confidentialの区別が行われます。この選択は、アプリケーションのセキュリティ設計において非常に重要な意味を持ちます。

4つのアプリケーションタイプ:

  1. 従来のウェブアプリケーション (Traditional web application) - サーバー側でレンダリングされるアプリケーション(例:.NET、Java、Ruby、Node.jsなど)。バックエンドサーバーがトークン交換と保存を処理するため、クライアントシークレットを安全に保管できる → Confidentialクライアント

  2. シングルページアプリケーション (SPA) - ブラウザで実行されるJavaScriptアプリケーション(例:React、Vue、Angular)。ブラウザの開発者ツールでコードを解析できるため、シークレットを安全に保管できない → Publicクライアント

  3. モバイルアプリ (Mobile app) - スマートフォンやタブレットで実行されるネイティブアプリケーション(例:iOS、Android、Flutter)。アプリを逆コンパイルすればコード内のシークレットを抽出できるため、シークレットを安全に保管できない → Publicクライアント

  4. Machine-to-Machine (M2M) - ユーザーの操作を伴わないシステム間通信(例:バックエンドサービス間のAPI連携、バッチ処理)。バックエンドサーバー上で動作し、シークレットを安全に保管できる → Confidentialクライアント

パブリッククライアントは、ブラウザやモバイルデバイス上で実行されるアプリケーション向けに設計されており、クライアントシークレットを持ちません。これは、ブラウザやモバイルアプリのコード内にシークレットを埋め込んでも、ユーザーがそのコードを容易に解析できてしまうためです。例えば、スマートフォンアプリのコードを逆コンパイルすれば、埋め込まれたシークレット情報を取り出すことが可能です。そのため、SPAやモバイルアプリでは、クライアントシークレットに頼らないセキュリティモデルを採用する必要があります。

一方、コンフィデンシャルクライアントは、信頼できるサーバー側リソースを持つアプリケーション向けに設計されています。バックエンドサーバー上で実行されるデーモンやシェルスクリプトなど、ユーザーがコードに直接アクセスできない環境では、クライアントシークレットを安全に保管できます。AWS公式ドキュメントによると、「Amazon Cognitoコンソールは、Traditional web applicationとMachine-to-machine applicationオプションを選択した場合に、クライアントシークレットを持つアプリクライアントを作成します」と明記されています。このシークレットは、すべてのAPI呼び出しでアプリケーションの正当性を証明するために使用される固定文字列です。

実行環境による選択基準:

アプリケーションタイプの選択は、コードの実行環境が「ユーザーからアクセス可能か(Public)」または「サーバー側で保護されているか(Private)」によって決まります。ブラウザやモバイルデバイスなど、ユーザーが直接コードにアクセスできる環境ではPublicクライアント(SPA、モバイルアプリ)を選択し、サーバー側で実行される環境ではConfidentialクライアント(従来のウェブアプリケーション、M2M)を選択します。

今回のモバイルアプリ開発では、「モバイルアプリ」タイプを選択したため、パブリッククライアントとして設定されました。これにより、クライアントシークレットを使用せず、後述するPKCE(Proof Key for Code Exchange)などのより安全な認証フローを利用できます。もしクライアントシークレットを誤ってモバイルアプリに埋め込んでしまうと、悪意のある第三者がそのシークレットを抽出し、あなたのアプリケーションになりすましてCognitoにアクセスする可能性があります。

なお、特殊なケースとして、Amazon CloudFrontプロキシを使用することで、パブリックアプリでもコンフィデンシャルクライアントの機能を安全に利用できる手法も存在します。この場合、CloudFrontが中間プロキシとして動作し、転送中にSECRET_HASHを追加することで、クライアントシークレットをアプリケーションコードに埋め込むことなくセキュリティを強化できます。

参考資料:

Tip

【解説】PKCEの重要性とUSER_PASSWORD_AUTHとの比較

今回のステップでは、開発とテストを簡便にするため「USER_PASSWORD_AUTH」フローを有効化しましたが、本番環境のモバイルアプリでは、Authorization Code flow with PKCEの実装を検討すべきです。USER_PASSWORD_AUTHは、ユーザー名とパスワードを直接APIに送信するフローで、迅速なプロトタイピングには便利ですが、PKCEを使用したフローほどセキュアではありません。

PKCE(Proof Key for Code Exchange)は、OAuth 2.0の認可コードグラントを拡張したセキュリティ機能で、傍受された認可コードの悪用を防ぎます。モバイルアプリやSPAでは、認可コードが傍受された場合でも、攻撃者は元のコード検証子(code verifier)を持っていないためトークンと交換できません。これにより、クライアントシークレットを安全に保管できないパブリッククライアントでも高いセキュリティを実現できます。AWS公式のPrescriptive Guidanceドキュメントでも、エンタープライズアプリケーションではアプリケーションのタイプに応じた適切な認証フローを選択することの重要性が強調されています。

本番環境へのデプロイを計画している場合は、ステップ6:セキュリティ強化でPKCEの実装方法を学習することを強く推奨します。

参考資料:

Tip

【解説】Machine-to-Machine認証によるビジネスプロセスの自動化とモダナイゼーション

Machine-to-Machine(M2M)認証は、人間の介入なしにアプリケーション間で安全に通信を行うための認証方式で、ビジネスプロセスのデジタル化と自動化において重要な役割を果たします。従来、企業間の情報交換は電話やメールなどの手動プロセスに依存していましたが、M2M認証を使用することで、より信頼性が高く安全で、完全に自動化された情報交換が可能になります。

M2M認証の中核となるのが「Client Credentials flow」です。このフローでは、アプリケーションがクライアントIDとクライアントシークレットという認証情報をCognitoに提示し、アクセストークンを取得します。ユーザーのログインや同意ステップが不要なため、バックグラウンドで動作するサービスやバッチ処理、API間の連携などに最適です。例えば、在庫管理システムが夜間に自動的にECサイトのAPIにアクセスして在庫情報を更新する場合や、データ分析システムが定期的に複数のマイクロサービスからデータを収集する場合などに使用されます。

M2M認証を実装する際には、Cognitoのアプリケーションクライアントで「Machine-to-machine application」タイプを選択します。これにより、自動的にクライアントシークレットが生成され、OAuth 2.0のClient Credentialsフローが有効化されます。取得したアクセストークンには、リソースサーバーで定義されたカスタムスコープが含まれ、各APIやマイクロサービスは、このスコープを検証することで、呼び出し元のアプリケーションが特定の操作を実行する権限を持っているかを確認できます。

セキュリティの観点では、M2M認証はクレデンシャルベース認証の一種であり、提示された認証情報(クライアントIDとシークレット)を検証することで、正当なアプリケーションからのリクエストであることを保証します。これは、銀行間のシステム連携のような高いセキュリティが求められるエンタープライズ環境でも採用されています。Amazon CognitoとAPI Gatewayを組み合わせることで、APIエンドポイントを正当なアプリケーションのみがアクセスできるように制限し、不正なアクセスを防止できます。

2024年5月には、AmazonがM2M通信向けのCognito階層型価格設定を発表し、大規模なM2M通信がより経済的に実装できるようになりました。これは、マイクロサービスアーキテクチャやサーバーレスアーキテクチャを採用する企業にとって、コスト効率の良いセキュアな認証基盤を提供します。モバイルアプリのバックエンドでも、複数のマイクロサービス間の通信にM2M認証を活用することで、全体的なセキュリティアーキテクチャを強化できます。

Tip

【解説】ユーザー名とメール認証の組み合わせ

モバイルアプリでは、ユーザビリティとセキュリティのバランスが重要です。ユーザー名での登録により覚えやすいIDを提供し、メール認証により本人確認とアカウント復旧機能を実現できます。

メールアドレスを使用することで、パスワードリセット機能やアカウント確認機能を自動化でき、カスタマーサポートの負荷を軽減できます。また、メール配信機能を使った通知システムとの連携も容易になります。

企業向けアプリの場合は、さらにSAMLやOIDCを使った社内認証システムとの連携も可能です。

Tip

【解説】認証と認可の違い - セキュリティシステムの二段階プロセス

モバイルアプリケーションやWebシステムのセキュリティを理解する上で、「認証(Authentication)」と「認可(Authorization)」の違いを正確に把握することは極めて重要です。この2つの概念は密接に関連していますが、それぞれ異なる役割を担っており、両方が組み合わさって初めて安全なアクセス制御が実現されます。

認証は、「あなたは誰ですか?」という問いに答えるプロセスです。ユーザーやアプリケーションが提示するサインイン認証情報(ユーザー名とパスワード、JWTトークン、APIキーなど)を検証し、その人物やシステムのIDを確認します。これは、オフィスビルに入る際にIDカードを提示して本人確認を受けることに似ています。Amazon Cognitoが行っているのがまさにこの認証プロセスで、ユーザーがログインすると、Cognitoは提示された認証情報を検証し、正当なユーザーであることを確認した上でJWTトークン(IDトークン、アクセストークン、リフレッシュトークン)を発行します。このトークンは、「この人物の身元は確認済みです」という証明書のような役割を果たします。

一方、認可は、「あなたは何ができますか?」という問いに答えるプロセスです。認証が完了した後、そのユーザーやアプリケーションが特定のリソースに対してどのような操作を実行できるかを決定します。これは、オフィスビルに入れた後でも、すべてのフロアや部屋にアクセスできるわけではなく、あなたの役職や権限に応じて入れる場所が制限されることに似ています。AWS IAMやAPI Gateway Authorizerが行っているのがこの認可プロセスです。例えば、今回のステップで設定したAPI Gateway Authorizerは、ユーザーが持つJWTトークンを検証し、そのユーザーが特定のAPIエンドポイント(例:/usersのGETメソッド)にアクセスする権限を持っているかを判断します。

実際のシステムでは、この2つのプロセスは連携して動作します。モバイルアプリユーザーがログインすると、まずCognitoが認証を行ってトークンを発行します(認証)。その後、ユーザーがAPIを呼び出すと、API Gatewayがトークンを検証し、そのユーザーが要求されたリソースにアクセスする権限を持っているかを確認します(認可)。この二段階のセキュリティチェックにより、「正しいユーザーが」「正しい権限の範囲内で」システムを利用できるようになります。企業向けシステムでは、さらに細かい権限制御のためにロールベースアクセス制御(RBAC)や属性ベースアクセス制御(ABAC)などの認可モデルを組み合わせることもあります。

なお、このステップでは認証の動作確認のためにシンプルな/healthエンドポイントを使用しています。ステップ3では、実際のアプリケーションで使用する/checkin/checkinsエンドポイントを作成し、より実践的な機能を実装していきます。

参考資料:How IAM works - AWS Identity and Access Management 

1-3. User Poolの確認と編集

  1. 左側メニューで「ユーザープール」を選択します
  2. 作成されたユーザープールをクリックします
  3. 「名前変更」をクリックします
  4. User Pool名に「mobile-app-user-pool」と入力します
  5. 「変更を保存」をクリックします
  6. ユーザープール情報のユーザープールIDをメモしておきます

1-4. セキュリティ要件の設定

  1. 左側メニューで「認証方法」を選択します
  2. SMSの「編集」をクリックします
  3. 「新しいIAMロールを作成」をクリックします
  4. IAMロール名に「cognito-sms」と入力します
  5. 「変更を保存」をクリックします
  6. 左側メニューで「サインイン」を選択します
  7. 多要素認証(MFA)で「オプションのMFA」を選択します
  8. 「変更を保存」をクリックします

2. API GatewayでのCognito認証統合

ステップ1で作成したAPI GatewayにCognito認証を統合します。

2-1. API GatewayのオーソライザーにCognitoを指定

  1. API Gatewayのコンソールで「mobile-app-api」を開きます
  2. 左側メニューで「オーソライザー」を選択します
  3. 「オーソライザーを作成」をクリックします
  4. 名前に「cognito-authorizer」と入力します
  5. タイプで「Cognito」を選択します
  6. Cognitoユーザープールで作成した「mobile-app-user-pool」を選択します
  7. トークンソースに「Authorization」と入力します
  8. 「オーソライザーを作成」をクリックします

2-2. APIメソッドへの認証適用

  1. 「リソース」メニューで「/health」のGETメソッドを選択します
  2. 「メソッドリクエスト」タブの「編集」をクリックします
  3. 認可で「cognito-authorizer」を選択します
  4. 「保存」をクリックします
  5. API Gatewayのコンソールで「APIをデプロイ」を選択します
  6. デプロイステージで「新しいステージ」を選択し、ステージ名に「dev」と入力します
  7. 「デプロイ」をクリックします
  8. 作成完了後、URLをメモしておきます

3. Lambda関数での認証情報処理

Lambda関数でCognitoから送信される認証情報を処理するように更新します。

3-1. Lambda関数の更新

  1. Lambdaコンソールで「mobile-app-handler」関数を開きます
  2. 以下のPythonコードに更新します:
import json import logging # ログ設定 logger = logging.getLogger() logger.setLevel(logging.INFO) def lambda_handler(event, context): """ 認証されたモバイルアプリからのAPIリクエストを処理する関数 """ try: # リクエスト情報をログに記録 logger.info(f"受信したイベント: {json.dumps(event)}") # 認証情報を取得 request_context = event.get('requestContext', {}) authorizer = request_context.get('authorizer', {}) # Cognitoから送信されるユーザー情報 claims = authorizer.get('claims', {}) user_id = claims.get('sub', 'unknown') email = claims.get('email', 'unknown') username = claims.get('cognito:username', 'unknown') # HTTPメソッドとパスを取得 http_method = event.get('httpMethod', 'GET') path = event.get('path', '/') # パスに応じた処理の分岐 if path == '/health' and http_method == 'GET': # ヘルスチェック用のレスポンス response_data = { 'message': '認証されたユーザーからのリクエストを受信しました', 'user_info': { 'user_id': user_id, 'email': email, 'username': username }, 'request_info': { 'method': http_method, 'path': path }, 'timestamp': context.aws_request_id } logger.info(f"認証ユーザー: {username} ({email})") # 成功レスポンス return { 'statusCode': 200, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token' }, 'body': json.dumps(response_data, ensure_ascii=False) } else: # 未対応のエンドポイント return { 'statusCode': 404, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps({ 'error': 'エンドポイントが見つかりません', 'path': path }, ensure_ascii=False) } except Exception as e: # エラーログを記録 logger.error(f"エラーが発生しました: {str(e)}") # エラーレスポンス return { 'statusCode': 500, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps({ 'error': 'サーバー内部エラーが発生しました', 'message': str(e) }, ensure_ascii=False) }
  1. 「Deploy」ボタンをクリックしてコードをデプロイします

4. 認証機能の動作確認

構築した認証システムが正しく動作することを、curlコマンドとAWS CLIで確認します。

4-1. ユーザー登録のテスト(AWS CLI使用)

AWS CLIを使用して、テストユーザーを作成します:

# User Pool IDを環境変数に設定 export USER_POOL_ID="us-east-1_xxxxxxxxx" export CLIENT_ID="xxxxxxxxxxxxxxxx" # テストユーザーの作成 aws cognito-idp sign-up \ --client-id ${CLIENT_ID} \ --username testuser@example.com \ --password Test1234! \ --user-attributes Name=email,Value=testuser@example.com \ --region us-east-1

期待されるレスポンス:

{ "UserConfirmed": false, "CodeDeliveryDetails": { "Destination": "t***@e***", "DeliveryMedium": "EMAIL", "AttributeName": "email" }, "UserSub": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }

4-2. メール確認コードの取得とユーザー確認

管理者権限でユーザーを確認済みにします(開発環境のみ):

# ユーザーを確認済みに設定 aws cognito-idp admin-confirm-sign-up \ --user-pool-id ${USER_POOL_ID} \ --username testuser@example.com \ --region us-east-1
Tip

【解説】本番環境での確認方法

本番環境では、ユーザーが実際にメールで受信した確認コードを使用して確認を行います:

aws cognito-idp confirm-sign-up \ --client-id ${CLIENT_ID} \ --username testuser@example.com \ --confirmation-code 123456 \ --region us-east-1

開発中はadmin-confirm-sign-upを使用して手動確認を省略できますが、本番環境ではメール確認フローを必ず実装してください。

4-3. ログインしてJWTトークンを取得

# ログイン(認証) aws cognito-idp initiate-auth \ --client-id ${CLIENT_ID} \ --auth-flow USER_PASSWORD_AUTH \ --auth-parameters USERNAME=testuser@example.com,PASSWORD=Test1234! \ --region us-east-1

期待されるレスポンス:

{ "AuthenticationResult": { "AccessToken": "eyJra...(長いトークン文字列)", "ExpiresIn": 3600, "TokenType": "Bearer", "RefreshToken": "eyJjd...(長いトークン文字列)", "IdToken": "eyJra...(長いトークン文字列)" } }

IdTokenの値をコピーしてください(次のステップで使用します)。

4-4. 認証が必要なAPIエンドポイントのテスト

① 認証なしでアクセス(失敗するはず)

# APIのURLを環境変数に設定 export API_URL="https://xxxxxxxxxx.execute-api.us-east-1.amazonaws.com/dev" # 認証なしでリクエスト curl -X GET "${API_URL}/health" \ -H "Content-Type: application/json"

期待されるレスポンス:

{ "message": "Unauthorized" }

ステータスコード:401 Unauthorized

② JWTトークンを使って認証付きアクセス(成功するはず)

# 取得したIDトークンを環境変数に設定 export ID_TOKEN=$(aws cognito-idp initiate-auth \ --client-id ${CLIENT_ID} \ --auth-flow USER_PASSWORD_AUTH \ --auth-parameters USERNAME=testuser@example.com,PASSWORD=Test1234! \ --region us-east-1 \ --output json | jq -r '.AuthenticationResult.IdToken') # 認証付きでリクエスト curl -X GET "${API_URL}/health" \ -H "Content-Type: application/json" \ -H "Authorization: Bearer ${ID_TOKEN}"

期待されるレスポンス:

{ "message": "認証されたユーザーからのリクエストを受信しました", "user_info": { "user_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "email": "testuser@example.com", "username": "testuser@example.com" }, "request_info": { "method": "GET", "path": "/health" }, "timestamp": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" }

ステータスコード:200 OK

4-5. CloudWatch Logsでの認証ログ確認

Lambda Authorizerの実行ログを確認します:

  1. AWSマネジメントコンソールでCloudWatchサービスを開きます
  2. 「ログ」→「ロググループ」を選択します
  3. /aws/lambda/mobile-app-handlerを開きます
  4. 最新のログストリームを確認します

成功時のログ例:

START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [INFO] 受信したイベント: {"xxx...} [INFO] 認証ユーザー: testuser@example.com (testuser@example.com) END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

失敗時のログ例:

START RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx [ERROR] トークン検証失敗: Invalid token [INFO] ポリシー生成: Deny END RequestId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

4-6. トラブルシューティング

エラー: “USER_PASSWORD_AUTH flow not enabled”

原因:App ClientでUSER_PASSWORD_AUTHフローが有効化されていない

対処法:

  1. Cognitoコンソールで対象のApp Clientを選択
  2. 「認証フロー」設定でALLOW_USER_PASSWORD_AUTHを有効化
  3. 変更を保存

エラー: “User is not confirmed”

原因:ユーザーのメール確認が完了していない

対処法:

aws cognito-idp admin-confirm-sign-up \ --user-pool-id ${USER_POOL_ID} \ --username testuser \ --region us-east-1

エラー: “Unauthorized” (トークン付きでも失敗)

原因:API GatewayのAuthorizerが正しく設定されていない、またはトークンが無効

対処法:

  1. API GatewayのAuthorizerテスト機能でトークンを検証
  2. Authorizerの設定(Token Source、User Pool等)を確認
  3. トークンの有効期限(通常1時間)を確認し、期限切れの場合は再ログイン

エラー: “InvalidParameterException: Missing required parameter USERNAME”

原因:リクエストボディのパラメータ名が間違っている

対処法:

  • パラメータ名は大文字小文字を区別します
  • USERNAMEPASSWORDCLIENT_IDなど、正確な名前を使用してください
Tip

【解説】JWTトークンのデバッグ

JWTトークンの内容を確認したい場合は、jwt.io を使用できます:

  1. jwt.ioにアクセス
  2. 「Encoded」欄にIDトークンを貼り付け
  3. 「Decoded」欄でペイロードの内容を確認

ペイロードには以下の情報が含まれます:

  • sub: ユーザーID(Cognito User Sub)
  • email: メールアドレス
  • exp: トークンの有効期限(Unix timestamp)
  • iss: 発行者(Cognito User Pool)

このステップで何をしたのか

このステップでは、モバイルアプリケーション向けの包括的な認証システムを構築しました。具体的には、Amazon CognitoでUser Poolを作成し、ユーザー登録・ログイン機能を実装しました。また、API GatewayにCognito Authorizerを統合し、JWTトークンによる認証機能を追加しました。さらに、Lambda関数でユーザー認証情報を処理できるように更新しました。

モバイルアプリでどのような影響があるのか

この構成により、モバイルアプリは企業レベルのセキュアな認証システムを利用できるようになります。ユーザーはメールアドレスとパスワードで安全にアカウントを作成し、JWTトークンを使って各種APIにアクセスできます。多要素認証やパスワードポリシーにより、セキュリティリスクが大幅に軽減されます。これは、銀行のような高セキュリティが求められる金融機関の「本人確認システム」に相当します。

技術比較まとめ表

技術領域AWSオンプレミス
ユーザー管理Amazon Cognito User Pool
マネージド認証、自動スケーリング
LDAP/Active Directory
サーバー管理、手動スケーリング
トークン管理JWT(Cognito発行)
自動検証、ローテーション機能
独自JWT実装
検証ロジック、鍵管理が必要
認証連携API Gateway Authorizer
ネイティブ統合、設定のみ
OAuth2サーバー
カスタム実装、統合開発

学習において重要な技術的違い

1. 認証システムの管理

  • AWS:Cognitoによる完全マネージド認証システム
  • オンプレミス:独自の認証システム構築・運用が必要

2. セキュリティ機能

  • AWS:MFA、パスワードポリシー、アカウントロックアウト機能が標準装備
  • オンプレミス:すべてのセキュリティ機能を独自実装する必要

3. スケーラビリティ

  • AWS:ユーザー数の増加に自動対応
  • オンプレミス:認証サーバーのキャパシティプランニングが必要

4. 統合の容易さ

  • AWS:API Gatewayとのネイティブ統合
  • オンプレミス:各サービス間の認証連携を個別に実装

実践チェック:画面キャプチャで証明しよう

下記のチェック項目について、実際にAWSマネジメントコンソールで設定ができていることを確認し、各項目ごとに該当画面のスクリーンショットを撮影して提出してください。

  • Cognito User Pool「mobile-app-user-pool」が作成されていること

  • User Pool Clientが正しく設定されていること

  • パスワードポリシーとMFA設定が適用されていること

  • API GatewayでCognito Authorizerが作成されていること

  • /health GETメソッドに認証が適用されていること

  • Lambda関数が認証情報を処理できるように更新されていること

提出方法: 各項目ごとにスクリーンショットを撮影し、まとめて提出してください。 ファイル名やコメントで「どの項目か」が分かるようにしてください。

構成図による理解度チェック

ステップ1の構成図に、このステップで作成した認証システムを追記して、現在のインフラ構成を完成させましょう。

なぜ構成図を更新するのか?

認証システムの追加により、システムのセキュリティ境界と認証フローが大きく変わります。モバイルアプリからAPIアクセスまでの認証の流れを視覚的に理解することで、セキュリティ設計の重要性を把握できます。また、JWTトークンの流れやCognito Authorizerの役割を明確にできます。

  • 認証フロー: ユーザー登録・ログイン → JWTトークン取得 → API認証の流れ
  • セキュリティ境界: 認証が必要な領域と不要な領域の明確化
  • トークン管理: JWTトークンの発行・検証・更新プロセス

構成図の書き方

ステップ1で作成した構成図をベースに、以下のリソースを追記してみましょう。

  1. Amazon Cognito User Pool: API Gatewayの上部に配置し、認証機能を表現
  2. Cognito Authorizer: API Gateway内に認証ゲートとして配置
  3. JWTトークン: モバイルアプリとAPI Gateway間の認証トークンフローを表現
  4. 認証フロー: ユーザー登録・ログインの流れを別途図示

💡 ヒント: 認証が必要なAPIエンドポイントと不要なエンドポイントを色分けして表現すると、セキュリティ設計が分かりやすくなります

理解度チェック:なぜ?を考えてみよう

AWSの各リソースや設計には、必ず”理由”や”目的”があります。 下記の「なぜ?」という問いに自分なりの言葉で答えてみましょう。 仕組みや設計意図を自分で説明できることが、真の理解につながります。 ぜひ、単なる暗記ではなく「なぜそうなっているのか?」を意識して考えてみてください。

Q. なぜモバイルアプリでJWTトークンを使用するのか?セッションベースの認証と比較してどのようなメリットがあるか?

Q. なぜCognitoでメール認証を有効にするのか?メール認証がない場合、どのようなセキュリティリスクが発生するか?

Q. なぜAPI GatewayレベルでCognito認証を統合するのか?Lambda関数内で認証処理を行う場合と比較してどのような違いがあるか?

今回のステップで利用したAWSサービス名一覧

  • Amazon Cognito:ユーザー認証・認可を提供するマネージドサービス
  • Amazon API Gateway:RESTful APIの作成・管理・認証統合を行うサービス
  • AWS Lambda:認証されたユーザー情報を処理するサーバーレスコンピューティング
  • AWS IAM:CognitoとAPI Gateway間のアクセス権限を管理するサービス
  • Amazon CloudWatch:認証ログの監視・分析を行う監視サービス
Last updated on