Martin Harris

"Ceci n'est pas une API Gateway" — René Magritte (paraphrased)

Making cloud abstractions tangible through physical hardware.

Chat with me →

Why Redirecting an API from HTTP to HTTPS Is a Really Bad Idea

Why Redirecting an API from HTTP to HTTPS Is a Really Bad Idea

A sealed envelope being handed through an open window into the rain before the courier is politely redirected to the front door, the letter already soaked and its ink running

There's a CloudFront setting most of us pick on autopilot: viewerProtocolPolicy: REDIRECT_TO_HTTPS. For a website it's the right call. For an API it's a quiet security hole, and I know because I shipped it — it sat in one of my own CDK stacks until a pull-request review caught it.

This is a short post about a one-line diff, and why the wrong line is so much worse than it looks.

The website case, where the redirect is fine

A browser asks for http://example.com/. The server answers 301, the browser retries over https://, and everything from then on is encrypted. The first request leaked nothing worth protecting — a GET for a public page, some standard headers. The redirect is just a nudge onto the secure URL, and HSTS makes the nudge permanent after the first visit. Good hygiene all round.

The reasoning silently baked into that: the first request carries no secrets. For a public website, that's true.

The API case, where it isn't

An API request is a different animal. It carries an Authorization: Bearer … header, or an x-api-key, or a session cookie — and possibly a request body full of customer data.

Here's the part that matters: the redirect happens after the request arrives. By the time CloudFront — or any server — can send a 301, the client has already transmitted the entire request over the unencrypted connection. Headers, credentials, body, all of it, in cleartext, past every network hop between the client and the edge. The 301 doesn't protect the secret. The secret was on the wire before the redirect response existed. All the redirect does is politely relocate a request that has already leaked.

The silent part is the worst part

If this failed loudly, it would barely matter. It doesn't.

Nearly every HTTP client library follows redirects by default, silently. A developer misconfigures a base URL as http://, the library sends the credentialled request in cleartext, gets the 301, transparently retries over HTTPS, and hands back a 200. The call works. The tests pass. The dashboard is green. Nobody ever learns that the token is going out in plaintext on every single call.

A silent leak beats a loud failure — for the attacker. The redirect converts a configuration mistake that should be a blocking error into one that is invisible indefinitely.

The one-line fix

For an API behind CloudFront, the correct setting is HTTPS_ONLY:

defaultBehavior: {
    // viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,  // ❌ relocates already-leaked requests
    viewerProtocolPolicy: ViewerProtocolPolicy.HTTPS_ONLY,            // ✅ refuses them, loudly
    ...
}

Now an HTTP request gets a 403. The misconfigured client fails immediately and loudly on its first call, the developer sees it, and the fix happens where it belongs — in the client, which should never have spoken plaintext in the first place. One cleartext request still occurred, which is why the real fix is the client's base URL; but a failure you see once beats a leak you never see, every time. (API Gateway itself takes the same stance: it doesn't expose a plaintext listener at all.)

What about HSTS? It does this job for browsers — but only after a first visit establishes the policy, and API clients aren't browsers and mostly don't honour it anyway. For an API there is no first-visit grace period worth preserving. Just refuse HTTP.

The diff that prompted this

This isn't hypothetical humility: the API distribution in my blog-pipeline project originally shipped with REDIRECT_TO_HTTPS, copied on autopilot from the website distribution next to it. A review comment on the PR flagged it, and the fix was the one-liner above. The website distribution kept its redirect, because for the website the redirect is correct.

That's the whole subtlety. The same setting is good hygiene on one distribution and a credential leak on the one next to it, and the only difference is what the first request carries.


Martin Harris connects cloud infrastructure to the real world. If your API key has ever taken the scenic route through port 80, you're in the right place.


If you find this blog useful, please consider a donation.