You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Title: bug: CloudFront-hosted LocalStack app folds multiple Set-Cookie headers into one header, dropping trust-device cookie
Repository: localstack/localstack
Summary
When accessing an auth flow through a LocalStack CloudFront-style hosted app domain, the response from POST /api/auth/two-factor/verify-otp returns better-auth.session_token and better-auth.trust_device in a single comma-joined Set-Cookie header.
As a result, clients persist only better-auth.session_token and drop better-auth.trust_device. The same auth flow works correctly against the direct ELB endpoint, where the two cookies are returned as separate Set-Cookie headers and both persist.
This breaks trusted-device login behavior: after signing in with trustDevice: true and signing out, the next sign-in through the hosted app still requires OTP.
Local image inspect: localstack/localstack-pro@sha256:da1ed4d300a62c41ca5c90b37ed87f5b03d942937cf6238ec942315150e7de3d
Image created: 2026-03-18T21:12:43.93508707Z
Known related issues
#12577 Issue with multiple cookies (array) in v2 Lambda proxy integration payload
#12633 bug: Multiple cookie wrongly set in a single Set-Header when accessing via ELB
Expected behavior
The hosted CloudFront-style path should preserve separate Set-Cookie headers exactly like the direct ELB path. Both better-auth.session_token and better-auth.trust_device should persist.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Title: bug: CloudFront-hosted LocalStack app folds multiple Set-Cookie headers into one header, dropping trust-device cookie
Repository: localstack/localstack
Summary
When accessing an auth flow through a LocalStack CloudFront-style hosted app domain, the response from
POST /api/auth/two-factor/verify-otpreturnsbetter-auth.session_tokenandbetter-auth.trust_devicein a single comma-joinedSet-Cookieheader.As a result, clients persist only
better-auth.session_tokenand dropbetter-auth.trust_device. The same auth flow works correctly against the direct ELB endpoint, where the two cookies are returned as separateSet-Cookieheaders and both persist.This breaks trusted-device login behavior: after signing in with
trustDevice: trueand signing out, the next sign-in through the hosted app still requires OTP.Environment
localstack/localstack-pro:latestlocalstack/localstack-pro@sha256:da1ed4d300a62c41ca5c90b37ed87f5b03d942937cf6238ec942315150e7de3d2026-03-18T21:12:43.93508707ZKnown related issues
#12577Issue with multiple cookies (array) in v2 Lambda proxy integration payload#12633bug: Multiple cookie wrongly set in a single Set-Header when accessing via ELBExpected behavior
The hosted CloudFront-style path should preserve separate
Set-Cookieheaders exactly like the direct ELB path. Bothbetter-auth.session_tokenandbetter-auth.trust_deviceshould persist.Actual behavior
Hosted path returns a single folded header:
curlthen stores onlybetter-auth.session_tokenin the cookie jar for the hosted domain.Control case
The same
verify-otpcall against the direct ELB auth URL returns:curlstores both cookies for the ELB domain, and the next sign-in succeeds without a 2FA redirect.Reproduction
Prerequisites
http://auth-api.elb.localhost.localstack.cloud:4566http://6c2f926b.cloudfront.localhost.localstack.cloud:4566/api/auth/*to the same auth backend.Observed result:
trustDevice: true.Observed hosted response:
Hosted cookie jar after verify:
Note that
better-auth.trust_deviceis missing.Observed direct ELB response:
Direct ELB cookie jar after verify:
Observed direct sign-in result:
This confirms the auth backend itself is behaving correctly and the cookie folding only happens on the hosted CloudFront-style path.
Why this looks like a LocalStack regression or separate code path
#12577and#12633.Beta Was this translation helpful? Give feedback.
All reactions