Skip to main content
blobhub.connect() needs two things: an API key, or none for anonymous reading, and the URL of the API. It resolves each one on its own, from the first source that has it. It reads the profiles that blobhub login stores and never writes them.

The order

hub.identity.source names the rung the key came from: argument, env, profile:<name> or anonymous. hub.identity.api_url is the URL in use, with any trailing / removed.
  • An empty value counts as unset. BLOBHUB_API_KEY="" falls through to the next rung.
  • There is no default organization. blobhub-cli’s BLOBHUB_ORG means nothing here: every SDK call names its blob in full, as an organization and a blob.

The profile file

Profiles live in ~/.blobhub/credentials.yaml, the file blobhub-cli and blobhub-worker share. Its shape is described under CLI configuration:
  • The SDK only reads it. It never creates the file, writes it, or changes its mode. Store a profile with blobhub login, from blobhub-cli, or blobhub-worker login.
  • It reads default, and each profile’s key and url. It ignores realtime_url and anything else.
  • Its place is fixed. It is always .blobhub/credentials.yaml in your home directory; no environment variable moves it.
  • It is read on every connect() except connect(anonymous=True), even when you pass api_key=. A file the SDK refuses fails connect(api_key=…) too, so fix the file rather than working around it.
  • A missing file is not an error. It contributes no profiles and no default.
When the file or a profile cannot be used, connect() raises blobhub.ConfigError: invalid_credentials_file covers a file that is not UTF-8 text, is not valid YAML, has no profiles map, holds a profile without a non-empty key and url, or has a default that is not a string. A named profile must exist even when a key is set. A profile is named by profile=, BLOBHUB_PROFILE or the file’s default:, and BLOBHUB_PROFILE=ci with BLOBHUB_API_KEY exported still raises profile_not_found if the file has no ci profile. The SDK refuses a loose file mode instead of repairing it, as blobhub-cli and blobhub-worker do.

Anonymous reading

With no key from any rung, the SDK reads as an anonymous visitor. It fetches a token from GET /auth/core/anonymous on the first request, keeps it in memory only, and renews it through Refresh Token when it is about to expire or is refused. connect(anonymous=True) asks for that on purpose:
  • It reads neither the profile file nor BLOBHUB_API_KEY nor BLOBHUB_PROFILE, so a stale, loose or foreign profile cannot break it. This is what the public notebooks use.
  • It still honours api_url= and BLOBHUB_API_URL.
  • Combined with api_key= or profile=, it raises ValueError.
Anonymous is a fallback, never a retry. A key the API refuses raises AuthError or PermissionDenied; the SDK never retries the request anonymously. The fallback runs only when no key resolved at all, and because that is silent, an AuthError or PermissionDenied raised for an anonymous request says in its message that the client is anonymous and where a key would come from.

Which credential reads what

An API key reaches what it was minted for (see API Key Authentication):
  • A user-scoped key acts as its user, capped at the key’s role: it reaches what the user reaches through ownership and membership, and reads public blobs in public organizations, as a signed-in user does.
  • An org-scoped key reaches blobs in its own organization.
  • A blob-scoped key reaches its own blob.
An org- or blob-scoped key reads no public content outside its scope: such a read raises PermissionDenied. To read public content elsewhere with one, such as the models in onnx-vision-models, connect a second client with connect(anonymous=True). One process can hold both clients.

In CI and containers

Export the key, and the URL if you are not using the default. No file is needed:
The key is never shown: not by hub.identity, not in a repr, not in an error message or a log line.

See also