The Cargo Guide
Authentication and Secrets Handling
Why Authentication Matters in Cargo
Cargo needs authentication mainly for operations that interact with registries in privileged ways, especially publishing. The authentication story is not only about getting a token into Cargo once. It is also about where that token lives, how it is injected in automation, which registry it applies to, and how secrets are rotated or revoked over time.
A useful mental model is:
- authentication proves permission to a registry
- secret handling determines whether that permission stays safe
- Cargo supports several ways to provide credentials depending on the environment
The Basic cargo login Flow
The most familiar interactive authentication command is:
cargo loginFor an alternate registry, the registry is named explicitly:
cargo login --registry companyIn ordinary usage, Cargo reads the token from standard input and passes it to the configured credential provider for storage or handling. This makes cargo login a setup step rather than a per-command authentication pattern.
What cargo login Actually Does
cargo login does not itself publish anything. Its job is to run a credential provider so that later commands like cargo publish can authenticate automatically.
A useful mental model is:
cargo loginstores or hands off credentialscargo publishuses those credentials later
This separation is helpful because it allows both interactive local workflows and non-interactive automation workflows.
Token Storage with the Default Provider
With the built-in cargo:token credential provider, Cargo stores tokens in Cargo home, typically in a credentials file rather than in Cargo.toml.
A representative location is:
$CARGO_HOME/credentials.tomlAnd if CARGO_HOME is not overridden, that usually means a path under the user's home directory.
A useful mental model is:
- manifest files describe packages
- credentials files hold sensitive registry auth data
- these concerns should stay separate
Why Token Storage Location Matters
Where tokens are stored affects both security and portability.
If credentials live in a local credentials file, that may be convenient for interactive developer use. But CI or ephemeral environments often prefer environment-based injection instead of persistent local storage.
This is one reason Cargo supports more than one credential-handling pattern.
Environment Variable Token Injection
Cargo supports token injection through environment variables, which is especially useful in CI.
For crates.io:
export CARGO_REGISTRY_TOKEN=your_token_hereFor an alternate registry named company:
export CARGO_REGISTRIES_COMPANY_TOKEN=your_token_hereThis is often the safest practical pattern for automation because it avoids committing tokens to files in the repository.
Why Environment Injection Is CI-Friendly
Environment variable token injection is CI-friendly because the CI platform can provide secrets at runtime without requiring those secrets to be checked into source control or written manually into persistent config files.
A useful mental model is:
- local interactive use often tolerates stored credentials
- CI should usually prefer short-lived runtime injection
Per-Registry Credentials
Cargo supports credentials that differ by registry. This matters because a developer or organization may interact with crates.io, one or more internal registries, and partner registries in the same overall environment.
A package may publish to one registry:
[package]
name = "internal_sdk"
version = "0.1.0"
edition = "2024"
publish = ["company"]And the corresponding auth token can be scoped to that registry rather than treated as one universal Cargo token.
A Small Alternate Registry Example
Suppose you have this Cargo config:
[registries.company]
index = "sparse+https://packages.example.com/index/"And this manifest:
[package]
name = "internal_tool"
version = "0.1.0"
edition = "2024"
publish = ["company"]Then a registry-specific login flow can look like:
cargo login --registry company
cargo publish --registry companyThis makes the authentication boundary match the registry boundary.
Publishing with Tokens on the Command Line
Cargo also supports providing a token directly to commands like publish.
Example:
cargo publish --token YOUR_TOKEN_HEREFor automation, this is usually less desirable than environment-variable injection because command-line arguments may be more visible in shell history, process listings, or logs depending on the environment.
The Credential Provider Model
Cargo's modern authentication story is built around credential providers. A credential provider is the component Cargo uses to store, retrieve, or remove credentials for a registry.
A useful conceptual model is:
- Cargo knows it needs a token
- the credential provider decides how that token is stored or retrieved
This is why Cargo can support both the default plaintext-token model and platform-specific secure storage models.
Built-In Credential Providers
Cargo includes several built-in credential providers. The exact available set may evolve, but conceptually they fall into patterns like:
- a simple token-file provider
- operating-system-backed secure storage providers
- registry-specific or globally configured provider chains
This means secret handling is not hardcoded to one storage method.
The Default cargo:token Provider
The default cargo:token provider is conceptually simple: it stores tokens in Cargo's credentials file and can also cooperate with environment-variable token lookup when configured through Cargo's credential-provider machinery.
A useful mental model is:
cargo:tokenis the simplest provider model- it is convenient, but it does not provide encrypted-at-rest secret storage by itself
Global and Registry-Specific Credential Providers
Cargo can select credential providers either from a registry-specific setting or from a global configured provider list.
A useful conceptual model is:
- if a registry names a specific provider, that provider is used for that registry
- otherwise Cargo falls back to the configured global provider list
This allows teams to use different secret-handling strategies for different registries if needed.
Credential Providers as a Layered Auth System
The credential-provider model is useful because it separates registry usage from secret storage mechanics.
That means a package manifest can stay focused on package metadata and registry intent, while auth policy can live in Cargo configuration and environment setup.
This separation is especially valuable in organizations where secret-handling requirements differ between developer laptops, CI, and release machines.
CI-Safe Secret Patterns
A good CI-safe secrets pattern usually has three traits:
- the token is injected at runtime, not committed to the repository
- the token is scoped only to the registry and actions it actually needs
- logs and shell output avoid printing the token
A common pattern looks like this:
export CARGO_REGISTRY_TOKEN="$CRATES_IO_TOKEN"
cargo publishOr for an alternate registry:
export CARGO_REGISTRIES_COMPANY_TOKEN="$COMPANY_REGISTRY_TOKEN"
cargo publish --registry companyWhy Not to Commit Tokens
Registry tokens should not be committed to source control, added to checked-in .cargo/config.toml, or embedded in scripts that live in the repository.
This is not just a good habit. It is a core security boundary. A leaked token can allow unauthorized publishing or other registry operations until it is revoked.
A Local Development Pattern
A practical local developer workflow often looks like this:
cargo login
cargo publish --dry-run
cargo publishThis is convenient for interactive use because the token is stored once and reused. But for shared machines or highly sensitive environments, teams may prefer a stronger credential-provider policy than the default file-based approach.
A CI Publishing Pattern
A practical CI pattern often looks like this:
cargo publish --dry-run
export CARGO_REGISTRY_TOKEN="$CRATES_IO_TOKEN"
cargo publishOr for an internal registry:
export CARGO_REGISTRIES_COMPANY_TOKEN="$COMPANY_REGISTRY_TOKEN"
cargo publish --registry companyThe key idea is that the token arrives only for the job that needs it.
Dry Runs Before Authenticated Publish
Even in authenticated workflows, --dry-run is valuable.
Example:
cargo publish --dry-runThis lets you verify package contents and publish readiness before performing the irreversible registry upload step. It is often wise to separate packaging validation from the secret-bearing final publish step.
Rotation Practices
Token rotation means replacing an existing credential with a new one on a planned basis or after a possible exposure.
A good practical rotation mindset is:
- prefer scoped tokens over broad long-lived tokens when possible
- rotate tokens when staff or infrastructure access changes
- replace tokens after suspected leakage, not only after confirmed abuse
In Cargo workflows, rotation usually means updating the stored credential or the CI secret source rather than changing package manifests.
Revocation Practices
Revocation means invalidating a token so it can no longer be used.
A useful mental model is:
- rotation is replacing a live credential with a new one
- revocation is disabling the old credential so it stops working
If a token leaks, revocation should happen promptly, because a secret that remains valid is still usable by whoever obtained it.
cargo logout and Stored Credentials
Cargo also supports removing saved credentials with cargo logout.
Examples:
cargo logout
cargo logout --registry companyThis is useful when cleaning up local auth state, rotating developer credentials, or removing secrets from a machine that should no longer retain them.
A Conceptual Auth Lifecycle
A healthy Cargo authentication lifecycle often looks like this:
1. obtain token from the registry owner or website
2. store it through cargo login or inject it via environment
3. use it only for the required registry actions
4. rotate or revoke it when appropriate
5. remove local credentials when they are no longer neededThis lifecycle framing is often more useful than thinking only about the initial login command.
A Full Small Example
Suppose you maintain one public crate and one internal crate.
Public package workflow:
cargo login
cargo publish --dry-run
cargo publishInternal package workflow with alternate registry:
[package]
name = "internal_sdk"
version = "0.1.0"
edition = "2024"
publish = ["company"]Registry config:
[registries.company]
index = "sparse+https://packages.example.com/index/"CI publish flow:
export CARGO_REGISTRIES_COMPANY_TOKEN="$COMPANY_REGISTRY_TOKEN"
cargo publish --registry companyThis example shows how local interactive auth and CI auth can coexist while still following Cargo's registry model.
A Credentials File Example
A conceptual credentials file entry might look like this:
[registries.company]
token = "example_token"This illustrates the kind of data the default token-based provider manages. In practice, teams should treat this file as sensitive local state, not as ordinary project configuration.
Why Secrets Handling Is Part of Reproducibility Too
Secrets handling affects reproducibility in a practical sense because builds and publishes that depend on hidden local state are harder to reproduce across machines. Environment-based injection in CI and documented credential-provider setup make authenticated workflows easier to repeat safely.
A useful mental model is:
- hidden auth state increases operational mystery
- explicit, documented auth setup improves repeatability
Common Beginner Mistakes
Mistake 1: treating cargo login as the whole authentication story rather than one step in a larger secret-handling workflow.
Mistake 2: committing tokens to repository files or scripts.
Mistake 3: using one broad token everywhere instead of per-registry or scoped credentials.
Mistake 4: assuming local stored credentials are the best pattern for CI.
Mistake 5: forgetting to rotate or revoke tokens after exposure or role changes.
Mistake 6: not realizing that Cargo's credential-provider model allows stronger storage strategies than the default token-file approach.
Hands-On Exercise
Practice the difference between local interactive auth and CI-style auth in a safe dry-run mindset.
For local interactive use:
cargo login
cargo publish --dry-runFor an alternate registry:
cargo login --registry company
cargo publish --dry-run --registry companyFor CI-style injection:
export CARGO_REGISTRY_TOKEN="$CRATES_IO_TOKEN"
cargo publish --dry-runAnd for a private registry:
export CARGO_REGISTRIES_COMPANY_TOKEN="$COMPANY_REGISTRY_TOKEN"
cargo publish --dry-run --registry companyThen compare the secret-handling properties of each approach. This makes the difference between storage, injection, and operational safety concrete.
Mental Model Summary
A strong mental model for authentication and secrets handling in Cargo is:
cargo loginstores or hands off credentials for later authenticated operations- the default token provider is simple and convenient, but not the only credential model Cargo supports
- per-registry credentials matter in mixed public and private registry environments
- CI should usually prefer runtime environment-variable injection over persistent local storage
- credential providers separate registry usage from secret-storage mechanics
- rotation and revocation are part of normal credential hygiene, not emergency-only concerns
Once this model is stable, Cargo authentication becomes much easier to reason about as a deliberate operational system rather than a one-time login command.
