locals { cognito_prefix_domain = "${local.project}-${var.environment}" google_oidc = jsondecode(data.aws_secretsmanager_secret_version.google_oidc.secret_string) google_oidc_client_id = local.google_oidc.client_id google_oidc_client_secret = sensitive(local.google_oidc.client_secret) app_origin = "https://${aws_cloudfront_distribution.web.domain_name}" portal_callback_urls = [ "${local.app_origin}/api/auth/callback", "http://127.0.0.1:8787/api/auth/callback", ] portal_logout_urls = [ local.app_origin, "http://127.0.0.1:3000/", ] cognito_pool_id = aws_cognito_user_pool.portal.id cognito_issuer = "https://cognito-idp.${var.aws_region}.amazonaws.com/${aws_cognito_user_pool.portal.id}" cognito_client_id = aws_cognito_user_pool_client.portal.id cognito_hosted_domain = "${aws_cognito_user_pool_domain.prefix.domain}.auth.${var.aws_region}.amazoncognito.com" } data "aws_secretsmanager_secret_version" "google_oidc" { secret_id = aws_secretsmanager_secret.google_oidc.id } data "archive_file" "cognito_presignup" { type = "zip" source_file = "${path.module}/lambda/cognito-presignup/index.mjs" output_path = "${path.module}/build/packages/cognito-presignup.zip" } resource "aws_s3_object" "cognito_presignup" { bucket = aws_s3_bucket.artifacts.id key = "functions/cognito-presignup.zip" content_base64 = filebase64(data.archive_file.cognito_presignup.output_path) source_hash = data.archive_file.cognito_presignup.output_base64sha256 } resource "aws_cloudwatch_log_group" "cognito_presignup" { name = "/aws/lambda/${local.project}-cognito-presignup" retention_in_days = 14 } data "aws_iam_policy_document" "lambda_assume" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" identifiers = ["lambda.amazonaws.com"] } } } resource "aws_iam_role" "cognito_presignup" { name = "${local.project}-cognito-presignup" path = "/tf-managed/" assume_role_policy = data.aws_iam_policy_document.lambda_assume.json permissions_boundary = data.aws_iam_policy.ecs_task_boundary.arn } resource "aws_iam_role_policy_attachment" "cognito_presignup_basic" { role = aws_iam_role.cognito_presignup.name policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" } resource "aws_lambda_function" "cognito_presignup" { function_name = "${local.project}-cognito-presignup" role = aws_iam_role.cognito_presignup.arn handler = "index.handler" runtime = "nodejs24.x" architectures = ["arm64"] memory_size = 128 timeout = 5 s3_bucket = aws_s3_bucket.artifacts.id s3_key = aws_s3_object.cognito_presignup.key source_code_hash = data.archive_file.cognito_presignup.output_base64sha256 depends_on = [ aws_cloudwatch_log_group.cognito_presignup, aws_iam_role_policy_attachment.cognito_presignup_basic, ] } resource "aws_cognito_user_pool" "portal" { name = local.project username_attributes = ["email"] auto_verified_attributes = ["email"] mfa_configuration = "OFF" admin_create_user_config { allow_admin_create_user_only = true } password_policy { minimum_length = 32 require_lowercase = true require_numbers = true require_symbols = true require_uppercase = true temporary_password_validity_days = 1 } account_recovery_setting { recovery_mechanism { name = "verified_email" priority = 1 } } lambda_config { pre_sign_up = aws_lambda_function.cognito_presignup.arn } tags = { Project = local.project } } resource "aws_lambda_permission" "cognito_presignup" { statement_id = "AllowCognitoInvoke" action = "lambda:InvokeFunction" function_name = aws_lambda_function.cognito_presignup.function_name principal = "cognito-idp.amazonaws.com" source_arn = aws_cognito_user_pool.portal.arn source_account = local.account_id } resource "aws_cognito_identity_provider" "google" { user_pool_id = aws_cognito_user_pool.portal.id provider_name = "Google" provider_type = "Google" provider_details = { client_id = local.google_oidc_client_id client_secret = local.google_oidc_client_secret authorize_scopes = "openid email profile" attributes_url = "https://people.googleapis.com/v1/people/me?personFields=" attributes_url_add_attributes = "true" authorize_url = "https://accounts.google.com/o/oauth2/v2/auth" oidc_issuer = "https://accounts.google.com" token_url = "https://www.googleapis.com/oauth2/v4/token" token_request_method = "POST" } attribute_mapping = { email = "email" name = "name" username = "sub" } } resource "aws_cognito_user_pool_client" "portal" { name = local.project user_pool_id = aws_cognito_user_pool.portal.id generate_secret = false allowed_oauth_flows_user_pool_client = true allowed_oauth_flows = ["code"] allowed_oauth_scopes = ["openid", "email", "profile"] supported_identity_providers = ["Google"] explicit_auth_flows = ["ALLOW_REFRESH_TOKEN_AUTH"] enable_token_revocation = true prevent_user_existence_errors = "ENABLED" callback_urls = local.portal_callback_urls logout_urls = local.portal_logout_urls access_token_validity = 1 id_token_validity = 1 refresh_token_validity = 8 token_validity_units { access_token = "hours" id_token = "hours" refresh_token = "hours" } depends_on = [aws_cognito_identity_provider.google] } resource "aws_cognito_user_pool_domain" "prefix" { domain = local.cognito_prefix_domain user_pool_id = aws_cognito_user_pool.portal.id }