Amazon Cognito入門:アプリケーションのための認証・認可サービスのヒーロー画像

Amazon Cognito入門:アプリケーションのための認証・認可サービス


Amazon Cognitoは、ウェブアプリケーションやモバイルアプリケーションに簡単に認証、認可、ユーザー管理機能を追加できるAWSのマネージドサービスです。本記事では、Cognitoの基本概念から最新機能までを詳しく解説し、実際の活用例を交えながら、アプリケーションに強固なセキュリティを実装する方法を紹介します。

Amazon Cognitoとは

Amazon Cognitoは、アプリケーションのユーザー認証と認可を管理するためのサービスで、大規模なユーザーベースにも対応できる柔軟性とスケーラビリティを備えています。主に以下の機能を提供します:

  • ユーザー認証: ユーザーのサインアップ、サインイン、アカウント回復など
  • アクセス制御: きめ細かいリソースへのアクセス権限管理
  • ID連携: ソーシャルIDプロバイダーや企業IDシステムとの統合
  • セキュリティ機能: 多要素認証(MFA)、アダプティブ認証など
  • クロスプラットフォーム対応: Web、iOS、Android、Flutterなど様々なプラットフォームをサポート

Cognitoの主な特徴は以下の通りです:

  • スケーラビリティ: 数百万ユーザーまでシームレスに拡張可能
  • セキュリティ: AWS責任共有モデルに基づく堅牢なセキュリティ
  • カスタマイズ性: UI、認証フロー、トークンなどの高度なカスタマイズ
  • コンプライアンス: SOC、PCI、HIPAA、GDPRなど各種規制に対応
  • コスト効率: 使用したリソースに対してのみ課金

Amazon Cognitoの基本コンポーネント

Amazon Cognitoは、主に2つの重要なコンポーネントから構成されています:

1. ユーザープール

ユーザープールは、アプリケーションのユーザーディレクトリで、ユーザー認証とユーザープロファイル情報の管理を担当します。主な機能として以下があります:

  • ユーザーの登録と確認
  • ユーザー認証(サインイン)
  • パスワード管理とリセット
  • 多要素認証(MFA)
  • カスタム属性によるユーザープロファイル管理
  • 外部IDプロバイダー(Google、Facebook、AppleなどのソーシャルIDや、SAML、OIDCプロバイダー)との連携
  • JWTトークン発行(ID、アクセス、リフレッシュトークン)

以下は、AWS CLIを使用してユーザープールを作成する例です:

aws cognito-idp create-user-pool \
  --pool-name MyUserPool \
  --auto-verified-attributes email \
  --schema Name=email,Required=true \
  --policies '{"PasswordPolicy":{"MinimumLength":8,"RequireUppercase":true,"RequireLowercase":true,"RequireNumbers":true,"RequireSymbols":true}}' \
  --mfa-configuration OFF

2. IDプール

IDプール(フェデレーテッドアイデンティティ)は、ユーザーに一時的なAWS認証情報を提供し、他のAWSサービスへのアクセスを可能にします。主な機能として以下があります:

  • 認証済み/未認証ユーザーへのAWS認証情報の提供
  • IAMロールによるきめ細かいアクセス制御
  • 複数のIDプロバイダーの連携(Cognitoユーザープール、ソーシャルIDプロバイダー、SAMLプロバイダーなど)

以下は、AWS CLIを使用してIDプールを作成する例です:

aws cognito-identity create-identity-pool \
  --identity-pool-name MyIdentityPool \
  --allow-unauthenticated-identities \
  --cognito-identity-providers ProviderName=cognito-idp.ap-northeast-1.amazonaws.com/ap-northeast-1_XXXXXXXXX,ClientId=1example23456789,ServerSideTokenCheck=false

Amazon Cognitoの主要機能

1. マネージドログイン

2025年現在、Amazon Cognitoは「マネージドログイン」と呼ばれる新しいホスティングUIを提供しています。これは従来のホスティングUIを改良したもので、以下の特徴があります:

  • レスポンシブデザインによる様々な画面サイズへの対応
  • ビジュアルエディタによるノーコードカスタマイズ
  • API操作によるプログラマティックな設定
  • AWS CloudFormationを使用したインフラストラクチャとしてのコード展開

マネージドログインの設定例:

// マネージドログインの設定
const signUpConfig = {
  header: 'アカウント作成',
  hideAllDefaults: false,
  defaultCountryCode: '1',
  signUpFields: [
    {
      label: 'メールアドレス',
      key: 'email',
      required: true,
      displayOrder: 1,
      type: 'string'
    },
    {
      label: '名前',
      key: 'name',
      required: true,
      displayOrder: 2,
      type: 'string'
    }
  ]
};

