I’ve been working a little in the world of HTTP Authentication. When you connect a system to another system, there’s usually a set of tokens that get passed around and managed and sometimes accidentally pushed to a public git repo.
When you try to connect to a website that requires a user login, you’ll be sent back a 401 response with a WWW-Authenticate: header. Except you won’t. You’ll be sent a 302 redirect to a login page.
That’s a little unfortunate for anyone doing server-to-server as the 401 response is ideal for APIs. Instead, if you get a 200 response (after you follow the redirect) and the contents looks like HTML with a login form instead of the JSON you were expecting, then your API token must have just expired! (And if you were actually expecting some HTML, good luck!)
“Big man, walking in the park. Wigwam, frightened of the dark.”
WWW-Authenticate
Let’s talk about this header. The 401 says you need to be logged in, but the header tells you exactly how you do that. This is known as a “Challenge” in the parlance. The client is being challenged to authenticate their identity somehow. Here’s what one of those headers with a challenge looks like.
WWW-Authenticate: Basic realm="My Web Site"
Looks simple enough. “Basic” means basic user/password style authentication. Your next request includes a username and password in a base64-encoded block. Simple.
The first thing to realize is that HTTP does allow a response to have many headers of the same name. If your HTTP library gives you a function that returns a named header’s single string value, then the designer of that library has made a mistake. A mistake I’ve made myself so you’re in good company.
This does mean that if a server supports many different methods of authentication and lets the client pick one, that response with the many challenges is either going to have to list many of them in a single header or return single challenges in multiple headers.
It means that this header…
WWW-Authenticate: Basic realm="My site"
WWW-Authenticate: Bearer realm="Still my site"
WWW-Authenticate: IMadeItUp realm="No really I did"
and this header…
WWW-Authenticate: Basic realm="My Site", Bearer realm="Still my site", IMadeItUp realm="No really I did"
are completely equivalent.
Both ways are a trade off. Some HTTP libraries simply don’t handle multiple headers with the same name, so the single header with multiple challenges might be preferable, but then that’s a whole other can of worms.
Let’s open the can, but hold on if your can opener is x.Split(',')!
“But what do you mean by comma?”
A surprising amount of HTTP tooling falls apart the moment you look closely at the WWW-Authenticate header. On paper it is very simple. The server lists one or more authentication schemes and the client chooses one. In practice, the header is a tiny grammar with decades of historical baggage, where commas, spaces, and equals signs all change meaning depending on the parsing state. It’s one of those corners of HTTP where the RFC is technically complete but practically opaque. If only JSON was a thing back then.
The core problem is that the header has to express three very different forms. It could be a bare scheme name, or a scheme with a “token68”, or most commonly a scheme with a set of named parameters. And it uses the same punctuation for all of them. A comma might mean “next parameter” or “next scheme”. An equals sign might mean “this is a parameter” or “this is padding at the end of a token68”. A space might be a separator, or it might be meaningless, or it might be forbidden entirely depending on what came before. If you’re thinking of splitting on commas or equals signs, you’re already in trouble.
Let’s look at a worst case scenario…
WWW-Authenticate: Newauth realm="apps, or the whole enterprise", type=1, title="Say \"hello\"", Basic realm="simple", Bearer dXNlcjpwYXNz==, Digest realm="notice, the comma here too", qop="auth, auth-int", algorithm=SHA-256
“So Newauth is the challenge type. There’s a comma inside the realm but it’s inside a quoted string. So we have realm, type, and title. So far so good. Basic followed by a space. That’s a new scheme, or is it a parameter and they’ve put a space before the equals? Let’s read ahead, no it’s definitely a new scheme, keep going. The Bearer scheme has a parameter called dXNlcjpwYXNz with a value =, that’s not allowed it must be a token68 value, keep going…”
The grammar makes things even more interesting because a challenge can contain either a token68 or a set of parameters, but never both. That single rule changes how you interpret every character that follows the scheme name. If the first token after the scheme looks like a token68 and is followed by a comma, that comma must be a scheme separator. If the first token looks like name=value, then every comma that follows might be another parameter, unless it’s actually the start of a new scheme. The meaning of each punctuation mark is contextual, and the context changes as you parse.
This is exactly the kind of problem that looks trivial until you try to write a parser. Once you do, you discover the edge cases. Quoted strings containing commas, token68 values ending in multiple equals signs, malformed headers that need graceful handling, the subtle rule that whitespace is allowed almost everywhere except where it absolutely isn’t. The RFC, to be fair, does answer all these questions, but your boss keeps asking you why a simple split-by-comma parser is taking so long. After implementing all of this myself, I realized there wasn’t a clean, reusable library that handled the full grammar correctly. So I wrote one.
“I swear, sometimes, that man is out to get me.”
Downloads: zero
I’ve now published WWWAuthenticateTools on NuGet, a small focused library that can parse and build WWW-Authenticate headers correctly, round-trip them safely, and give you a clean object model instead of a pile of string-splitting heuristics. If you’ve ever had to deal with multiple authentication schemes, custom schemes, or clients that insist on single‑line headers, this library should save you a lot of pain. (It’s still in a pre-release state with a zero-dot version. I’ll change it to one-dot-zero once I’ve had a few people review it.)
This library explicitly avoids integrating with any HTTP libraries. Think of it like your JSON or XML parser. Strings come in, strings go out. I’m planning to write Python and JS/TypeScript ports, but if you want to port it to your favorite ecosystem, please do. If you’ve found a bug or you want to contribute a test vector, please see the project’s Github page.
Picture credits 📸 “Free Hugs” by me. 📸 “Cat on Laptop” by Doug Woods. (Creative Commons)
IP address exhaustion is still with us. Back in the early 1990s, when the scale of the problem first became obvious, the projections were grim. Some estimates had us running out of IPv4 addresses as early as 2005 and even the optimistic ones didn’t push much beyond the following decade.
As the years passed, we got clever. Or perhaps, more desperate.
We managed to put off that imminent exhaustion for decades, breaking the Internet in the process in small, subtle ways. Want multiple home machines behind a single IP? No problem — we invented NAT. ISPs want in on that “multiple devices, one address” trick? Sure, have some Carrier‑Grade NAT. Want to run a server on your home machine? Er… no.
And through all of this, IPv6 has been sitting there patiently. It fixes the address shortage. It fixes autoconfiguration. It fixes fragmentation. It fixes multicast. It fixes almost everything people complain about in IPv4.
But hardly anyone wants it.
The problem isn’t that IPv6 is bad, but that deploying it means spending money before your neighbors do and no one wants to be the first penguin off the ice shelf. So we’ve ended up in a long, awkward stalemate. IPv6 is waiting for adoption and IPv4 is stretched far beyond what anyone in 1981 imagined.
But what if it hadn’t gone that way? What if the “IP Next Generation” team that designed IPv6 had chosen a different path? One that extended IPv4 instead of replacing it.
Let’s take a visit to that parallel universe.
“Images of broken light which dance before me like a million eyes, they call me on and on across the universe. Thoughts meander like a restless wind inside a letter box, they tumble blindly as they make their way…”
1993 — The Birth of IPv4x
It’s 1993, and the IP‑Next‑Generation working group has gathered to decide the future of the Internet. The mood is earnest, a little anxious, and very aware that the world is depending on them.
One engineer proposes a bold idea: a brand‑new version of IP with 128‑bit addresses. It would need a new version number but it would finally give the Internet the address space it deserved. Clean. Modern. A fresh start. IPv6!
Another engineer pushes back. A brand‑new protocol sounds elegant but IPv4 is already everywhere. Routers, stacks, firmware, embedded systems, dial‑up modems, university labs, corporate backbones. Replacing it outright would take decades and no one wants to be the first to deploy something incompatible with the rest of the world.
So the group settles down and agrees what that would look like. People want the same IP they’re used to but with more space. But if this idea is going to have legs, there is one requirement that is going to be unavoidable.
The new protocol must work across existing IPv4 networks from day one.
The Version field must remain 4.
The destination must remain a globally routable 32‑bit IPv4 address.
The packet must look, smell, and route like IPv4 to any router that doesn’t understand the new system.
And so IPv4x is born.
In a nutshell, an IPv4x packet is a normal IPv4 packet, just with 128‑bit addresses. The first 32 bits of both the source and target address sit in their usual place in the header, while the extra 96 bits of each address (the “subspace”) are tucked into the first 24 bytes of the IPv4 body. A flag in the header marks the packet as IPv4x, so routers that understand the extension can read the full address, while routers that don’t simply ignore the extra data and forward it as usual.
Who owns all these new addresses? You do. If you own an IPv4 address, you automatically own the entire 96‑bit subspace beneath it. Every IPv4 address becomes the root of a vast extended address tree. It has to work this way because any router that doesn’t understand IPv4x will still route purely on the old 32‑bit address. There’s no point assigning part of your subspace to someone else — their packets will still land on your router whether you like it or not.
An IPv4 router sees a normal IPv4 packet and routes according to the 32‑bit target address in the header, while an IPv4x router sees the full 128‑bit target address and routes according to that instead.
This does mean that an ordinary home user with a single IPv4 address will suddenly find themselves in charge of 96-bits of address space they never asked for nor will ever use, but that’s fine. There are still large regions of the IPv4 space going unused.
“If you’re still there when it’s all over, I’m scared I’ll have to say that a part of you has gone.”
1996 — The First IPv4x RFC
By 1996, the IPv4x design had stabilized enough for the working group to publish its first formal RFC. It wasn’t a revolution so much as a careful extension of what already worked.
DNS received a modest update. A normal query still returned the familiar A record, but clients could now set a flag indicating “I understand IPv4x”. If the server had an extended address available, it could return a 128‑bit IPv4x record alongside the traditional one. Old resolvers ignored it. New resolvers used it. Nothing broke.
DHCP was updated in the same spirit. Servers could hand out either 32‑bit or 128‑bit addresses depending on client capability.
Dial‑up stacks were still distributed with modem software, not the OS, which turned out to be a blessing: the major dial‑up packages all added IPv4x support within a year.
Adoption was slow but steady. The key advantage was that the network didn’t have to change. If your machine spoke IPv4x but the next router didn’t, the packet still flowed. Old routers forwarded based on the top 32 bits. New routers used the full 128.
MIT and the First Large‑Scale Deployment
The first major adopter was MIT. They had been allocated the entire 18.0.0.0/8 block in the early ARPANET era and they were famously reluctant to give it up. Stories circulated about individual buildings — some zoned for fewer than a dozen residents — sitting on entire /24s simply because no one had ever needed to conserve addresses.
IPv4x gave them a way forward and to show their credentials as responsible stewards. Every IPv4 address in their /8 became the root of a 96‑bit subspace. MIT deployed IPv4x experimentally across their campus backbone and the results were encouraging. Nothing broke. Nothing needed to be replaced overnight. It was the perfect demonstration of the “no flag day” philosophy the IPng group had hoped for.
Their success reassured everyone else that IPv4x was not only viable, but practical. Other large networks began making small updates during their weekend maintenance windows.
Buoyed by this success, IANA announced a new policy. All /8 blocks that are currently unused are reserved for IPv4x only.
“Hypnotizing, mesmerizing me. She was everything I dreamed she’d be.”
2006 — Ten Years of IPv4x
By 2006, IPv4x had firmly established itself. Dial‑up was fading, broadband was everywhere, and homes with multiple computers were now normal. IPv4 hadn’t vanished — some ISPs and server farms stuck to an “if it ain’t broke” philosophy.
“IPv4x when we can. NAT when we must.”
Windows XP embodied this mindset. It always asked DNS for an IPv4x address first, falling back to IPv4 when necessary and relying on NAT only as a last resort.
Residential ISPs began deploying IPv4x in earnest. Customers who wanted a dedicated IPv4 address could still have one — for a fee. Everyone else received an IPv4x /64, giving them 64 bits for their own devices. ISPs used carrier‑grade NAT as a compatibility shim rather than a lifeline: if you needed to reach an IPv4‑only service, CGNAT stepped in while IPv4x traffic flowed natively and without ceremony.
The old IPv4 pool finally ran dry in 2006, just in time for the anniversary. There were still plenty of unused /8 blocks, but these had all been earmarked for IPv4x, and IANA refused to budge. If you wanted more addresses, they would have to be the IPv4x kind.
Peer‑to‑Peer and the IPv4x Backlash
IPv4x had its fans, but it also had one determined opponent: the music industry.
Under IPv4 and NAT, peer‑to‑peer networking had always been awkward, especially if you weren’t a nerd who understood IP addresses. If you wanted to participate in peer-to-peer, you needed to log into your router’s admin panel and mess with arcane configurations which every router manufacturer had a different name for. Many gave up and simply decided music piracy wasn’t for them.
IPv4x removed all that friction. Every device had a stable and globally reachable address. File‑sharing exploded as peer-to-peer software was simple to use. You didn’t need to poke about with your router, it all just worked.
One trade group identified IPv4x as the cause of the growth in music file sharing and ran with the slogan “The X is for exterminating your favorite bands.” That stung a little but it didn’t stick. Cheap international calls, multiplayer games, chat systems and early collaboration tools all flourished. IPv4x didn’t just make peer‑to‑peer easier but it made direct communication the default again.
“They’re Justified, and they’re Ancient and they drive an ice cream van. They’re Justified and they’re Ancient, with still no master plan. The last train left an hour ago, they were singing All Aboard, All bound for Mu Mu Land.”
2016 — The Tipping Point
By 2016, IPv4x was the norm. The only major holdouts were the tier‑1 backbones, but that had always been part of the plan. They didn’t need IPv4x at all as the top 32 bits were enough for global routing between continents. But mostly, their eye‑wateringly expensive hardware didn’t really need replacing.
A few websites still clung to IPv4, forcing ISPs to maintain CGNAT systems, until one popular residential ISP broke ranks.
“IPv4x, or don’t.”
For customers of this ISP, those last few IPv4‑only sites simply failed. Support staff were given a list of known‑broken websites and trained to offer an alternative plan if a customer insisted the fault lay with the ISP. Most customers just shrugged and moved on. As far as they were concerned, those websites were simply malfunctioning.
Eventually, a technically minded customer pieced together what was happening and blew the whistle. A few dogs barked, but almost no one cared. The ISP spun the story that these websites were using “out‑of‑date” technology, but not to worry, they had an option for customers who really needed CGNAT support, provided they were willing to pay for it.
2020 — The Pandemic and IPv4x’s Quiet Triumph
When the world locked down in 2020, IPv4x quietly proved its worth.
The most popular video‑conferencing platforms had long since adopted a hybrid model. The operators centralized authentication and security, but handed the actual media streams over to peer‑to‑peer connections. Under IPv4/NAT, that had always been fragile but under IPv4x it was effortless.
Remote desktop access surged as well. People had left their office machines running under their desks and IPv4x made connecting to them trivial. It simply worked.
“You run to catch up with the sun, but it’s sinking. Racing around to come up behind you again. The sun is the same in a relative way, but you’re older. Shorter of breath, and one day closer to death.”
2026 — Thirty Years of IPv4x
By 2026, as the world celebrated the thirtieth anniversary of IPv4x, only a few pain points remained. The boundary between the first 32 bits and the remaining 96 was still visible.
If you were a serious network operator, you wanted one of those 32-bit IP addresses to yourself which you could attach your own router to. If you weren’t important or wealthy enough for one of those, you were at the mercy of whoever owned the router that was connected to those top 32-bits. But it wasn’t a serious problem. The industry understood the historical baggage and lived with it.
Public DNS resolvers were still stuck on IPv4. They didn’t want to be — DNS clients had spoken IPv4x for years — but the long tail of ancient DHCP servers kept handing out 32‑bit addresses. As long as those relics survived in wiring cupboards and forgotten branch offices, DNS had to pretend it was still 1998.
MIT still held onto their legendary 18.0.0.0/8 allocation, but their entire network now lived comfortably inside 18.18.18.18/32. They remained ready to release the rest of the block if the world ever needed it.
It was around this time that a group of engineers rediscovered an old, abandoned proposal from the 1990s: a clean‑slate protocol called IPv6, which would have discarded all legacy constraints and started fresh with a new address architecture. Reading it in 2025 felt like peering into a parallel universe.
Some speculated that, in that world, the Internet might have fully migrated by now, leaving IPv4 behind entirely. Others argued that IPv4 would have clung on stubbornly, with address blocks being traded for eye‑watering sums and NAT becoming even more entrenched.
IPv4x had avoided both extremes. It hadn’t replaced IPv4 but absorbed it. It hadn’t required a revolution but enabled an evolution. In doing so, it had given the Internet a smooth transition that no one noticed until it was already complete.
“Bells will ring. Sun will shine. I’ll be his and he’ll be mine. We’ll love until the end of time and we’ll never be lonely anymore.”
Back in the Real World
Of course, none of this really happened.
IPv4x was never standardized, no university ever routed a 96‑bit subspace beneath its legacy /8, and the world never enjoyed a seamless, invisible transition to a bigger Internet. Instead, we built IPv6 as a clean break, asked the world to deploy it alongside IPv4, and then spent the next twenty‑five years waiting for everyone else to go first.
And while imagining the IPv4x world is fun, it’s also revealing. That universe would have carried forward a surprising amount of legacy. IPv6 wasn’t only only a big chunk of address pace but a conscious modernization of the Internet. In our IPv4x world, NAT would fade, but ARP and DHCP would linger. The architecture would still be a patchwork of 1980s assumptions stretched across a 128‑bit address space.
IPv6, for all its deployment pain, actually fixes these things. It gives us cleaner auto-configuration, simpler routing, better multicast, and a control plane designed for the modern Internet rather than inherited from the ARPANET. The road is longer, but the destination is better.
Still, imagining the IPv4x world is useful. It reminds us that the Internet didn’t have to fracture into two incompatible address families. It could have grown incrementally, compatibly, without a flag day. It could have preserved end‑to‑end connectivity as the default rather than the exception.
And yet, the real world isn’t a failure but a different story. IPv6 is spreading while IPv4 is receding. The transition is messy, but it is happening. And perhaps the most important lesson from our imaginary IPv4x universe is this.
The Internet succeeds not because we always choose the perfect design, but because we keep moving forward anyway.
Epilogue
It was while writing this speculative history that the idea for SixGate finally clicked for me. In this alternate timeline, there’s a moment when an old IPv4‑only router hands off to a router that understands IPv4x. The handover is seamless because there’s always a path from old to new. The extended IPv4x subspace lives under the IPv4 address and the transition is invisible.
In our real world — the one split between IPv4 and IPv6 — we don’t have that luxury. But it led me to realize that if only an IPv4 user had a reliable way to reach into the IPv6 world, the transition could be smoother and more organic.
That’s where SixGate steps in. A user stuck on IPv4 can ask the IPv6 world for a way in. By returning a special SRV record from the ip6.arpa space, the user receives a kind of magic portal, provided by someone who wants them to be able to connect. Not quite as seamless as the router handover in our parallel universe, but impressively close given the constraints we live with.
So I hope SixGate can grow into something real — something that helps us get there a little faster. Maybe it will give IPv6 the invisible on‑ramp that IPv4x enjoyed in that parallel world.
Either way, imagining the road not taken has made the road we’re on feel a little clearer, and a little more hopeful.
And yes, this whole piece was a sneaky way to get you to read my SixGate proposal. Go on. You know you want to.
“The Watusi. The Twist. El Dorado.”
Credits 📸 “Chiricahua Mountains, Portal, AZ” by Karen Fasimpaur. (Creative Commons) 📸 “Splitting Up” by Damian Gadal. (Creative Commons) 📸 “Reminder Note” by Donal Mountain. (Creative Commons) 📸 “Cat on Laptop” by Doug Woods. (Creative Commons) 📸 “Up close Muscari” by Uroš Novina. (Creative Commons) 🎨 “Cubic Rutabaga” generated by Microsoft Copilot. 📸 “You say you want a revolution” by me. 🌳 Andrew Williams for inspiring me to pick the idea up. 🤖 Microsoft Copilot for helping me iron out technical details and reviewing my writing.