Podman Login: Authenticate to Container Registries

Tested on Red Hat Enterprise Linux 10.2 (Coughlan)
Package podman-5.8.2-5.el10_2.x86_64
Applies to Any Linux host with Podman installed
Privilege Rootful and rootless examples; rootless uses user podtest on the lab host
Scope podman login and podman logout, auth file locations, --username, --password-stdin, --authfile, REGISTRY_AUTH_FILE, --compat-auth-file, credential helpers overview, --secret, --get-login, rootless vs rootful stores, authentication troubleshooting, and a reusable CI pattern. Does not cover private registry deployment, TLS or CA trust fixes, registries.conf mirrors, or push workflows in depth.
Related guides Pull images with podman pull

podman login stores registry credentials on disk so later podman pull, podman push, podman manifest push, and related registry commands can authenticate without prompting every time. It does not open a permanent session with the registry — it writes reusable auth material that Podman reads when a registry operation needs it.


Log in to a container registry

The usual interactive flow names the registry host:

bash
podman login quay.io

Podman prompts for credentials:

output
Username:
Password:
Login Succeeded!

Type your registry username and password (or access token where the registry treats tokens as passwords). Nothing in this flow keeps a long-lived connection open — success means credentials were saved locally.

Confirm which account was stored without printing the password:

bash
podman login --get-login quay.io

When you are not logged in, the command fails clearly:

output
Error: not logged into quay.io

After a successful login, --get-login prints the username Podman will send for that registry host.

On the lab host we exercised the same workflow against a private registry at registry.example.com:5001 using non-interactive flags so the transcript stays scriptable. The auth file behavior is identical across registries.


Log in with an explicit username

When the username is already known, pass it on the command line:

bash
podman login --username labuser registry.example.com:5001

Podman prompts only for the password. That is handy when a human is at the keyboard and the registry account name is fixed.

Avoid putting the password on the command line:

bash
podman login -u USER -p PASSWORD registry.example.com:5001

The password lands in shell history and process listings. Scripts and CI should use --password-stdin instead.


Use --password-stdin for scripts and CI

Pipe the password so it never appears as a CLI argument:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman login --username "$REGISTRY_USER" --password-stdin registry.example.com:5001

Sample output:

output
Login Succeeded!

printf '%s' avoids the newline echo often adds and keeps the secret value under your control. The CI platform or secret store supplies $REGISTRY_PASSWORD; the article examples use environment variable names only, not real credentials.

See which auth file received the entry:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman login \
  --username labuser \
  --password-stdin \
  --verbose \
  registry.example.com:5001

Sample output (tested as rootless user podtest on the lab host):

output
Used:  /run/user/1014/containers/auth.json
Login Succeeded!

The Used: line is the fastest way to confirm where Podman wrote credentials on your host.


Where Podman stores credentials

On Linux the default writable auth file for a normal login is under the runtime directory:

text
${XDG_RUNTIME_DIR}/containers/auth.json

For a typical rootless user that often resolves to:

text
/run/user/$UID/containers/auth.json

Rootful podman login as root on the lab host used a different default path:

text
/run/containers/0/auth.json

That file is JSON. Each registry host maps to a base64-encoded username:password pair — encoding is not encryption. Treat the file like a password store: restrictive permissions and appropriate ownership matter.

Because the default path sits under a runtime directory, it may disappear after reboot or when the user session ends. Do not assume an interactive podman login without --authfile is permanently persistent unless you have verified the path and your session model.


Store credentials in a persistent auth file

When credentials must survive reboots or be shared across several commands, choose the file explicitly:

bash
mkdir -p ~/.config/containers

Log in to the persistent file path:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman login --username "$REGISTRY_USER" --password-stdin --authfile ~/.config/containers/auth.json registry.example.com:5001

Verbose output confirms the persistent path (tested as user podtest on the lab host):

output
Used:  /home/podtest/.config/containers/auth.json
Login Succeeded!

Check permissions — Podman created an owner-only file:

bash
stat -c '%a %U:%G %n' ~/.config/containers/auth.json

Sample output:

output
600 podtest:podtest /home/podtest/.config/containers/auth.json

Point later registry operations at the same file:

bash
podman pull --authfile ~/.config/containers/auth.json registry.example.com:5001/lab/hello:v1

The pull succeeds when the registry holds that tag and the credentials in the auth file are valid. Push and manifest commands accept the same --authfile flag.


Rootless vs rootful authentication

Rootless and rootful Podman maintain separate credential stores because they run under different users with different HOME and runtime paths.

Log in as a normal user:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman login \
  --username labuser \
  --password-stdin \
  registry.example.com:5001

Log in separately for rootful operations:

bash
printf '%s' "$REGISTRY_PASSWORD" | sudo podman login --username "$REGISTRY_USER" --password-stdin registry.example.com:5001

Rootful verbose output on the lab host showed:

output
Used:  /run/containers/0/auth.json
Login Succeeded!

Rootless user podtest wrote to /run/user/1014/containers/auth.json instead. A pull that works as your user can still return unauthorized under sudo podman pull until root has its own login or both commands share an explicit --authfile.


How Podman chooses an auth file

--authfile or REGISTRY_AUTH_FILE selects the primary auth file. Without an override, Podman uses ${XDG_RUNTIME_DIR}/containers/auth.json. When credentials are not found there, containers/image can also search persistent containers auth and Docker-compatible files such as ~/.config/containers/auth.json, ~/.docker/config.json, and ~/.dockercfg, subject to credential-helper configuration.

When in doubt, run podman login --verbose once and read the Used: line rather than assuming a single global path.


Override the auth file with --authfile

Isolate credentials for automation or multiple registry identities:

bash
podman login --authfile /secure/path/auth.json --username "$REGISTRY_USER" --password-stdin registry.example.com:5001

Every registry command in that workflow must reuse the same path:

bash
podman pull --authfile /secure/path/auth.json registry.example.com:5001/lab/hello:v1

Per-command --authfile is ideal for CI jobs, short-lived service accounts, and keeping production registry credentials out of a developer’s default login store.


Set REGISTRY_AUTH_FILE for a session

Export a default auth file for compatible Podman commands in the current shell:

bash
export REGISTRY_AUTH_FILE="$HOME/.config/containers/ci-auth.json"

Log in without repeating --authfile:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman login --username "$REGISTRY_USER" --password-stdin registry.example.com:5001

Verbose output on the lab host (tested as user podtest):

output
Used:  /home/podtest/.config/containers/ci-auth.json
Login Succeeded!

A later pull in the same shell picks up that file automatically:

bash
podman pull registry.example.com:5001/lab/hello:v1

Explicit --authfile on a command line overrides REGISTRY_AUTH_FILE. Export the variable only in shells or unit files where every registry operation should share one file.


Write Docker-compatible auth with --compat-auth-file

When another tool must read the same credentials, update a Docker-format config instead of the default Podman auth file:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman login --compat-auth-file ~/.docker/config.json \
  --username labuser --password-stdin registry.example.com:5001

Sample output (tested as user podtest on the lab host):

output
Used:  /home/podtest/.docker/config.json
Login Succeeded!

The file uses the familiar auths object Docker tools expect. This article does not cover Docker credential management in depth — only the Podman flag that produces interoperable output.


Credential helpers

Instead of keeping plaintext-equivalent material in auth.json, Podman and containers-image can delegate to external Docker-compatible credential helpers such as pass or secretservice. Helper binaries are named like docker-credential-pass and docker-credential-secretservice.

Per-registry helper mapping can live in a Docker-compatible auth file:

json
{
  "credHelpers": {
    "registry.example.com:5001": "pass"
  }
}

Global helper preference can also appear in registries.conf:

toml
credential-helpers = [
  "pass",
  "containers-auth.json"
]

The reserved value containers-auth.json means fall back to normal auth-file lookup. Full registries.conf behavior belongs in Configure registries.conf.


Log in with a Podman secret

Avoid placing the password in the shell environment by storing it as a Podman secret first:

bash
printf '%s' "$REGISTRY_PASSWORD" | podman secret create registry-password -

Log in referencing that secret:

bash
podman login --username labuser --secret registry-password registry.example.com:5001

Sample output (tested as rootless user podtest on the lab host):

output
Used:  /run/user/1014/containers/auth.json
Login Succeeded!

Secret creation, rotation, and runtime mounting are covered in Manage Podman secrets. Here the secret only supplies the login password.


Authenticate to Docker Hub

Docker Hub’s registry host is docker.io:

bash
podman login docker.io

After login, pulls such as docker.io/library/alpine:latest can use your account’s authenticated quota instead of the lower anonymous pull allowance. This page does not reproduce full toomanyrequests diagnosis — see Fix Docker Hub rate limit when pulls fail with rate-limit errors despite correct credentials.


Authenticate to Quay

Red Hat Quay uses quay.io as the registry host:

bash
podman login quay.io

Use your Quay username and password, or an application token where Quay expects token-based login. Account creation and robot token setup live in Quay’s own documentation — this guide only covers the Podman client side.


Authenticate to a private registry

Name the host and port your organization publishes:

bash
podman login registry.example.com:5001

Pull a private image after login:

bash
podman pull registry.example.com:5001/lab/hello:v1

If login or pull fails with certificate trust errors, fix CA trust or registry TLS configuration — see Configure Podman for a private registry and Fix x509 certificate signed by unknown authority. Disabling TLS verification is a lab shortcut, not the default answer for production registries.


Check whether credentials already exist

Before logging in again, ask Podman which username is stored:

bash
podman login --get-login registry.example.com:5001

Sample output when logged in:

output
labuser

When nothing is stored, the same command exits with an error:

bash
podman login --get-login registry.example.com:5001

Sample output:

output
Error: not logged into registry.example.com:5001

CI scripts can use --get-login to skip redundant login steps when the auth file already contains the registry.


Log out of a registry

Remove credentials for one host:

bash
podman logout registry.example.com:5001

Sample output:

output
Removed login credentials for registry.example.com:5001

Confirm they are gone:

bash
podman login --get-login registry.example.com:5001

Sample output:

output
Error: not logged into registry.example.com:5001

Clear every registry entry in the active auth store:

bash
podman logout --all

Sample output:

output
Removed login credentials for all registries

Logout updates the local auth file or credential helper. It does not delete images you already pulled, and it does not revoke server-side tokens unless the registry provides that separately. Other users — including root versus your login user — keep their own stores.


Common login and auth errors

Symptom Likely cause Fix
unauthorized: authentication required wrong user, token, or registry host verify hostname, username, and password; confirm you logged in to the same host you pull from
Login succeeds but pull fails unauthorized different auth file or user context compare podman login --verbose with the pull command; align --authfile, REGISTRY_AUTH_FILE, and rootless vs rootful
Credentials gone after reboot default runtime auth.json log in with --authfile under $HOME/.config/containers/

CI authentication pattern

A reusable pattern for ephemeral runners:

bash
AUTHFILE="$RUNNER_TEMP/podman-auth.json"

printf '%s' "$REGISTRY_PASSWORD" | podman login \
  --authfile "$AUTHFILE" \
  --username "$REGISTRY_USER" \
  --password-stdin \
  "$REGISTRY"

podman pull --authfile "$AUTHFILE" "$REGISTRY/project/image:tag"

The same $AUTHFILE path serves login, pull, and push in one job. Let the CI environment delete $RUNNER_TEMP when the job finishes so the credential file does not linger on disk. Adapt variable names to GitHub Actions, GitLab CI, Jenkins, or any runner that exports secrets into the environment — this article stays provider-neutral.


References


Summary

podman login writes registry credentials to an auth file on disk so later pull and push commands can authenticate silently. The default location lives under the runtime directory and may not survive reboot, which surprises operators who expect a permanent login. Use --authfile or REGISTRY_AUTH_FILE when you need persistence, CI isolation, or a shared credential path across several commands.

Rootless and rootful Podman do not share the same default store — sudo podman pull after a user-level login often fails until you log in again as root or standardize on one auth file. For automation, pipe secrets with printf into --password-stdin and never pass -p on the command line. --get-login confirms which username is stored; podman logout removes local entries without deleting pulled images.

When authentication works but TLS or rate limits still block registry access, the fix lives in sibling guides for private registry trust, x509 errors, and Docker Hub quotas — not in repeating podman login with the wrong auth file.

Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)