Go, HTTP Headers, and Rubber Duck Debugging
A recent Jira ticket instructed me to make a call from one of my Go services to another group’s service. I’d perform a PUT to a specific URL to create a service provider in our access management solution, here known as “Cool Access Manager” or “CoolAM.” For authentication, I’d include an HTTP header with the key “X-CoolAM-Token” and the value of the user’s login cookie. Simple enough. Yes, I’m aware that the “X-“ prefix for HTTP header keys has been deprecated. So I added the following Go code to my service:
req.Header.Set("X-CoolAM-Token", loginCookie)
I ran my code against the Test environment’s CoolAM service . . . and got an HTTP 401 with the following message:
"Authorization Failed: Information is missing/invalid in the headers"
Time to step through the CoolAM service code. I pulled the latest from source control, fired up Eclipse, and set a breakpoint. I configured my local Go service to hit my local CoolAM service instead of the Test environment. And I fired off the request. My breakpoint hit. I stepped. When it got to this line:
if (context.request().getHeader("X-CoolAM-Token") != null) { ... }
the instruction pointer stepped into the “if” condition. The header was there. The login cookie was there. The call authenticated. Everything worked. Why, then, was this not working in the Test environment? I figured some middleware had additional authentication requirements that I needed to satisfy, so I reached out to the middleware group. They replied that no, nothing was trying to authenticate the call until it arrived at the CoolAM service. The 401 was coming from the CoolAM code.
I wasn’t much swayed, I’ll confess, since my debugging sessions seemed to show otherwise. I pressed. I explained. Our CoolAM support person asked me to send him a sample of my request. I launched GoLand and set a breakpoint. When it hit, I grabbed the request headers . . . and saw that I had a header called “X-Coolam-Token”. Yes, that’s “Coolam” and not “CoolAM.” And yes, I know that HTTP headers are supposed to be case-insensitive. I investigated, and learned that, in our Test environment, a middleware appliance whitelists headers case-sensitively. It allows an “X-CoolAM-Token” header but swallows any “X-Coolam-Token” header. Foiled by Go! The Node.js folks here hit the same issue. I googled and found https://dhdersch.github.io/golang/2016/08/11/golang-case-sensitive-http-headers.html and I changed my header-setting code to:
req.Header["X-CoolAM-Token"] = []string{loginCookie}
And then things worked. So thank you, Daniel — you didn’t blog much, but you got me on track. And thank you Jason, who acted as my rubber duck!