API Authentication

  • I am fairly positive there is more than the described way in the API docs to authenticate, please add the other ways to the documentation
  • Having any form of access token as a query parameter is VERY discouraged¹ yet it is the only documented way
    • Best way would be to have it as part of the HTTP header
    • This also avoids having to send an URL Form with both the auth token and the actual data all in one

¹ Don’t take it from me, read the OAuth Spec. It clearly says you shouldn’t do it IIRC. Also I think we had that discussion already here but I might be hallucinating.

1 Like

Yeah. I think the reason usually given is that query params are always clear text, even over HTTPS, and can get cached multiple times between the user and the server.

From my experience with the Beeminder API, it seems they’ll accept the token other ways, too, such as via POST form data.

What would be the secure way to do it via a GET request? A custom request header?

1 Like

GET supports bodies, too. But still, header is the way to go

1 Like

And before someone chimes in and cries that GET with a body is weird and odd and not right: think of it as some sort of tribute to the http resource god. You bring them something and in return they speak to you.

This is incorrect. The only part of the URL transmitted in plaintext over HTTPS is the hostname. The path, the query parameters, and so forth are all encrypted.

That said, it’s still a bad idea to do it, if only because query parameters end up in all sorts of places such as in your webserver’s logs. At that point you’ve lost all control over what’s being stored where. This is a good reason not to use query parameters for sensitive information, but that’s because of how they’re treated at rest, not how they’re treated in transit. Over the wire they are exactly as encrypted as the URL path, or as the body of the request.

(See e.g. this stack overflow question for discussion on the topic.)

Yes, a custom header is a good way to handle it.

GET requests with payloads in the body are highly nonstandard, to say the least. You’re not wrong when you describe it this way as something which could be meaningful, but in practice nobody does it, and that itself is a reason for not doing it yourself. Most HTTP server libraries you’d use probably don’t support it, nor will the HTTP client libraries that users will want to use to access your API.

So I’d recommend avoiding GET bodies for this, if only for because of practical difficulties.

2 Likes

The Beeminder Server supports it if I recall correctly.
And what’s your source for the claim that GET with body is likely to not be supported? I have yet to see a http library that forbids that. It’s in the HTTP standard after all.

Great information, @zzq! And I stand corrected. :smiley:

I’d vote for making the Beeminder API contain as few surprises as possible for the average person familiar with using a REST API.

2 Likes

Some libraries support it, while some others go out of their way to forbid it. In Javascript, for instance, both XHR and fetch forbid it. In Haskell, wreq doesn’t allow for it (although I guess you could hack around that using customPayloadMethod), and req (a HTTP client library that takes a very strong approach to encoding everything possible in the type signatures) sets up complicated type-level machinery to explicitly rule it out.

Other libraries do support it: Python’s requests makes GET requests with bodies if you ask it to, and so does cURL both as a command line tool and as a C library. It’s not cut and dry if this is allowed or not, but it definitely isn’t something that everybody is set up to handle.

I’ll argue with the assertion that the HTTP standard explicitly allows for GET requests with bodies. Yes, it doesn’t categorically exclude them, but RFC 2616 says:

[…] if the request method does not include defined semantics for an entity-body, then the message-body SHOULD be ignored when handling the request.

That’s SHOULD, and not MUST, sure. And RFC 2616 is outdated and no longer the latest HTTP/1.1 spec. So there is definitely room for argument. Anyway, the newer RFC 7231 says:

A payload within a GET request message has no defined semantics; sending a payload body on a GET request might cause some existing implementations to reject the request.

This is about as clear a statement as you’re going to get that there is no good answer to this and that the whole topic is unclear, with no real agreed upon behavior for GET requests with bodies.

I’ll also point out that RFC 7540 (the HTTP/2 spec) says:

An HTTP GET request includes request header fields and no payload body and is therefore transmitted as a single HEADERS frame, […]

But on the other hand that’s part of an example, so it’s non-normative. Anyway, you could argue that it’s talking just about a specific example GET request and not GET requests in general, although I’d consider that to be a fairly tortured reading.

All in all, I think this supports what I said previously: there is no one good answer. It’s far from clear to what extent GET requests with bodies are or should be allowed, or what behavior should be enforced by conforming implementations.

2 Likes

okay, fair. Thanks for the nice writeup. It goes to show just how much REST is a retrofitted approach to API design :wink: But that’s a can of worms I don’t wanna open in public. Lot of people seem to be very religious about REST. Not saying here – just in general. Besides it would be offtopic.

I’d already be happy with a more up-to-date API documentation.