AWS Builder Center
Fixing Kiro IDE SSO Authentication Timeouts on Linux: A DNS64 and IPv6 Deep Dive

Fixing Kiro IDE SSO Authentication Timeouts on Linux: A DNS64 and IPv6 Deep Dive

Why Kiro IDE authentication works at the office but times out at home on Linux. The culprit: DNS64 synthesizing fake IPv6 addresses + Node.js Happy Eyeballs killing IPv4 connections too early. Here's how I found it and fixed it.

Series: KIRO (2 articles)

  1. 1
    Fixing Kiro IDE SSO Authentication Timeouts on Linux: A DNS64 and IPv6 Deep Dive This article

How It Started

So I installed Kiro IDE on my Linux laptop. Clicked "Sign In." Browser opened, I authenticated, browser redirected back... and nothing happened. The IDE just sat there saying "Authentication FAILED."
I tried again. And again. Same thing.
Next morning, I took my laptop to the office. Opened Kiro IDE, clicked Sign In, and it worked instantly. First try.
Came back home. Broken again. And while working from home, I kept getting random timeouts during AI-assisted coding sessions.
I knew something weird was going on.

Is This Just Me?

No. This is a known problem affecting many developers. Here's the evidence:
This affects any developer who:
  1. Uses a tool built on Node.js v20+ or Electron (VS Code, Kiro IDE, Cursor, GitHub Desktop, Postman, etc.)
  2. Has a network that returns unreachable IPv6 addresses (DNS64 without NAT64, broken IPv6, ISP advertising IPv6 without full connectivity)
  3. Connects to servers that are geographically distant (high latency means the 250ms timeout is too short)
Common scenarios where this hits:
  • Home routers with DNS64 enabled (many modern routers do this "helpfully")
  • Mobile hotspots/tethering (cellular networks often have IPv6 transition technologies)
  • Corporate VPNs that misconfigure IPv6
  • ISPs in Africa, Asia, South America where latency to US/EU servers exceeds 250ms
  • Satellite internet (Starlink, etc.) where latency is inherently high

Why It Works on Windows But Breaks on Linux

This was my biggest question. Same laptop dual-booting, same WiFi, same router. Windows works, Linux doesn't. Here's why:

Windows Handles DNS64 Differently

  1. Windows DNS client filters differently: When Windows detects it has no IPv6 route, its DNS client is smarter about filtering out IPv6 records it knows are unreachable. It checks if it has a working IPv6 interface before requesting AAAA records.
  2. Windows prefix policy: Windows has a built-in prefix policy table that by default often prefers IPv4 in practice, especially when no real IPv6 connectivity is detected.
  3. Windows DNS Client Service caching: The Windows DNS Client does more aggressive negative caching. If IPv6 connections fail, Windows remembers and stops trying.
  4. Electron on Windows uses different network stack paths: On Windows, Electron/Chromium can use the Windows HTTP stack (WinHTTP) for certain operations. Its Happy Eyeballs implementation is more mature and handles the "instant IPv6 failure" pattern correctly.

Linux Trusts DNS Blindly

On Linux:
  • systemd-resolved faithfully returns whatever the upstream DNS gives it, including DNS64 synthesized addresses
  • There's no automatic detection of "we don't actually have IPv6 connectivity, let's not use those AAAA records"
  • Node.js's getaddrinfo() on Linux returns all addresses and lets the Happy Eyeballs algorithm sort it out
  • The Happy Eyeballs implementation in Node.js v20+ has a known bug where the 250ms timeout per attempt is too aggressive, and it cancels working IPv4 connections prematurely

macOS Behavior

macOS actually handles this the best. Apple invented the DNS64/NAT64 approach for iOS and has deep OS-level integration that correctly handles synthesized IPv6 addresses. The system won't use DNS64 addresses unless NAT64 is actually functioning.

The Clue That Changed Everything

Here's what was interesting: the Kiro CLI (terminal version) worked perfectly at home. Same machine, same network, same account. But the terminal tool could authenticate while the desktop IDE could not.
This told me the problem wasn't my account, wasn't my credentials, wasn't a firewall. It was something specific to how the IDE's underlying technology (Electron/Node.js v22) handles network connections.

Understanding the Authentication Flow

