aws / aws/containers-roadmap

[ECR] [request]: return 401 with challenge instead of 400 on expired access token

Open
#2,835 0 comments 1 reaction 0 assignees View on GitHub
ECR Proposed
Dominant language
Shell
Stars
5.4k
Forks
334
PR merge metrics
No merged PRs in 30d

Description

### Community Note

* Please vote on this issue by adding a 👍 [reaction](https://blog.github.com/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) to the original issue to help the community and maintainers prioritize this request
* Please do not leave "+1" or "me too" comments, they generate extra noise for issue followers and do not help prioritize the request
* If you are interested in working on this issue or have submitted a pull request, please leave a comment

**Tell us about your request**

When a bearer token presented to `public.ecr.aws` is **expired or invalid**, return `401 Unauthorized` with a `WWW-Authenticate: Bearer …` challenge (per the Docker Registry v2 / OCI token-auth flow), instead of `400 Bad Request`. Today the expired-token case returns `400` with no challenge, which is problematic for registry clients that evict from their access token cache on 401.

**Which service(s) is this request for?**

Amazon ECR — **ECR Public** (`public.ecr.aws`) registry/distribution API, token authentication.

**Tell us about the problem you're trying to solve. What are you trying to do, and why is it hard?**

We noticed that when authenticating to `public.ecr.aws` with the standard Docker Registry v2 bearer-token flow — fetch a token from the realm, cache it, and reuse it until it expires — an **expired or invalid** token is rejected with **`400 Bad Request` and no `WWW-Authenticate` header**, instead of the expected `401 Unauthorized` + `WWW-Authenticate: Bearer realm=…,service=…,scope=…` challenge.

Because `400` carries no challenge and is a client-error class, clients neither refresh the token nor retry — the request hard-fails until the cached token happens to rotate for some other reason. The correct `401 + challenge` would instead tell the client to re-acquire a token from the realm and retry.

Reproduction — status code by auth state (`HEAD /v2/komodor-public/telegraf/manifests/sha256:e9ed55dccc73b5c399c59cc1db44ddef2d14325bd3d0e3cf78ffb2f034ad0e2b`):

| Authorization presented | Response | `WWW-Authenticate` |
|---|---|---|
| (none) | `401 Unauthorized` | `Bearer realm="https://public.ecr.aws/token/",service="public.ecr.aws",scope="aws"` ✅ |
| valid token | `200 OK` | — |
| expired / invalid token | **`400 Bad Request`** | **(none)** ❌ |

Expected behavior:

- Expired / invalid / missing token → `401 Unauthorized` + `WWW-Authenticate: Bearer realm=…,service=…,scope=…` (RFC 6750; ideally `error="invalid_token"` for the expired case).
- Never `400 Bad Request` for an expired/invalid bearer token on an otherwise well-formed request.

The no-token path already returns the correct `401 + challenge` (see table) — aligning the expired/invalid-token path with it fully resolves the issue.

**Are you currently working around this issue?**

No — not currently working around this issue.

**Additional context**

**Attachments**

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the documented HEAD request to public.ecr.aws and compare the no-token, valid-token, and expired or invalid-token responses. Read the Docker Registry v2 bearer-token flow and RFC 6750 expectations. Done means expired or invalid tokens return 401 Unauthorized with the WWW-Authenticate Bearer challenge rather than 400 without a challenge.

Written by the indexing model from the issue text.

Assessment

Tech stack
aws, docker
Domain
api, authentication, cloud
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.