,

Hugging Face Access Tokens and the hf CLI: Credentials Done Right (Hugging Face Series, Part 3)

A Hugging Face access token is a credential, not a convenience. Here is how to scope, store, rotate and use tokens with the new hf CLI, written for the infrastructure engineer who already runs registries and secret stores.

Hugging Face Series · Part 3 of 17

TL;DR

A Hugging Face access token is a credential, full stop. Treat it like a registry pull secret: scope it down, keep it in a secret manager, rotate it, and never bake it into an image or commit it. The CLI is now hf (the old huggingface-cli still works but warns you). Log in once with hf auth login. Use a read token on workstations and a fine-grained token for anything in CI or production. If your organization enforces a fine-grained policy, plain read and write tokens get a 403 against that org.

Who this is for: Platform and infrastructure engineers who already run registries, secret stores and CI, and now have to let people and pipelines pull models from Hugging Face without leaking credentials. If you have ever rotated a registry pull secret or scoped a service account, this maps straight onto skills you already have. No data-science background needed.

Here is the first thing that goes wrong on a fresh box. Someone tries to pull a gated or private model and gets this:

$ hf download meta-llama/Llama-3.1-8B-Instruct config.json
...
huggingface_hub.errors.GatedRepoError: 401 Client Error.
Cannot access gated repo for url https://huggingface.co/...
Access to model meta-llama/Llama-3.1-8B-Instruct is restricted.
You must be authenticated to access it.

That 401 is not a bug. It is access control doing its job. The fix is not a workaround, it is understanding that your Hugging Face account is an identity and the token is the credential that proves it. Get the credential model right once and the rest of this series stops fighting you. If you are still finding your way around the platform itself, Part 2 on navigating the Hub and reading model cards sets the scene; this part is about getting in the door safely.

Tested on: Python 3.11+, huggingface_hub 1.21 (the hf CLI). These are the versions this walkthrough was checked against in mid-2026. The Hugging Face stack moves quickly, so pin the version you install rather than pulling latest, and expect a major release to shift some defaults.

Your account is an identity, the token is the credential

Strip away the friendly branding and the Hub is a registry. It holds artifacts (model and dataset repos), it has public and private visibility, and it gates some artifacts behind an access request. To pull anything that is not fully public, you authenticate. The token is how you do that from a machine. It is the exact equivalent of the pull secret you already hand to a Kubernetes node so it can pull from your container registry. Same job, same risks, same rules.

You generate tokens on the Hub at Settings, then Access Tokens. Each token is a long string that starts with hf_. Anyone holding that string acts as you, within the token scope, until it is revoked. There is no second factor on a token once it exists. That single fact should shape every decision that follows: a token is a bearer credential, so the entire game is limiting what it can do and limiting how long a leaked one stays useful.

How a token authenticates a pullYou / CI jobneeds a modelAccess tokenscoped credentialHub repomodel / datasetpresentschecks scopereturns files only if the token scope allows it
The Hub validates the token and its scope on every request. No valid token, no access to private or gated repos.

Three token types, and which to use in production

Hugging Face gives you three kinds of token. The difference is exactly the difference between a broad service account and a least-privilege one, so you already have the instinct for this.

Token typeWhat it can doUse it forBlast radius if leaked
ReadPull any public, private or gated repo you can already read.Workstations, read-only CI, inference servers pulling weights.Attacker can read every private repo you can.
WriteEverything read can, plus push, create and edit repos you can write to.Publishing models or datasets, release pipelines.Attacker can overwrite or delete your models.
Fine-grainedExactly the repos and permissions you select, nothing else.Production, CI, anything shared or automated.Limited to the repos and scopes you picked.

My position is simple. People on laptops can use a read token because the convenience is worth it and the scope is read-only. Everything automated, everything shared, and everything that writes should be a fine-grained token pinned to the specific repos it touches. Hugging Face itself recommends fine-grained tokens for production for the same reason you scope an IAM role: when it leaks, and one eventually will, the damage is bounded to what you granted. The one place I would not reach for fine-grained is a quick throwaway on your own machine where the ceremony of picking repos is not worth it. Validate first by checking whether your org has a token policy, because that decides the question for you.

What this means if you run the platform: Treat the token table the way you treat registry robot accounts. A read token is a pull-only robot, a write token is push-capable and belongs only in a publish pipeline, and a fine-grained token is the per-project service account you should default to. Map each token you issue to one workload, give it one owner, and write down its expiry. A token with no owner and no expiry is the model-registry version of a shared admin password.

Installing and logging in with the hf CLI

The command line tool ships inside the huggingface_hub Python package, and it was renamed. What used to be huggingface-cli is now just hf, with a cleaner hf <resource> <action> grammar. The legacy name still works for now, but it prints a deprecation warning and points you at the new form. Install or upgrade, then check the version:

$ pip install -U huggingface_hub
$ hf version
huggingface_hub version: 1.0.0

All the authentication commands now live under hf auth:

$ hf auth login        # log in and store a token
$ hf auth whoami       # confirm which account you are
$ hf auth list         # list stored tokens / profiles
$ hf auth switch       # switch between stored profiles
$ hf auth logout       # remove the stored token

Run hf auth login on a workstation and it walks you through a browser flow: it prints a URL and a short code, you open the URL, enter the code, approve, and the token is retrieved and saved locally. After that, hf download and the Python libraries pick the token up automatically. The same 401 from the opener now succeeds, assuming you have also accepted the gated model terms on its repo page.

The interactive login flowhf auth loginrun commandopen URLenter codeapprovein browsertoken savedlocal cache
Interactive login is fine for humans. Pipelines should never see a browser; they get the token from the environment instead.

Where the token lives on disk

After login, the token is written to disk in plain text under your Hugging Face home directory, by default ~/.cache/huggingface/token. The location is controlled by the HF_HOME environment variable. The libraries also read a token straight from the HF_TOKEN environment variable, which takes priority and is the right path for servers and pipelines. Knowing both of these is the difference between treating a token as a magic setting and treating it as a secret with a known location on every box.

Gotcha: That plain-text token file is a secret at rest. On a shared build agent or a multi-user box, anyone who can read another user home directory, or restore a backup or a container layer, has the token. Do not run hf auth login on shared CI runners. Inject HF_TOKEN from your secret manager for that job only, so nothing lands on disk and the value disappears when the job ends.

Tokens in CI and automation

The interactive browser flow is useless to a pipeline. For automation, pass the token without prompting. The clean pattern is to read it from a secret store into the environment as HF_TOKEN and let the tooling pick it up. If you must call the login command non-interactively, it accepts the token directly:

# Preferred: let the libraries read HF_TOKEN from the env
export HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxxx
hf download my-org/internal-model --local-dir ./model

# Or log in explicitly without a browser prompt
hf auth login --token $HF_TOKEN

# Never do this: a token in plain command history / logs
hf auth login --token hf_realSecretPastedInline   # leaks into shell history
A token in a pipeline, with rotationSecret storeVault / CI secretCI job envHF_TOKEN sethfnon-interactiveHubrotation: issue new fine-grained token, update store, revoke old
The token never touches the repo or an image. It flows from the secret store into the job and is rotated on a schedule.

Worked example

A nightly job pulls an internal model into a build. In the CI settings you store a fine-grained token scoped to read only my-org/internal-model, exposed to the job as HF_TOKEN. The job step is just:

$ hf download my-org/internal-model --local-dir ./model
Fetching 7 files: 100%|...| 7/7
./model

Expected result: the files land in ./model and nothing secret is printed. Failure mode: if the token is missing or wrong you get 401 Client Error: Repository not found or you do not have access. If the token is valid but scoped to the wrong repo, you get a 403, not a 401, which is your tell that authentication worked but authorization did not.

Rotation, revocation, and org token policy

Tokens do not rotate themselves. You revoke and reissue them from the same Settings page where you created them, and a revoked token stops working immediately. The discipline is the same one you apply to any long-lived credential: issue with an owner and a purpose, rotate on a schedule, and revoke the moment someone leaves or a value might be exposed. Because fine-grained tokens are per-workload, you can rotate one pipeline without breaking the other twelve, which is the whole point of scoping them narrowly in the first place.

At the organization level there is a control worth knowing. An org can set a policy that requires fine-grained tokens. When that is on, a plain read or write token used against that org returns a 403, and a fine-grained token scoped to an org that requires approval sits in a pending state until an administrator approves it. That is governance you can enforce, and it parallels exactly what you already do with a registry: project-level access control, robot accounts, and approval before anything privileged is handed out. If you want the same controls applied to container images rather than models, the registry side of this is covered in the Harbor for Beginners guide, and the broader concept of credential scoping in AI systems sits in the GenAI series.

Disclaimer: Revoking or rotating a token takes effect immediately and will break any job still using the old value. Stage the new token in your secret store, roll it out, confirm the affected jobs are green, then revoke the old one. Test the change in a non-production project before you touch anything people depend on.

Multiple identities, profiles, and the whoami habit

Most platform engineers end up with more than one Hugging Face identity. There is your personal account, and there is the bot or service identity that owns the org tokens your pipelines use. Mixing them is how a model gets pushed under the wrong owner, or a personal token ends up doing production work it should never touch. The CLI handles this the way kubectl handles contexts. After you log in with more than one token, hf auth list shows the stored profiles and hf auth switch changes the active one, so you can keep a read-only personal login and a scoped org login side by side and pick the right one per task.

The habit that prevents the worst mistakes is cheap: run hf auth whoami before anything that writes. It prints the account the active token belongs to and the orgs it can act for. Treat it the same way you glance at your current kubectl context before running a destructive command. One extra line in a script, and you never push to the wrong namespace again.

$ hf auth whoami
your-bot-account
orgs: my-org

$ hf auth switch    # pick the profile you want
$ hf auth list      # see every stored token and which is active

On a server, you skip profiles entirely and let HF_TOKEN decide the identity for that one process. That is cleaner than stored profiles because the credential lives only for the life of the job and the identity is whatever you injected, with nothing left behind to switch away from later.

What I’d Do

Default to fine-grained tokens for everything that is not a human on a laptop. Why: when one leaks, the damage is bounded to the repos and permissions you granted, which is the only property that reliably saves you. When not: a quick read-only pull on your own machine does not need the ceremony, so a read token is fine there. What to validate first: check whether your org enforces a fine-grained policy, because if it does, the decision is made and your read and write tokens will start returning 403 anyway.

The mental shift that makes all of this easy is the one I opened with: a Hugging Face token is not a setting, it is a credential, and you already know how to run credentials. Scope them, store them in a secret manager, keep them out of images and shell history, rotate them, and put an owner on each one. Do that and the Hub behaves like a well-run registry instead of a place where secrets quietly leak. Next time you wire a model pull into a pipeline, set HF_TOKEN from your vault and confirm nothing lands on disk.

Hugging Face Series · Part 3 of 17
« Previous: Part 2  |  Hugging Face Guide  |  Next: Part 4

References

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading