Authenticate with the container registry

  • Tier: Free, Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

To authenticate with the container registry, you can use:

For token-based authentication, the token must have the following scopes or permissions:

OperationPersonal, project, group, or deploy token scopesFine-grained personal access token permissions
Pull container imagesread_registryContainer Repository: Read
Push container imagesread_registry and write_registryNot supported
Delete container images and tagsapi1Container Repository: Delete

For more information, see access token scopes and fine-grained permissions for the container registry.

Admin Mode does not apply during authentication with the container registry. For example, you might be an administrator with Admin Mode enabled. A personal access token you create without the admin_mode scope still works with the registry. For more information, see Admin Mode.

Authenticate with username and password

If you have enabled two-factor authentication (2FA) (including email OTP) on your account, you must authenticate with a token.

To authenticate with your username and password, run the docker login command:

shell
docker login registry.example.com -u <username> -p <password>

For security reasons, it’s recommended to use the --password-stdin flag instead of -p:

shell
echo "<password>" | docker login registry.example.com -u <username> --password-stdin

Authenticate with a token

To authenticate with a token, run the docker login command:

shell
TOKEN=<token>
echo "$TOKEN" | docker login registry.example.com -u <username> --password-stdin

After authentication, the client caches the credentials. Later operations make authorization requests that return JWT tokens, authorized to do only the specified operation. Tokens remain valid:

Use GitLab CI/CD to authenticate

To use CI/CD to authenticate with the container registry, you can use:

  • The CI_REGISTRY_USER and CI_REGISTRY_PASSWORD CI/CD variables.

    CI_REGISTRY_USER holds a per-job user with read-write access to the container registry, and CI_REGISTRY_PASSWORD holds its automatically created password.

    shell
    echo "$CI_REGISTRY_PASSWORD" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin
  • A CI/CD job token.

    This token has read (pull) and write (push) access to the container registry of the project that runs the job. The CI/CD job token allowlist controls access to other projects’ registries.

    shell
    echo "$CI_JOB_TOKEN" | docker login $CI_REGISTRY -u $CI_REGISTRY_USER --password-stdin

    You can also use the gitlab-ci-token scheme:

    shell
    echo "$CI_JOB_TOKEN" | docker login $CI_REGISTRY -u gitlab-ci-token --password-stdin
  • A GitLab deploy token.

    shell
    echo "$CI_DEPLOY_PASSWORD" | docker login $CI_REGISTRY -u $CI_DEPLOY_USER --password-stdin
  • A personal access token or fine-grained personal access token.

    shell
    echo "<access_token>" | docker login $CI_REGISTRY -u <username> --password-stdin

Authenticate with the registry API

The container registry has its own API, separate from the GitLab REST API. To call it, get a registry token from GitLab, then pass it in the Authorization: Bearer header. A registry token is different from a personal, project, or group access token.

To get a registry token, send a request to the /jwt/auth endpoint with the scope and actions the token needs:

shell
SCOPE="repository:${CI_PROJECT_PATH}:delete" # or push, pull

curl --request GET \
  --user "${CI_REGISTRY_USER}:${CI_REGISTRY_PASSWORD}" \
  --url "${CI_SERVER_URL}/jwt/auth?service=container_registry&scope=${SCOPE}"

The response is JSON, and the registry token is its token field. Registry repository paths are lowercase, so if your project path contains uppercase letters, convert CI_PROJECT_PATH to lowercase before you use it.

For more information, see the token authentication specification.

List all container repositories

Prerequisites:

  • You must have administrator access.

To list every container repository on the instance, get a registry token with the registry:catalog:* scope, then send a request to the _catalog endpoint:

shell
SCOPE="registry:catalog:*"

curl --request GET \
  --user "<admin-username>:<admin-password>" \
  --url "https://gitlab.example.com/jwt/auth?service=container_registry&scope=${SCOPE}"

curl --header "Authorization: Bearer <registry_token>" \
  --url "https://gitlab.example.com:5050/v2/_catalog"

Troubleshooting

Error: docker login command fails with access forbidden

The container registry returns the GitLab API URL to the Docker client to validate credentials. The Docker client uses basic auth, so the request contains the Authorization header. If the Authorization header is missing in the request to the /jwt/auth endpoint configured in the token_realm for the registry configuration, you receive an access forbidden error message.

For example:

> docker login gitlab.example.com:4567

Username: user
Password:
Error response from daemon: Get "https://gitlab.company.com:4567/v2/": denied: access forbidden

To avoid this error, ensure the Authorization header is not stripped from the request. For example, a proxy in front of GitLab might be redirecting to the /jwt/auth endpoint.

For more information about credential validation with Docker clients, see Container registry architecture.

Error: docker login fails with an authentication error

When GitLab rejects a docker login request, the Docker client displays a JSON error envelope containing an error code and message.

To resolve the error, identify the error code and follow the instructions:

  • UNAUTHORIZED (401): GitLab could not verify the credentials. To resolve:
    • Confirm the password or token is correct and not expired.
    • Confirm the token has the scopes or permissions required for the operation.
    • If the account uses two-factor authentication, authenticate with a token instead of a password. For more information, see authenticate with a token.
  • DENIED (403): GitLab denied access. Check the message:
    • access forbidden: the credentials are valid but do not grant registry access. Confirm the token has the scopes or permissions required for the operation, and that your role allows access to the project’s registry.
    • Pushing to protected repository path forbidden: the target path is protected by container registry protection rules.
    • Access denied: too many failed authentication attempts from this network: abuse protection blocked your network. Wait for the block to expire, or retry from a different network.
    • Access denied: too many distinct sources for this account: the account was used from too many IP addresses. Review where the account is used, then consolidate or stagger the requests.
  • UNSUPPORTED (404): GitLab does not recognize the requested authentication service. To resolve:
    • Verify the registry token service is configured correctly.

If the Docker client instead reports unexpected end of JSON input, the response body was empty or contained invalid JSON.

Error: unexpected end of JSON input

When a proxy or load balancer in front of GitLab strips the response body, you might receive the following error:

Error response from daemon: error parsing HTTP <status> response body: unexpected end of JSON input: ""

To resolve this issue, check the request path between the Docker client and GitLab.

Error: unauthorized: authentication required when pushing large images

When pushing large images, you may see an authentication error like the following:

shell
docker push gitlab.example.com/myproject/docs:latest
The push refers to a repository [gitlab.example.com/myproject/docs]
630816f32edb: Preparing
530d5553aec8: Preparing
...
4b0bab9ff599: Waiting
d1c800db26c7: Waiting
42755cf4ee95: Waiting
unauthorized: authentication required

This error happens when your authentication token expires before the image push is complete. On GitLab Self-Managed, an administrator can increase the token duration.


  1. Deploy tokens do not have the api scope and cannot delete container images or tags. ↩︎