2. パスワードレス認証

2025年のCognitoでは、パスワードレス認証が標準で提供されるようになりました。以下の方法がサポートされています:

  • パスキー認証: FIDO標準に基づく公開鍵暗号を使用し、フィッシング耐性のある強力な認証を提供
  • メール認証: メールでのワンタイムパスワード(OTP)による認証
  • SMS認証: SMSでのワンタイムパスワード(OTP)による認証

パスキー認証の例:

// パスキーによるサインイン
async function signInWithPasskey() {
  try {
    const user = await Auth.signIn({
      username: email, // 通常はメールアドレスなどの識別子
      options: {
        authFlowType: 'CUSTOM_WITHOUT_SRP',
        clientMetadata: { passkeySignIn: 'true' }
      }
    });

    // 認証完了後の処理
    console.log('サインイン成功:', user);
  } catch (error) {
    console.error('サインインエラー:', error);
  }
}

3. マルチファクター認証(MFA)

Cognitoは複数のMFA方式をサポートし、セキュリティを強化します:

  • TOTP(Time-based One-Time Password): Google AuthenticatorやMicrosoft Authenticatorなどの認証アプリ
  • SMS: 電話番号へのテキストメッセージ
  • メールOTP: メールアドレスへのワンタイムコード

MFAの設定例:

// TOTP MFAのセットアップ
async function setupTOTP() {
  try {
    // TOTPのセットアップを開始
    const totpCode = await Auth.setupTOTP(user);

    // QRコードのURIを生成(認証アプリで読み取り用)
    const qrCodeUri = `otpauth://totp/AWSCognito:${username}?secret=${totpCode}&issuer=CognitoDemo`;

    // ユーザーがQRコードをスキャンした後、コードを検証
    await Auth.verifyTotpToken(user, verificationCode);

    // MFAの好みを設定
    await Auth.setPreferredMFA(user, 'TOTP');

    console.log('TOTP MFAが正常に設定されました');
  } catch (error) {
    console.error('TOTP MFAのセットアップエラー:', error);
  }
}

4. ロールベースアクセス制御(RBAC)

Cognitoではユーザーグループを使用して、ロールベースのアクセス制御を実装できます:

  • ユーザーを異なるグループに割り当て
  • グループにIAMロールを関連付け
  • グループメンバーシップに基づいたアクセス権の付与

RBACの設定例:

// グループの作成
aws cognito-idp create-group \
  --user-pool-id ap-northeast-1_XXXXXXXXX \
  --group-name Administrators \
  --description "管理者グループ" \
  --precedence 1 \
  --role-arn arn:aws:iam::123456789012:role/CognitoAdminRole

// ユーザーをグループに追加
aws cognito-idp admin-add-user-to-group \
  --user-pool-id ap-northeast-1_XXXXXXXXX \
  --username johndoe \
  --group-name Administrators

5. トークンのカスタマイズ

2025年に追加された機能の一つとして、M2M(マシン間)認可フローでのアクセストークンのカスタマイズが可能になりました:

  • カスタムクレームの追加
  • スコープの制御
  • トークンの有効期限設定

アクセストークンのカスタマイズ例:

// プリトークン生成Lambda関数
exports.handler = (event, context, callback) => {
  // アクセストークンにカスタムクレームを追加
  if (event.triggerSource === 'TokenGeneration_AccessToken') {
    // ユーザーの属性を取得
    const user = event.request.userAttributes;

    // カスタムクレームを追加
    event.response = {
      claimsOverrideDetails: {
        claimsToAddOrOverride: {
          'custom:role': user['custom:role'] || 'basic',
          'organization_id': user['custom:org_id'],
          'permissions': ['read', 'write', 'delete']
        }
      }
    };
  }

  // 処理を続行
  callback(null, event);
};

Amazon Cognitoの他AWSサービスとの統合

Amazon Cognitoは様々なAWSサービスと統合することができ、アプリケーションのエコシステム全体にわたるセキュリティを確保することが可能です。

1. Amazon API Gateway

API Gatewayと統合して、RESTful APIとHTTP APIのアクセス制御を行うことができます:

# API Gateway + Cognito認証の例(OpenAPI 3.0)
openapi: "3.0.1"
info:
  title: "CognitoProtectedAPI"
  version: "1.0.0"