When you click "Sign In" in Kiro IDE, here's what happens:
1
2
3
4
5
6
7
Kiro IDE starts local server on port 3128
→ Browser opens app.kiro.dev/signin
→ You log in via AWS SSO Identity Center
→ Browser redirects back to localhost:3128 with auth code
→ IDE receives code, now needs to exchange it for a token
→ IDE calls oidc.us-east-1.amazonaws.com
→ THIS IS WHERE IT BREAKS
After the browser redirects back, the IDE needs to make an HTTPS request to oidc.us-east-1.amazonaws.com to exchange the authorization code for a real access token.
That call was timing out.

Investigating the Logs

I dug into Kiro IDE's logs at ~/.config/Kiro/logs/ and found the smoking gun:
1
2
3
4
5
6
PortalAuthServer: Listening on http://localhost:3128 Good
PortalAuthProvider: Opening portal at https://app.kiro.dev... Good
PortalAuthServer: Received callback for login_option=awsidc Good!
IdCAuth: Starting authentication (provider: Enterprise) Good
SSOOIDC client: registerClient TimeoutError [ETIMEDOUT] FAILED!
Authentication failed: SSOOIDC client: Unexpected issue FAILED!
Browser auth worked perfectly! The IDE received the callback. But when it tried to contact AWS to register as an OAuth client... timeout.

Testing the Network Connection

From the terminal:
1
2
3
4
$ curl -X POST https://oidc.us-east-1.amazonaws.com/client/register \
-H "Content-Type: application/json" \
-d '{"clientName":"test","clientType":"public"}'
# Response: 200 OK, works instantly!
From Node.js (the same runtime Kiro IDE uses):
1
2
3
4
5
6
7
8
9
10
const https = require('https');
const req = https.request({
hostname: 'oidc.us-east-1.amazonaws.com',
port: 443,
path: '/client/register',
method: 'POST'
}, (res) => {
console.log('Status:', res.statusCode); // Never reaches here!
});
// Result: ERROR: ETIMEDOUT after 2124ms
Same computer. Same network. Same destination. curl works, Node.js doesn't.
Why?

The DNS Detective Work

I looked at what DNS was returning:
1
2
3
4
5
6
7
8
9
10
11
$ resolvectl query oidc.us-east-1.amazonaws.com

oidc.us-east-1.amazonaws.com:
64:ff9b::6438:8ee7 <- IPv6 address (NAT64 synthesized)
64:ff9b::643c:7cb5 <- IPv6 address (NAT64 synthesized)
64:ff9b::20c6:bd81 <- IPv6 address (NAT64 synthesized)
...8 more IPv6...
52.45.155.180 <- IPv4 address (real)
100.56.142.231 <- IPv4 address (real)
54.87.95.156 <- IPv4 address (real)
...5 more IPv4...
Wait. Why is my DNS returning IPv6 addresses for AWS? AWS services in us-east-1 are IPv4-only!
Those 64:ff9b:: addresses are a dead giveaway. That's the NAT64 well-known prefix. My router was synthesizing fake IPv6 addresses from real IPv4 addresses using a technology called DNS64.

What Is DNS64/NAT64?

So my home router was trying to be helpful. It knows the internet is moving from IPv4 (old addresses like 54.87.95.156) to IPv6 (new addresses like 2600:1f18:243:cf02::1).
The router thought: "I'll help! When someone asks for an address that's only available in IPv4, I'll create a fake IPv6 address that maps to the real IPv4 one."
It takes the IPv4 address and wraps it in an IPv6 envelope:
1
2
3
4
Real IPv4: 54.87.95.156
Router creates fake IPv6: 64:ff9b::3657:5f9c
^^^^^^^^
This prefix means "NAT64 translated"
The idea is that traffic would go to the router via IPv6, and the router would translate it back to IPv4 before sending it to the real internet. This is called NAT64.
But the problem: My router was creating these fake addresses but had no actual IPv6 routing set up. It was handing out IPv6 addresses that led absolutely nowhere. Like giving someone a street address in a city that doesn't exist.
1
2
3
4
5
$ ip -6 route show default
# (nothing, no IPv6 route exists!)

$ openssl s_client -connect '[64:ff9b::6438:8ee7]:443'
# connect: Network is unreachable (errno=101)

What Is "Happy Eyeballs"?

Now here's where Node.js v22 enters the picture.
When your computer wants to connect to a website, DNS might return both IPv4 and IPv6 addresses. In the past, the computer would try one type first, and only if it failed, try the other. This was slow if the first type was broken because you'd wait for a full timeout.
In 2012, engineers invented an algorithm called "Happy Eyeballs" (RFC 6555, updated in RFC 8305). The idea:
  1. Start connecting via IPv6
  2. After 250ms, also start connecting via IPv4
  3. Whichever connects first wins!
Node.js v20+ enabled Happy Eyeballs by default (called autoSelectFamily in Node.js). But the implementation has a known bug (Node.js Issue #54359 ):
Instead of racing connections properly, Node.js:
  1. Tries the first address with a 250ms timeout
  2. If it times out, cancels it and tries the next one
  3. Interleaves IPv4 and IPv6 attempts
In my situation with 16 DNS results (8 IPv4 + 8 IPv6), it went like this:
1
2
3
4
5
6
Attempt 1: Try IPv4 52.45.155.180 -> 250ms timeout (my latency is ~500ms!)
Attempt 2: Try IPv6 64:ff9b::6438:... -> ENETUNREACH (instant fail)
Attempt 3: Try IPv4 100.56.142.231 -> 250ms timeout (too short!)
Attempt 4: Try IPv6 64:ff9b::643c:... -> ENETUNREACH (instant fail)
...repeat...
FINAL RESULT: AggregateError ETIMEDOUT, ALL attempts failed!
The IPv4 connections needed ~500ms to complete (normal for connecting to US-East-1 from East Africa), but they were being killed at 250ms. The IPv6 connections failed instantly because the addresses don't route. Everything failed.

Why Curl Worked

curl uses a different, more mature Happy Eyeballs implementation. When IPv6 fails immediately with ENETUNREACH, curl quickly marks those addresses as dead and focuses on IPv4, giving them the full timeout. It doesn't waste timeout budget on clearly-unreachable addresses.

Why It Worked at the Office

Simple: the office router doesn't have DNS64 enabled. DNS at the office returned only IPv4 addresses:
1
2
3
4
Office DNS response:
54.87.95.156 <- IPv4 only
184.73.238.207 <- IPv4 only
52.4.253.143 <- IPv4 only
No IPv6 addresses. No Happy Eyeballs confusion. Node.js connects normally. Authentication succeeds.

Why the CLI Worked at Home

The Kiro CLI uses a different HTTP client stack or different connection settings. Many CLI tools either:
  • Disable autoSelectFamily (Happy Eyeballs)
  • Use a custom HTTP agent with family: 4 (IPv4 only)
  • Use a more generous timeout configuration
  • Are built on a different Node.js version or use native HTTP libraries

The Fix

The root cause: my home router advertises DNS64 (fake IPv6 addresses) but doesn't actually provide IPv6 connectivity.
The fix is to tell my computer to not use IPv6 on my home WiFi, since it's completely non-functional:
1
2
3
4
5
6
7
8
9
# Find your WiFi connection name
nmcli connection show --active

# Disable IPv6 on your home WiFi
nmcli connection modify "YOUR_WIFI_NAME" ipv6.method "disabled"

# Reconnect to apply
nmcli connection down "YOUR_WIFI_NAME"
nmcli connection up "YOUR_WIFI_NAME"

What this does:

  1. Disables IPv6 on the network interface. Your computer won't attempt IPv6 connections.
  2. DNS results get filtered. getaddrinfo() won't return AAAA records for an interface without IPv6.
  3. Node.js Happy Eyeballs has nothing to fight about. Only IPv4 addresses, direct connection.

What this doesn't affect:

  • Your office WiFi (different connection profile, unaffected)
  • IPv4 connectivity (completely unchanged)
  • All your other apps (they only worked via IPv4 anyway)
  • Connection speeds (if anything, slightly faster without the IPv6 detour)

Verifying the Fix

After applying:
1
2
3
4
5
6
7
8
9
10
# Before: DNS returned fake IPv6 + real IPv4
$ resolvectl query oidc.us-east-1.amazonaws.com
64:ff9b::6438:8ee7 <- BROKEN fake IPv6
52.45.155.180 <- Working IPv4

# After: IPv4 only
$ resolvectl query oidc.us-east-1.amazonaws.com
34.194.243.91 <- Working IPv4
100.60.124.181 <- Working IPv4
184.73.238.207 <- Working IPv4
Node.js connects successfully:
1
SUCCESS - Status: 200 Time: 3672 ms
Kiro IDE signs in on the first try. No more random timeouts during coding sessions.

The Bigger Picture

This bug affected every HTTPS request my IDE made from my home network. Not just authentication. That's why I had frequent timeouts during normal usage (AI responses, remote tools, telemetry). Every API call to AWS services was hitting the same Happy Eyeballs vs DNS64 conflict.
If you're a developer in a region with:
  • High latency to cloud providers (>250ms)
  • A home router with IPv6 "features" enabled
  • Using any Electron-based IDE (VS Code, Kiro, Cursor)
  • Getting intermittent ETIMEDOUT errors
You probably have this problem and don't know it. You might think "my internet is slow" or "this tool is buggy" when the real issue is a 250ms timeout racing against a 500ms real-world connection time.

Quick Reference: How to Check if You Have This Problem

1
2
3
4
5
6
7
8
9
10
11
12
# 1. Check if your DNS returns 64:ff9b:: addresses
resolvectl query any-aws-service.amazonaws.com
# If you see 64:ff9b:: prefixed addresses, you have DNS64

# 2. Check if you actually have IPv6 connectivity
ip -6 route show default
# If this returns nothing, IPv6 isn't working

# 3. If both are true: DNS64 active + no IPv6 route = you have this problem
# Fix:
nmcli connection modify "YOUR_WIFI" ipv6.method "disabled"
nmcli connection down "YOUR_WIFI" && nmcli connection up "YOUR_WIFI"

Alternative Fixes

Option A: Fix it in /etc/gai.conf (system-wide IPv4 preference, requires sudo)
1
echo 'precedence ::ffff:0:0/96 100' | sudo tee -a /etc/gai.conf
This tells the system to always sort IPv4 addresses before IPv6 in DNS results.
Option B: Fix it on the router
Log into your router and disable DNS64/NAT64 if you're not actually using IPv6 connectivity.
Option C: For Node.js apps you control
1
2
const net = require('net');
net.setDefaultAutoSelectFamily(false);
Or start Node with: --no-network-family-autoselection
Option D: Wait for Node.js to fix it
The Node.js team is aware (Issue #54359 ). Future versions may handle the "instant IPv6 ENETUNREACH + slow IPv4" pattern more gracefully.

Technical Details

ComponentValue
OSLinux (Pop!_OS / Ubuntu)
IDEKiro IDE 1.0.182 (Electron-based)
Node.jsv22.22.0 (bundled with Electron)
DNS Resolversystemd-resolved (stub at 127.0.0.53)
Upstream DNSHome router at 192.168.100.1 (DNS64 enabled)
NetworkWiFi, IPv4-only connectivity, no IPv6 route
AWS Regionus-east-1 (OIDC endpoint)
Auth MethodAWS SSO Identity Center (IDC) via PKCE
Broken FeatureautoSelectFamily (Happy Eyeballs, RFC 8305), Node.js default since v20
Node.js Issue#54359 

Lessons Learned

  1. "Works at the office, not at home" = network/DNS difference. Not an application bug.
  2. DNS64 without working NAT64 is worse than no IPv6 at all. It creates phantom addresses that waste connection attempts.
  3. Different HTTP clients handle dual-stack failures differently. curl is graceful, Node.js v20+'s Happy Eyeballs is not.
  4. The 250ms autoSelectFamilyAttemptTimeout is too aggressive. For developers in Africa, Asia, South America, or anyone on high-latency connections, this kills legitimate IPv4 connections.
  5. Windows hides this problem. Its network stack is more conservative about using IPv6 addresses when connectivity is questionable. Linux trusts DNS literally.
  6. Check your IDE logs. They usually tell you exactly what's failing. In my case: TimeoutError [ETIMEDOUT] on registerClient pointed straight to the network layer.

If this helped you, share it. The combination of DNS64 + no IPv6 route + Node.js Happy Eyeballs is hitting developers worldwide, especially in regions far from cloud provider data centers. Many just think their tool is buggy or their internet is slow.

References

Series: KIRO (2 articles)

  1. 1
    Fixing Kiro IDE SSO Authentication Timeouts on Linux: A DNS64 and IPv6 Deep Dive This article
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article