Skip to content

feat(identity): cut the internal pool over from GoogleSAML to Google - #175

Merged
Alexanderamiri merged 2 commits into
mainfrom
feat/cognito-google-cutover
Oct 30, 2026
Merged

Alexanderamiri merged 2 commits into
mainfrom
feat/cognito-google-cutover

Conversation

@Alexanderamiri

Copy link
Copy Markdown
Member

Replaces #172 (auto-closed when its base branch was deleted). Rebased onto main: #170, #173 (managed login) and #174 (IdP probe client) are merged and applied.

Why

GoogleSAML has no account chooser. A browser signed in to a personal Google account hits a dead-end 403 app_not_configured_for_user (#157). The Google provider on managed login can show Google's account chooser, but only if prompt=select_account reaches Google. DRAFT: do not merge until the checklist below is done.

Probe result (2026-10-30, platform-idp-probe, client 75ejr2cdi133ictvip1mc32nr3, lists only Google)

Each request got a 302 straight to accounts.google.com/o/oauth2/v2/auth. Results were the same on repeated runs:

/oauth2/authorize extra params prompt in Google URL hd in Google URL
prompt=select_account absent absent
prompt=select_account&identity_provider=Google prompt=select_account absent
identity_provider=Google absent absent
none absent absent
prompt=select_account&identity_provider=Google&hd=java.no prompt=select_account absent

Managed login forwards prompt only when the request names the IdP. On the single-IdP auto-redirect it drops it. hd is never forwarded. Domain enforcement relies on the Internal consent screen and auth-claims, as designed. The generic OIDC IdP fallback is not needed: the Google-type IdP does get prompt, the request just has to include identity_provider. So this PR adds that fix instead of the fallback.

What

  • internal_identity_providers default changes from ["GoogleSAML"] to ["Google"]. One list feeds every internal app client (app-auth-sync) and auth-claims' FEDERATED_IDENTITY_PROVIDERS.
  • ALB sign-in (terraform/modules/service-routing): internal-pool rules now send identity_provider=<client's IdP> next to prompt=select_account. The IdP is read from the client's cognito-client-identity-provider parameter, which app-auth-sync writes, so it is never hardcoded and follows the cutover. Adds a identity_provider_parameter_name output to cognito-app-client.
  • Apps: docs/app-yaml-reference.md "Account chooser" now says to send identity_provider=$COGNITO_IDENTITY_PROVIDER together with COGNITO_EXTRA_AUTH_PARAMS. The generate-modules comment and docs/cognito-google-setup.md step 3 record the probe result.

How verified

  • python3 -m unittest discover -s scripts/tests: OK. python3 -m unittest discover -s terraform/lambda-src/tests: 219 OK.
  • terraform fmt -check -recursive terraform and terraform validate on service-routing.
  • Expected platform plan: the app-auth-sync and auth-claims Lambda environments are updated in place. No Cognito pool, domain or client is replaced (Terraform manages no clients). After apply, the CI reconcile switches every internal client to Google and rewrites cognito-client-identity-provider, which restarts each auth app (app-secret-rollout).
  • The service-routing change reaches app repos on their next deploy. Before the cutover it sends identity_provider=GoogleSAML, which matches today's auto-redirect.

Rollout: pre-cutover checklist

Rollout: after merge

  1. python3 scripts/auth-doctor.py --app-yaml <app>/app.yaml for each auth app. Expect a redirect to accounts.google.com with prompt=select_account. auth-doctor sends identity_provider like a correct app, so also check that the app itself sends it.
  2. Sign in once with a personal Gmail account active in the browser. Google must show the account chooser.
  3. A week later, delete the 4 GoogleSAML_* users, the GoogleSAML provider and the Google Admin SAML app (docs/cognito-google-setup.md, "Decommission").

Rollback: revert to ["GoogleSAML"] (GoogleSAML still exists until decommission).

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown

Terraform Plan

🚧 Changes detected — Plan: 0 to add, 2 to change, 0 to destroy.

Plan output
aws_ssm_parameter.atlassian_api_key: Refreshing state... [id=/javabin/platform/atlassian-api-key]
aws_ssm_parameter.atlassian_org_id: Refreshing state... [id=/javabin/platform/atlassian-org-id]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # module.identity.aws_lambda_function.auth_claims will be updated in-place
  ~ resource "aws_lambda_function" "auth_claims" {
        id                             = "javabin-auth-claims"
        tags                           = {}
        # (23 unchanged attributes hidden)

      ~ environment {
          ~ variables = {
              ~ "FEDERATED_IDENTITY_PROVIDERS" = "GoogleSAML" -> "Google"
                # (2 unchanged elements hidden)
            }
        }

        # (3 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.app_auth_sync will be updated in-place
  ~ resource "aws_lambda_function" "app_auth_sync" {
        id                             = "javabin-app-auth-sync"
        tags                           = {}
        # (23 unchanged attributes hidden)

      ~ environment {
          ~ variables = {
              ~ "INTERNAL_IDENTITY_PROVIDERS" = "GoogleSAML" -> "Google"
                # (5 unchanged elements hidden)
            }
        }

        # (3 unchanged blocks hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

LLM Review

Risk: 🟢 LOW

Plan updates two existing Lambda functions in place (0 to add, 2 to change, 0 to destroy), changing an identity provider environment variable from "GoogleSAML" to "Google" in each.

  • ✅ [routine] module.identity.aws_lambda_function.auth_claims: in-place update of the FEDERATED_IDENTITY_PROVIDERS environment variable from "GoogleSAML" to "Google". No replacement or destruction.
  • ✅ [routine] module.lambdas.aws_lambda_function.app_auth_sync: in-place update of the INTERNAL_IDENTITY_PROVIDERS environment variable from "GoogleSAML" to "Google". No replacement or destruction.
  • 🔒 [security] Both changes alter which identity provider value the functions use for auth/claims handling. Confirm the "Google" value matches the provider actually configured (the SAML provider is being dropped from the value), since a mismatch could cause users to fail login or claims to be mapped incorrectly. No IAM, security group, or public access changes are shown.
  • 💰 [cost] No new billable resources are created. Lambda cost impact is negligible.
  • 💥 [destruction] No resources are destroyed or force-replaced.

Alexanderamiri added a commit that referenced this pull request Oct 30, 2026
… prompt (#176)

## Why
The probe client (#174) showed that Cognito managed login forwards
`prompt=select_account` to Google **only when the request also sends
`identity_provider`**. `auth-doctor.py` always adds `identity_provider`,
so an app that sends only `prompt` passed but would get no account
chooser after the Google cutover (#175).

## What
- New `chooser` check (WARN only): an app that renames auth variables
via `auth.env` but doesn't alias `COGNITO_IDENTITY_PROVIDER` almost
certainly doesn't send it. Apps that read the platform variables
directly aren't flagged, since the doctor can't see their code.
- The authorize warning and the docstring explain the
`identity_provider` requirement.

## How verified
- `python3 -m unittest discover -s scripts/tests`: 133 tests, OK. There
are 4 new tests: aliased without IdP warns, aliased with IdP passes, no
aliases passes, and the probe names the IdP.
- `python3 -m unittest discover -s terraform/lambda-src/tests`: 219
tests, OK.
- Live against the current pool:
  - frosting's `app.yaml` on main gets `WARN chooser`.
- The `app.yaml` from javaBin/frosting#258, which aliases
`COGNITO_IDENTITY_PROVIDER`, passes with no warning.

## Rollout
Script only, with no Terraform changes. App deploys pick it up from
platform `main`.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Alexanderamiri and others added 2 commits October 30, 2026 10:47
internal_identity_providers = ["Google"]: every internal app client and
auth-claims' FEDERATED_IDENTITY_PROVIDERS move to the Google OIDC provider,
which shows Google's account chooser on managed login.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Probe with platform-idp-probe: managed login forwards prompt=select_account
to Google only when the request also has identity_provider=; on the
single-IdP auto-redirect it drops it. ALB sign-in now sends the client's IdP
(from cognito-client-identity-provider) with prompt, and the docs tell apps
to send identity_provider=$COGNITO_IDENTITY_PROVIDER alongside
COGNITO_EXTRA_AUTH_PARAMS. hd= is never forwarded.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Alexanderamiri
Alexanderamiri marked this pull request as ready for review October 30, 2026 09:47
@Alexanderamiri
Alexanderamiri force-pushed the feat/cognito-google-cutover branch from b60f790 to 32487b0 Compare October 30, 2026 09:47
@Alexanderamiri
Alexanderamiri requested a review from a team as a code owner October 30, 2026 09:47
@github-actions

Copy link
Copy Markdown

Terraform Plan

🚧 Changes detected — Plan: 0 to add, 2 to change, 0 to destroy.

Plan output
aws_ssm_parameter.atlassian_org_id: Refreshing state... [id=/javabin/platform/atlassian-org-id]
aws_ssm_parameter.atlassian_api_key: Refreshing state... [id=/javabin/platform/atlassian-api-key]

Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
  ~ update in-place

Terraform will perform the following actions:

  # module.identity.aws_lambda_function.auth_claims will be updated in-place
  ~ resource "aws_lambda_function" "auth_claims" {
        id                             = "javabin-auth-claims"
        tags                           = {}
        # (23 unchanged attributes hidden)

      ~ environment {
          ~ variables = {
              ~ "FEDERATED_IDENTITY_PROVIDERS" = "GoogleSAML" -> "Google"
                # (2 unchanged elements hidden)
            }
        }

        # (3 unchanged blocks hidden)
    }

  # module.lambdas.aws_lambda_function.app_auth_sync will be updated in-place
  ~ resource "aws_lambda_function" "app_auth_sync" {
        id                             = "javabin-app-auth-sync"
        tags                           = {}
        # (23 unchanged attributes hidden)

      ~ environment {
          ~ variables = {
              ~ "INTERNAL_IDENTITY_PROVIDERS" = "GoogleSAML" -> "Google"
                # (5 unchanged elements hidden)
            }
        }

        # (3 unchanged blocks hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

─────────────────────────────────────────────────────────────────────────────

Saved the plan to: tfplan

To perform exactly these actions, run the following command to apply:
    terraform apply "tfplan"

LLM Review

Risk: 🟢 LOW

Plan updates two existing Lambda functions in place (0 to add, 2 to change, 0 to destroy), changing the identity provider environment variable from "GoogleSAML" to "Google" in each.

  • ✅ [routine] module.identity.aws_lambda_function.auth_claims (javabin-auth-claims): in-place update changing environment variable FEDERATED_IDENTITY_PROVIDERS from "GoogleSAML" to "Google". No replacement or destruction.
  • ✅ [routine] module.lambdas.aws_lambda_function.app_auth_sync (javabin-app-auth-sync): in-place update changing environment variable INTERNAL_IDENTITY_PROVIDERS from "GoogleSAML" to "Google". No replacement or destruction.
  • 🔒 [security] The value change affects which identity provider the functions use for authentication/claims logic. Confirm that the "Google" provider is configured and intended, and that the removal of the "GoogleSAML" provider does not lock out or change access for existing users. The plan does not show any IAM, security group, or public access changes.
  • 💰 [cost] No new billable resources are created. No cost impact expected.
  • 💥 [destruction] No resources are destroyed. Changes are configuration-only environment variable updates.

@Alexanderamiri
Alexanderamiri merged commit ff82522 into main Oct 30, 2026
4 checks passed
@Alexanderamiri
Alexanderamiri deleted the feat/cognito-google-cutover branch October 30, 2026 09:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant