POST-as-GET and privacy

I realize this topic doesn't really matter while unauthenticated GETs are still supported for the various ACME objects. But when it eventually gets turned off, I'm curious what the intent is.

For things like Orders, Authorizations, and Challenges that are tied to a specific account, should any ACME account be able to sign a POST-as-GET request to query those resources if they know the location/URL? Or should only the account owner be able to?

Today, it appears any account can sign the request and get the data. But will that always be the case?

In section 6.3 the spec says:

On receiving a request with a zero-length (and thus non-JSON) payload, the server MUST authenticate the sender and verify any access control rules.

But I can't find any references on mandated access control rules associated with the object types. Is it basically a server implementation choice?


It was my understanding that only the ACME account to which the resources (orders, authzs, challenges) belong can access them. When you say that any other account can access them as well via POST-as-GET, did you test that with Boulder? Or Pebble? Or both? I would say that it would be a bug if that’s possible.

1 Like

I haven’t tested against Pebble or Prod Boulder yet. But it definitely works against Staging Boulder. I’ve also only tested getting authorization objects so far.

1 Like

The merge of “POST-as-GET” into the spec cites “privacy concerns raised in Adam’s and Ben’s AD reviews” (but without link to theses, sadyl) :

Maybe @jsha remembers? (Richard Barnes doesn’t seams of have an account here)

I personally feel it’s a but that should be fixed: if the requirement of POST-as-GET only require to create any account, it doesn’t protect anything.

@tdelmas At a guess, probably these:


Thank you @mnordhoff !

The most wiring example there ends with the email and phone number. In the Let's Encrypt context, as email validation is not allowed and the account entry point protected, I think it doesn't apply. Only the discovery of domains. Which will ends up in CT logs. But could it may help discover the link between one domain and another (with are not in the same certificate)? (which can be problematic if possible, like and

I don't see anything much relevant there, did I missed it?

Skimming the message, I didn't see a lot, but it was mentioned:

Section 6.2 notes that servers MUST NOT respond to GET requests for
sensitvie resources. Why are account resources the only sensitive ones?
Are authorizations not sensitive? Or are those considered to fall under
the umbrella of "account resources" (Section 7.1 seems pretty clear that
they do not)?

On the other hand, one of the other reviewers was named Ben Campbell; they might have said something I missed.

1 Like

Thanks for finding those links, @mnorhoff! That is accurate. The specific issue raised by reviewers was that some CAs might consider the account ID-to-hostname matching sensitive. More broadly, the issue was that we had a protocol in which some elements were authenticated, and some were not, based only on whether they happened to have polling semantics or "write" (i.e. POST) semantics.

Right now we don't specify any access control rules for Orders, Authorizations, and Challenges (because we don't consider those resources sensitive), but for best compatibility with other ACME servers, you should probably assume that most ACME servers will enforce that those objects can only be retrieved by the account they were created for. It's possible we might implement such a rule in Boulder if it looks like it will be useful in encouraging the client ecosystem in the right direction.


Is there any update on the deprecation schedule for unauthenticated GETs on staging? The latest update to ACME v2 - Scheduled deprecation of unauthenticated resource GETs says that POST-as-GET would be required on staging from November 1, 2019. Unauthenticated GETs seem to work today.

With the privacy thing, it would suit us to keep the status quo. When providing email support, we lean on order URLs quite a bit to troubleshoot. I’d prefer not to start logging entire response bodies like Certbot does.

1 Like

I think I may be misunderstanding what you have written here. I tried testing access across accounts and it seems like access control is enforced in Boulder.

1 Like

I’m pretty sure you’re right @_az. There was a bug in the code in my initial tests that was still using the correct account instead of the alternate account. After fixing it, I’m now getting the same errors as your tests.

So yay for privacy, but boo for third party troubleshooting?

1 Like

Let's Encrypt specific API for resource GET w/o POST-as-GET · Issue #4577 · letsencrypt/boulder · GitHub :relieved:


You're right. Thanks for checking me on this. At the time I wrote the above, I had read @rmbolger's results, and went looking in the Boulder code for the access controls I had assumed were there. Not seeing them, I must have retconned a reason why they weren't there. Definitely appreciate you helping sort out the facts!


This date slipped off of my own radar, thanks for the bump. I think we need to discuss internally when we intend to make this switch. Speaking personally I wouldn't be sad if we decided to postpone the change until we have a chance to implement #4577.

We're going to plan to roll this out in staging Dec 4th. See my latest comment on the announcement thread.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.

Am I doing something wrong while trying to use the unauthenticated GET API?

I created an order with Certbot:

2020-01-30 17:17:10,968:DEBUG:urllib3.connectionpool: "POST /acme/new-order HTTP/1.1" 201 357
2020-01-30 17:17:10,970:DEBUG:acme.client:Received response:
HTTP 201
Server: nginx
Date: Thu, 30 Jan 2020 06:17:10 GMT
Content-Type: application/json
Content-Length: 357
Connection: keep-alive
Boulder-Requester: 10776612
Cache-Control: public, max-age=0, no-cache
Link: <>;rel="index"
Replay-Nonce: 0001cs6S_yutqCZ6kItSSwIbrmM0CQFf9r9UeoqFeGeB8zY
X-Frame-Options: DENY
Strict-Transport-Security: max-age=604800

  "status": "ready",
  "expires": "2020-02-06T06:17:10.911872372Z",
  "identifiers": [
      "type": "dns",
      "value": ""
  "authorizations": [
  "finalize": ""

It’s now 17:45:00 (28 minutes later) and visiting still produces:

  "type": "urn:ietf:params:acme:error:unauthorized",
  "detail": "Order is too new for GET API. You should only use this non-standard API to access resources created more than 15m0s ago",
  "status": 403

Same thing seems to be happening with that order’s authzs too.

Edit: filed

1 Like

A fix for both bugs identified has been merged and should make its way to staging next week, thanks!