NAME

API::Docker::Role::RegistryAuth - AuthConfig encoding shared by the registry-facing endpoints

VERSION

version 0.004

SYNOPSIS

package API::Docker::API::Whatever;
use Moo;
with 'API::Docker::Role::RegistryAuth';

# The header form: X-Registry-Auth on a registry-facing request
my $header = $self->_registry_auth_header($opts{auth});

# The map-header form: X-Registry-Config on /build, hostname -> AuthConfig
my $cfg_header = $self->_registry_config_header($opts{registry_config});

# The body form: the same credentials as a plain HashRef
my $config = $self->_registry_auth_config($opts{auth});

DESCRIPTION

One AuthConfig, three carriers. The Docker Engine takes registry credentials as a JSON object with the keys username, password, serveraddress, identitytoken and email, and moves it around in three shapes:

  • base64url-encoded in the X-Registry-Auth request header, for POST /images/{name}/push, POST /images/create, GET /distribution/{name}/json and the /plugins family

  • as a base64url-encoded map of registry hostname to AuthConfig in the X-Registry-Config request header, for POST /build -- one build may pull base images from several registries, so it carries a set of credentials rather than one

  • as the plain JSON request body of POST /auth

This role carries the conversion in both directions so every class that speaks to a registry agrees on it, and so a caller can hand the same auth argument to any of them.

It carries the encoding, not the policy. Whether a header is sent at all differs per endpoint on purpose and stays with the endpoint: "push" in API::Docker::API::Images sends X-Registry-Auth on every push because the engine rejects an image push without it, while an anonymous plugin or distribution call sends no header -- their routers decode the header and discard the error, so an absent one is the anonymous case rather than a failure.

The padding is not optional

The engine decodes X-Registry-Auth with Go's base64.URLEncoding, not RawURLEncoding, so the = padding is required. Stripping it makes every push fail with failed to parse "X-Registry-Auth" header ... unexpected EOF -- the anonymous case included, where the payload {} encodes to e30=: three characters and one pad.

METHODS

These are private and composed into the resource classes; they are documented here because the shapes are one decision, not several.

_registry_auth_header($auth) returns the padded base64url value for X-Registry-Auth. undef gives the anonymous encoding e30=, a HashRef is JSON-encoded, and a string that already looks base64-encoded is passed through -- but respelled into the URL-safe alphabet, so a value pre-encoded in standard base64 (with + or /) reaches the wire as the -/_ the engine's base64.URLEncoding decoder expects rather than failing there.

_registry_config_header($map) is the same encoding for X-Registry-Config on POST /build. It takes the same shapes, but the HashRef it JSON-encodes is a map of registry hostname to AuthConfig ({ 'registry.example:5000' => { username => ..., password => ... } }), not a single AuthConfig.

_registry_auth_config($auth) returns the same credentials as a plain HashRef for a JSON request body. undef gives undef -- whether that is an error is the endpoint's call, not this role's. A HashRef is copied, a JSON object is decoded, and a base64url string is decoded back through both layers. Anything that does not read as an AuthConfig croaks.

SEE ALSO

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/p5-api-docker/issues.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <getty@cpan.org>

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.