paths:
  /items:
    get:
      security:
        - CognitoAuth: []
      responses:
        '200':
          description: "成功レスポンス"
components:
  securitySchemes:
    CognitoAuth:
      type: "oauth2"
      flows:
        implicit:
          authorizationUrl: "https://mydomain.auth.region.amazoncognito.com/oauth2/authorize"
          scopes:
            "items.read": "itemsの読み取り権限"
      x-amazon-apigateway-authorizer:
        type: "cognito_user_pools"
        providerARNs:
          - "arn:aws:cognito-idp:region:account-id:userpool/user-pool-id"

2. Amazon Verified Permissions

2025年時点で、Amazon CognitoはVerified Permissionsと統合し、Cognitoグループメンバーシップに基づいた詳細な認可ポリシーを実装できるようになりました:

// Verified Permissionsポリシー例(Cedar言語)
permit(
    principal,
    action == Action::"ReadDocument",
    resource
)
when {
    principal.groups has "Readers" ||
    principal.groups has "Administrators"
};

permit(
    principal,
    action in [Action::"UpdateDocument", Action::"DeleteDocument"],
    resource
)
when {
    principal.groups has "Administrators"
};

3. AWS Lambda

Lambdaトリガーを使用して、認証フローの各ステップをカスタマイズできます:

  • サインアップ前/後のトリガー
  • サインイン前/後のトリガー
  • トークン生成前のトリガー
  • カスタム認証チャレンジ
  • ユーザー移行トリガー
// サインアップ前のLambdaトリガー
exports.handler = (event, context, callback) => {
  // 特定のドメインからのメールアドレスのみを許可
  const email = event.request.userAttributes.email;
  if (!email.endsWith('@example.com')) {
    callback(new Error('example.comドメインのメールアドレスのみが許可されています'));
    return;
  }

  // ユーザー属性を追加または変更
  event.request.userAttributes.custom_department = 'sales';

  // 処理を続行
  callback(null, event);
};

4. Amazon CloudFront

CloudFrontと統合して、Webアプリケーションへのアクセスを保護できます:

// Lambda@Edgeで認証状態を確認
exports.handler = async (event) => {
  const request = event.request;
  const headers = request.headers;
  const cookies = headers.cookie || [];

  // Cognitoの認証Cookieを確認
  const authCookie = cookies.find(cookie =>
    cookie.key === 'CognitoIdentityServiceProvider.YOUR_CLIENT_ID.YOUR_USER.idToken'
  );

  if (!authCookie) {
    // 認証されていない場合はログインページにリダイレクト
    return {
      status: '302',
      statusDescription: 'Found',
      headers: {
        location: [{
          key: 'Location',
          value: 'https://auth.example.com/login?redirect=' + encodeURIComponent(request.uri)
        }]
      }
    };
  }

  // 認証されている場合はリクエストを続行
  return request;
};

5. Amazon EventBridge

EventBridgeと統合して、認証イベントに基づいたワークフローを自動化できます:

// EventBridgeルール設定
const rule = {
  Name: 'CognitoSignInMonitoring',
  EventPattern: JSON.stringify({
    source: ['aws.cognito-idp'],
    'detail-type': ['Cognito User Pool SignIn'],
    detail: {
      userPoolId: ['ap-northeast-1_XXXXXXXXX']
    }
  }),
  State: 'ENABLED',
  Targets: [{
    Id: 'ProcessSignInEvents',
    Arn: 'arn:aws:lambda:ap-northeast-1:123456789012:function:ProcessSignInEvents'
  }]
};

Cognitoの実践的な実装例

Webアプリケーションでの実装(React)

React applicationでAmazon Cognitoを使用する例:

// Amplify設定
import { Amplify } from 'aws-amplify';

Amplify.configure({
  Auth: {
    region: 'ap-northeast-1',
    userPoolId: 'ap-northeast-1_XXXXXXXXX',
    userPoolWebClientId: '1example23456789',
    oauth: {
      domain: 'auth.example.com',
      scope: ['email', 'openid', 'profile'],
      redirectSignIn: 'https://example.com/callback',
      redirectSignOut: 'https://example.com/',
      responseType: 'code'
    }
  }
});

// サインアップ
import { Auth } from 'aws-amplify';

async function signUp(username, password, email, phoneNumber) {
  try {
    const { user } = await Auth.signUp({
      username,
      password,
      attributes: {
        email,
        phone_number: phoneNumber
      },
      autoSignIn: {
        enabled: true
      }
    });
    console.log('サインアップ成功:', user);
    return user;
  } catch (error) {
    console.error('サインアップエラー:', error);
    throw error;
  }
}

// サインイン
async function signIn(username, password) {
  try {
    const user = await Auth.signIn(username, password);
    console.log('サインイン成功:', user);
    return user;
  } catch (error) {
    console.error('サインインエラー:', error);
    throw error;
  }
}

// 認証状態の確認
import { useEffect, useState } from 'react';

function AuthStatus() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    checkAuthStatus();
  }, []);

  async function checkAuthStatus() {
    try {
      const currentUser = await Auth.currentAuthenticatedUser();
      setUser(currentUser);
    } catch (error) {
      setUser(null);
    } finally {
      setLoading(false);
    }
  }

  if (loading) return <div>ロード中...</div>;

  return (
    <div>
      {user ? (
        <div>
          <p>ログイン中: {user.attributes.email}</p>
          <button onClick={() => Auth.signOut()}>ログアウト</button>
        </div>
      ) : (
        <p>ログインしていません</p>
      )}
    </div>
  );
}

モバイルアプリケーションでの実装(Flutter)

Flutter applicationでAmazon Cognitoを使用する例:

// pubspec.yaml
dependencies:
  amazon_cognito_identity_dart_2: ^3.0.0

// 実装例
import 'package:amazon_cognito_identity_dart_2/cognito.dart';

class AuthService {
  final userPool = CognitoUserPool(
    'ap-northeast-1_XXXXXXXXX',  // ユーザープールID
    '1example23456789', // クライアントID
  );

  // サインアップ
  Future<bool> signUp(String email, String password) async {
    final userAttributes = [
      AttributeArg(name: 'email', value: email),
    ];

    try {
      final result = await userPool.signUp(
        email,
        password,
        userAttributes: userAttributes,
      );

      return result.userConfirmed;
    } catch (e) {
      print('サインアップエラー: $e');
      return false;
    }
  }

  // 確認コード検証
  Future<bool> confirmSignUp(String email, String confirmationCode) async {
    final cognitoUser = CognitoUser(email, userPool);

    try {
      await cognitoUser.confirmRegistration(confirmationCode);
      return true;
    } catch (e) {
      print('確認エラー: $e');
      return false;
    }
  }

  // サインイン
  Future<CognitoUserSession?> signIn(String email, String password) async {
    final cognitoUser = CognitoUser(email, userPool);
    final authDetails = AuthenticationDetails(
      username: email,
      password: password,
    );

    try {
      final session = await cognitoUser.authenticateUser(authDetails);
      return session;
    } catch (e) {
      print('サインインエラー: $e');
      return null;
    }
  }

  // サインアウト
  Future<void> signOut(String email) async {
    final cognitoUser = CognitoUser(email, userPool);
    await cognitoUser.signOut();
  }
}

セキュリティのベストプラクティス

Amazon Cognitoを使用する際のセキュリティベストプラクティスを紹介します:

1. 強力なパスワードポリシーの設定

ユーザープールの設定で、強力なパスワードポリシーを設定しましょう:

const passwordPolicy = {
  minimumLength: 12, // 12文字以上
  requireUppercase: true, // 大文字を必須
  requireLowercase: true, // 小文字を必須
  requireNumbers: true, // 数字を必須
  requireSymbols: true, // 記号を必須
  temporaryPasswordValidityDays: 3 // 一時パスワードの有効期限
};

2. MFAの強制

セキュリティを強化するために、MFAの使用を強制することを検討しましょう:

// MFAの強制設定
await Auth.setPreferredMFA(user, 'TOTP');

// MFAの強制状態をチェック
const mfaType = await Auth.getMFAOptions(user);
console.log('現在のMFA設定:', mfaType);

3. アドバンストセキュリティ機能の有効化

Cognito Plus tierを使用して、アドバンストセキュリティ機能を有効にしましょう:

  • リスクベースの適応型認証: ユーザーの行動パターンに基づく認証強度の調整
  • 侵害された認証情報の検出: パスワード漏洩データベースとの照合
  • 脅威シグナルの分析: 異常なログインパターンの検出と対策
// アドバンストセキュリティの設定
const advancedSecurityConfig = {
  mfaConfiguration: 'OPTIONAL', // MFA設定(OFF, OPTIONAL, REQUIRED)
  userPoolAddOns: {
    advancedSecurityMode: 'ENFORCED' // セキュリティ機能の強制モード
  }
};

4. IDトークンの検証

クライアントから受け取ったIDトークンは必ず検証してください:

// トークン検証(Node.js)
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const client = jwksClient({
  jwksUri: 'https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json'
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    const signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
}

// トークンの検証
jwt.verify(token, getKey, { algorithms: ['RS256'] }, (err, decoded) => {
  if (err) {
    console.error('トークン検証エラー:', err);
    return;
  }

  // トークンが有効
  console.log('検証済みトークン:', decoded);
});

5. 最小権限の原則を適用

IAMロールを設定する際は、最小権限の原則を適用し、必要最小限のアクセス権のみを付与しましょう:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::example-bucket",
        "arn:aws:s3:::example-bucket/*"
      ],
      "Condition": {
        "StringEquals": {
          "s3:prefix": ["${cognito-identity.amazonaws.com:sub}/"]
        }
      }
    }
  ]
}

トラブルシューティング

Amazon Cognitoを使用する際によくある問題とその解決方法を紹介します:

1. トークン有効期限の問題

// リフレッシュトークンを使用して新しいトークンを取得
async function refreshSession() {
  try {
    const currentUser = await Auth.currentAuthenticatedUser();
    const currentSession = await Auth.currentSession();

    // セッションが期限切れの場合
    if (!currentSession.isValid()) {
      // リフレッシュトークンを使用して新しいトークンを取得
      const refreshedSession = await currentUser.refreshSession(
        currentSession.getRefreshToken(),
        (err, session) => {
          if (err) {
            console.error('セッション更新エラー:', err);
            return;
          }
          console.log('新しいセッション:', session);
        }
      );
    }
  } catch (error) {
    console.error('認証エラー:', error);
  }
}

2. CORS問題の解決

// Cognitoホスティング済みUIのCORS設定
const corsConfiguration = {
  AllowedHeaders: ['*'],
  AllowedMethods: ['GET', 'POST', 'PUT', 'DELETE'],
  AllowedOrigins: ['https://example.com'],
  ExposeHeaders: ['x-amz-server-side-encryption'],
  MaxAge: 3000
};

3. カスタムメッセージの設定

// カスタムメッセージLambdaトリガー
exports.handler = (event, context, callback) => {
  if (event.triggerSource === 'CustomMessage_SignUp') {
    const { codeParameter } = event.request;
    event.response.emailSubject = '【Example App】ご登録の確認';
    event.response.emailMessage = `
      <h1>Example Appへようこそ!</h1>
      <p>ご登録ありがとうございます。以下の確認コードを入力して、アカウントを有効化してください。</p>
      <h2>${codeParameter}</h2>
      <p>このコードは24時間有効です。</p>
    `;
  }

  callback(null, event);
};

料金体系

2025年現在のAmazon Cognitoの料金体系は以下の通りです:

1. ティア別料金

Amazon Cognitoは現在、3つの料金ティアを提供しています:

  • Lite: 基本的な認証機能(パスワードベース認証、ソーシャルIDプロバイダー連携など)
  • Essentials: 包括的な認証・アクセス制御機能(マネージドログイン、パスワードレス認証、トークンカスタマイズなど)
  • Plus: 高度なセキュリティ機能(リスクベースの適応型認証、侵害された認証情報の検出など)

2. 月間アクティブユーザー(MAU)による課金

料金は月間アクティブユーザー(MAU)数に基づいて計算されます:

  • Lite: 階層化されたMAU料金(最初の10,000ユーザーは無料、その後は段階的な価格)
  • Essentials: 固定MAU価格(最初の10,000ユーザーは無料)
  • Plus: 固定MAU価格(セキュリティ機能付き)

3. 追加料金

以下の機能を使用する場合、追加料金が発生することがあります:

  • M2M認証: マシン間認証のためのトークンリクエスト
  • 高API RPS: 高いAPIリクエスト率のクォータ
  • Amazon Cognito同期: デバイス間でのユーザーデータ同期

まとめ

Amazon Cognitoは、アプリケーションに強力な認証・認可機能を簡単に追加するためのサービスであり、2025年の最新機能によって、さらに使いやすく、セキュアになっています。パスワードレス認証やマネージドログインなどの機能により、ユーザーエクスペリエンスを向上させながら、強固なセキュリティを維持することが可能です。

また、AWS Lambdaや他のAWSサービスとの統合により、カスタマイズ性と拡張性に優れており、様々なニーズに対応することができます。小規模なアプリケーションから大規模エンタープライズシステムまで、Amazon Cognitoはスケーラブルな認証・認可ソリューションを提供します。

ぜひAmazon Cognitoを活用して、アプリケーションに強固なセキュリティを実装してください。