Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Re-authenticate against OCI registry after 403 error
Writing to an OCI registry, as done with `devcontainer features publish` requires authentication against the registry with the `push` OAuth scope. Currently, devcontainer CLI only authenticates or re-authenticates if the registry returns a 401 error (invalid_token). But some registries, notably the IBM Container Registry (icr.io) may also return a 403 error (insufficient_scope) in case of a request being authenticated, but without sufficient scopes (i.e., the token was only valid for the `pull` scope, but `push,pull` was required for write access). Update the code to attempt to re-authenticate in case of a 403 error, just like it's done for a 401 error. The server does supply the correct scope in its `WWW-Authenticate` header and subsequent requests will then work as expected. See also [RFC 6750, Section 3.1 (Error Codes)](https://datatracker.ietf.org/doc/html/rfc6750#section-3.1) for a standards reference. This improvement makes `devcontainer features publish` work with IBM Cloud Container Registry. --- Test: ``` $ devcontainer.js features publish --registry icr.io -n my-ns/features ~/my-feature` ``` HTTP trace (abbreviated) *before* this change: ``` -> POST https://icr.io/v2/my-ns/features/my-feature/tags/list -> 401 Unauthorized www-authenticate: Bearer realm="https://icr.io/oauth/token",service="registry",scope="repository:my-ns/features/my-feature:pull" -> POST https://icr.io/oauth/token client_id=devcontainer&grant_type=refresh_token&service=registry&scope=repository%3Amy-ns%2Ffeatures%2Fmy-feature%3Apull&refresh_token=... <- 200 OK -> POST https://icr.io/v2/my-ns/features/my-feature/blobs/uploads/ authorization: Bearer <- 403 Forbidden: www-authenticate: Bearer realm="https://icr.io/oauth/token",service="registry",scope="repository:my-ns/features/my-feature:pull,push",error="insufficient_scope" ``` HTTP trace (abbreviated) before *after* change: ``` -> POST https://icr.io/v2/my-ns/features/my-feature/tags/list -> 401 Unauthorized www-authenticate: Bearer realm="https://icr.io/oauth/token",service="registry",scope="repository:my-ns/features/my-feature:pull" -> POST https://icr.io/oauth/token client_id=devcontainer&grant_type=refresh_token&service=registry&scope=repository%3Amy-ns%2Ffeatures%2Fmy-feature%3Apull&refresh_token=... <- 200 OK -> POST https://icr.io/v2/my-ns/features/my-feature/blobs/uploads/ authorization: Bearer <- 403 Forbidden: www-authenticate: Bearer realm="https://icr.io/oauth/token",service="registry",scope="repository:my-ns/features/my-feature:pull,push",error="insufficient_scope" -> POST https://icr.io/oauth/token client_id=devcontainer&grant_type=refresh_token&service=registry&scope=repository%3Amy-ns%2Ffeatures%2Fmy-feature%3Apull%2Cpush&refresh_token=... <- 200 OK ``` Note the second auth request after the 403 response.
- Loading branch information