Design: Fix Deconsolidated Login Page URL Issue
When users visit alpha.atoz.amazon.dev, they end up on atoz.integ.amazon.com after login.
The root cause: the deconsolidated login page uses hardcoded absolute URLs (e.g., https://atoz-login.integ.amazon.com/login?loginType=AA) that break the X-ATOZ-SOURCE header mechanism needed for the domain migration.
LPT (Ruby) → CloudFormation Param → StaticCopyCustomResource → S3 bundle
aa_authentication_controller_url() → AaAuthenticationControllerUrl → replaces {{...}} in built JS → served to browser
In the React code, the placeholders look like:
// LoginForm.tsx — the main AA login form
const aaAuthenticationControllerUrl =
(source === "ac") ? "{{AaAuthenticationControllerUrl}}" : "{{AaEsspUrl}}";
formRef.current!.action = aaAuthenticationControllerUrl;
// DeconsolidatedLoginScreenV2.tsx — the DA tile
href={"{{DaAuthenticationControllerUrl}}"}
// Other tiles
href={"{{PbAuthenticationControllerUrl}}"}
href={"{{SruAuthenticationControllerUrl}}"}
After deploy, these become actual URLs like https://atoz-login.integ.amazon.com/login?loginType=AA.
#Approach
Replace the {{*AuthenticationControllerUrl}} template values with relative paths (/login?loginType=XX) directly in the React components. Since the deconsolidated login page is already served from the Auth Controller's CloudFront distribution (same origin as /login), relative URLs naturally stay on whatever domain the user is currently on.
#Changes Required
AtoZIdentityAppWebsite/src/components/LoginForm.tsx:
// BEFORE:
const aaAuthenticationControllerUrl: string =
(source === ParameterNames.REQUEST_SOURCE_AUTHENTICATION_CONTROLLER) ?
"{{AaAuthenticationControllerUrl}}" : "{{AaEsspUrl}}";
// AFTER:
const aaAuthenticationControllerUrl: string =
(source === ParameterNames.REQUEST_SOURCE_AUTHENTICATION_CONTROLLER) ?
"/login?loginType=AA" : "{{AaEsspUrl}}";
AtoZIdentityAppWebsite/src/components/DeconsolidatedLoginScreenV2.tsx:
// BEFORE:
const newHref = (source === ParameterNames.REQUEST_SOURCE_AUTHENTICATION_CONTROLLER) ?
"{{DaAuthenticationControllerUrl}}" : "{{DaEsspUrl}}";
// AFTER:
const newHref = (source === ParameterNames.REQUEST_SOURCE_AUTHENTICATION_CONTROLLER) ?
"/login?loginType=DA" : "{{DaEsspUrl}}";
// BEFORE:
href={"{{PbAuthenticationControllerUrl}}"}
// AFTER:
href={"/login?loginType=PB"}
// BEFORE:
href={"{{SruAuthenticationControllerUrl}}"}
// AFTER:
href={"/login?loginType=SRU"}
Other components (CSGO region pages, Jobseeker, etc.) — same pattern: replace {{*AuthenticationControllerUrl}} with /login?loginType=XX.
#Pros
- Simplest change — only React code, no LPT/CloudFormation changes needed
- Works for all stages including future domains — relative URLs are domain-agnostic
- No deploy ordering dependency — doesn't need LPT+CFN redeploy
- Eliminates the entire class of bug — no more hardcoded domains to go stale
- Works for personal dev stacks too (e.g.,
wzhongwe.atoz-apps-alpha.integ.amazon.com)
#Cons
- ESSP URLs remain absolute — the
{{AaEsspUrl}}(non-AC) path still uses absolute URLs, but those go to the portal domain which is a different CloudFront distribution, so relative wouldn't work for them - Requires understanding the
sourceparameter logic — thesource === "ac"branch is the only one that should use relative URLs (when the page is served from the AC distribution) - Won't fix the ESSP flow — if a user somehow lands on the deconsolidated page without
?source=ac, the ESSP URLs are still absolute (but this is a different flow and not broken by this bug)
#Risk Assessment
- Low risk — relative URLs on the same origin is standard web behavior
- The
?source=acparameter guarantees the page is served from the AC distribution, so/loginresolves correctly
#Approach
Change all *_authentication_controller_url methods in website_template.rb to emit new-domain URLs for pre-prod stages.
#Changes Required
AtoZIdentityAppLPT/lib/amazon/lpt/website_template.rb:
# BEFORE:
def aa_authentication_controller_url(options)
if options.logical_stage.name.downcase == "beta"
url = "https://atoz-login.integ.amazon.com/login?loginType=AA"
elsif options.logical_stage.name.downcase == "gamma"
url = "https://atoz-login-gamma.corp.amazon.com/login?loginType=AA"
elsif options.logical_stage.name.downcase == "prod-na"
url = "https://atoz-login.amazon.work/login?loginType=AA"
end
url
end
# AFTER:
def aa_authentication_controller_url(options)
if options.logical_stage.name.downcase == "beta"
url = "https://login.beta.atoz.amazon.dev/login?loginType=AA"
elsif options.logical_stage.name.downcase == "gamma"
url = "https://login.gamma.atoz.amazon.dev/login?loginType=AA"
elsif options.logical_stage.name.downcase == "prod-na"
url = "https://atoz-login.amazon.work/login?loginType=AA"
end
url
end
Repeat for ALL helper methods:
da_authentication_controller_urldspa_authentication_controller_urldsp_authentication_controller_urlcsgo_authentication_controller_url_nacsgo_authentication_controller_url_eucsgo_authentication_controller_url_fesru_authentication_controller_urlpb_authentication_controller_urljobseeker_authentication_controller_url
#Pros
- Doesn't modify React app code — keeps the existing template variable approach
- Explicit and auditable — each stage's URL is clearly visible in one file
#Cons
- Only fixes new-domain users — users who arrive via the legacy domain (
atoz-login.integ.amazon.com) would get redirected to the new domain mid-flow, potentially breaking cookies - Requires LPT + CloudFormation deploy — change in LPT triggers a pipeline redeploy of the S3 bundle via CloudFormation
- Hardcodes new domains — same category of problem (domain changes require LPT updates)
- Many methods to update — 9+ helper methods, easy to miss one
- Personal dev stacks break — personal stacks like
wzhongwe.atoz-apps-alpha.integ.amazon.comdon't have a correspondinglogin.wzhongwe.atoz.amazon.devdomain - Doesn't work for beta stage — beta LPT currently serves BOTH alpha and beta traffic (the same S3 bundle is deployed for both), so you can't have one URL that works for both
login.alpha.atoz.amazon.devandlogin.beta.atoz.amazon.devfrom the same bundle
#Risk Assessment
- Medium risk — the beta/alpha shared bundle problem makes this approach non-trivial
- Would need a way to distinguish alpha vs beta at deploy time (currently
betastage in LPT covers both)
#Approach
Replace the template placeholders with dynamic URL construction using the browser's current origin.
#Changes Required
AtoZIdentityAppWebsite/src/components/LoginForm.tsx:
// BEFORE:
const aaAuthenticationControllerUrl: string =
(source === ParameterNames.REQUEST_SOURCE_AUTHENTICATION_CONTROLLER) ?
"{{AaAuthenticationControllerUrl}}" : "{{AaEsspUrl}}";
// AFTER:
const aaAuthenticationControllerUrl: string =
(source === ParameterNames.REQUEST_SOURCE_AUTHENTICATION_CONTROLLER) ?
`${window.location.origin}/login?loginType=AA` : "{{AaEsspUrl}}";
Same pattern for all other *AuthenticationControllerUrl usages.
#Pros
- Domain-agnostic like Option A
- Works for personal dev stacks — picks up whatever origin the page is on
- Explicit about what's happening (constructs full absolute URL)
#Cons
- Functionally identical to Option A but more verbose —
window.location.origin + "/login?loginType=AA"is the same as just/login?loginType=AAfor same-origin navigation - More code to write — template literal instead of simple string
- SSR considerations — if this code ever runs server-side,
window.locationdoesn't exist (not currently an issue since this is a static S3 app) - No real advantage over Option A — since the page is always same-origin with
/login, relative is simpler
#Risk Assessment
- Low risk — same as Option A, just more verbose
Option A is the clear winner:
- Fewest changes, lowest risk
- Eliminates the hardcoded-domain class of bugs entirely
- Works for all current and future domains
- Only modifies the React app (same VS, same pipeline, fast deploy)
- No LPT/CloudFormation deploy required — just a website bundle update
The key insight: when source === "ac", the page is ALWAYS served from the AC distribution. So /login is guaranteed to resolve to the correct Auth Controller endpoint on the same domain the user is already on.
- Identify all
{{*AuthenticationControllerUrl}}usages inAtoZIdentityAppWebsite/src/ - Replace with relative paths only in the
source === "ac"branches - Keep ESSP URLs unchanged — those go to the portal distribution (different origin)
- Update tests — any test mocking these URLs needs updating
- Optionally clean up LPT/CFN — remove unused
*AuthenticationControllerUrlparameters (separate follow-up CR to avoid risk) - Deploy to alpha and verify the full login flow on
alpha.atoz.amazon.dev
#Files to Modify
| File | Change |
|---|---|
AtoZIdentityAppWebsite/src/components/LoginForm.tsx | Replace "{{AaAuthenticationControllerUrl}}" with "/login?loginType=AA" |
AtoZIdentityAppWebsite/src/components/DeconsolidatedLoginScreenV2.tsx | Replace DA, PB, SRU controller URLs with relative paths |
| Any CSGO region components | Replace {{CsgoAuthenticationControllerUrl*}} with /login?loginType=CSGO®ion_hint=XX |
| Any Jobseeker components | Replace {{JobseekerAuthenticationControllerUrl}} with /login?loginType=JOBSEEKER |
AtoZIdentityAppWebsite/src/components/__tests__/* | Update test expectations |
AtoZIdentityAppWebsite/configuration/webpack.config.js | Can remove the AC URL template entries (optional cleanup) |
After deploying to alpha:
- Visit
https://alpha.atoz.amazon.dev - Get redirected to
https://login.alpha.atoz.amazon.dev/login - AC redirects to
https://login.alpha.atoz.amazon.dev/?source=ac - Click "Associate" / enter login / submit
- Verify: form submits to
https://login.alpha.atoz.amazon.dev/login?loginType=AA(relative → same origin) - Complete Federate auth
- Verify: land on
https://alpha.atoz.amazon.dev/(notatoz.integ.amazon.com)
Also verify DA, PB, SRU, CSGO tiles navigate to relative /login?loginType=XX paths.
1 comment
+1 more