private setupCognitoM2M()

in packages/constructs/L3/utility/m2m-api-l3-construct/lib/m2m-api-l3-construct.ts [193:353]


  private setupCognitoM2M(apiScope: ResourceServerScope): UserPool {
    const userPool = new UserPool(this, 'user-pool', {
      enableSmsRole: false,
      userPoolName: this.props.naming.resourceName(),
      selfSignUpEnabled: false,
      accountRecovery: AccountRecovery.NONE,
    });

    MdaaNagSuppressions.addCodeResourceSuppressions(
      userPool,
      [
        {
          id: 'AwsSolutions-COG1',
          reason: 'User Pool used only for app integration, and will not contain users or passwords.',
        },
        { id: 'AwsSolutions-COG2', reason: 'User Pool used only for app integration, and will not contain users.' },
      ],
      true,
    );

    (userPool.node.defaultChild as CfnUserPool).userPoolAddOns = {
      advancedSecurityMode: 'ENFORCED',
    };

    const domainName = userPool.addDomain('DomainName', {
      cognitoDomain: {
        domainPrefix: this.props.naming.resourceName(undefined, 64),
      },
    });

    const resourceServer = userPool.addResourceServer('resource-server', {
      userPoolResourceServerName: this.props.naming.resourceName(undefined, 64),
      identifier: M2MApiL3Construct.identifier,
      scopes: [apiScope],
    });

    const oauthScope = OAuthScope.resourceServer(resourceServer, apiScope);

    Object.entries(this.props.m2mApiProps.appClients || {}).forEach(appClientEntry => {
      const appClientName = appClientEntry[0];
      const appClientProps = appClientEntry[1];

      userPool.addClient(`oauth-client-${appClientName}`, {
        userPoolClientName: this.props.naming.resourceName(appClientName, 64),
        idTokenValidity: appClientProps.idTokenValidityMinutes
          ? Duration.minutes(appClientProps.idTokenValidityMinutes)
          : undefined,
        accessTokenValidity: appClientProps.accessTokenValidityMinutes
          ? Duration.minutes(appClientProps.accessTokenValidityMinutes)
          : undefined,
        refreshTokenValidity: appClientProps.refreshTokenValidityHours
          ? Duration.hours(appClientProps.refreshTokenValidityHours)
          : undefined,
        authFlows: {
          userPassword: false,
          userSrp: false,
          custom: true,
        },
        oAuth: {
          flows: {
            authorizationCodeGrant: false,
            implicitCodeGrant: false,
            clientCredentials: true,
          },
          scopes: [oauthScope],
        },
        preventUserExistenceErrors: true,
        generateSecret: true,
        enableTokenRevocation: true,
      });
    });

    const cognitoAuthLogFunctionRole = new MdaaLambdaRole(this, 'cognito-auth-lambda-role', {
      description: 'Lambda Role for Cognito Auth Logger function',
      roleName: 'cognito-auth',
      naming: this.props.naming,
      logGroupNames: [this.props.naming.resourceName('log-auth-event')],
      createParams: false,
      createOutputs: false,
    });

    const postAuthLogFn = new MdaaLambdaFunction(this, 'postAuthLogFn', {
      runtime: Runtime.NODEJS_22_X,
      handler: 'index.handler',
      functionName: 'log-auth-event',
      role: cognitoAuthLogFunctionRole,
      naming: this.props.naming,
      code: Code.fromInline(`
                const handler = async function(event) {
                    console.log("Authentication successful");
                    console.log("Trigger function =", event.triggerSource);
                    console.log("User pool = ", event.userPoolId);
                    console.log("App client ID = ", event.callerContext.clientId);
                    console.log("User ID = ", event.userName);
                    return event;
                };
                exports.handler = handler;
                `),
    });

    MdaaNagSuppressions.addCodeResourceSuppressions(
      postAuthLogFn,
      [
        { id: 'NIST.800.53.R5-LambdaDLQ', reason: 'Function only logs to stdout. DLQ is not required.' },
        {
          id: 'NIST.800.53.R5-LambdaInsideVPC',
          reason:
            'Function is logging Cognito events directly to CloudWatch via stdout and is not VPC bound by design.',
        },
        {
          id: 'NIST.800.53.R5-LambdaConcurrency',
          reason: 'Function is logging successful authentication requests. Concurrency is unbounded by design.',
        },
        { id: 'HIPAA.Security-LambdaDLQ', reason: 'Function only logs to stdout. DLQ is not required.' },
        { id: 'PCI.DSS.321-LambdaDLQ', reason: 'Function only logs to stdout. DLQ is not required.' },
        {
          id: 'HIPAA.Security-LambdaInsideVPC',
          reason:
            'Function is logging Cognito events directly to CloudWatch via stdout and is not VPC bound by design.',
        },
        {
          id: 'PCI.DSS.321-LambdaInsideVPC',
          reason:
            'Function is logging Cognito events directly to CloudWatch via stdout and is not VPC bound by design.',
        },
        {
          id: 'HIPAA.Security-LambdaConcurrency',
          reason: 'Function is logging successful authentication requests. Concurrency is unbounded by design.',
        },
        {
          id: 'PCI.DSS.321-LambdaConcurrency',
          reason: 'Function is logging successful authentication requests. Concurrency is unbounded by design.',
        },
      ],
      true,
    );

    userPool.addTrigger(UserPoolOperation.POST_AUTHENTICATION, postAuthLogFn);

    new MdaaParamAndOutput(this, {
      ...{
        resourceType: 'cognito-userpool-id',
        resourceId: 'm2m-cognito-userpool-id',
        name: 'm2m-userpool-id',
        value: userPool.userPoolProviderName,
      },
      naming: this.props.naming,
    });

    new MdaaParamAndOutput(this, {
      ...{
        resourceType: 'cognito-userpool-domain-name',
        resourceId: 'cognito-userpool-domain-name-id',
        name: 'm2m-userpool-domain-id',
        value: `https://${domainName.domainName}.auth.${this.region}.amazoncognito.com`,
      },
      naming: this.props.naming,
    });

    return userPool;
  }