> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Credentials and Profiles

> Where blobhub.connect() finds its API key and URL, and how to read public content with none

`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`](/cli/auth#blobhub-login) stores and never writes them.

## The order

| Value | 1 | 2 | 3 | 4 |
| :- | :- | :- | :- | :- |
| profile name | `profile=` | `BLOBHUB_PROFILE` | the file's `default:` | none |
| API key | `api_key=` | `BLOBHUB_API_KEY` | the profile's `key` | an anonymous token |
| API URL | `api_url=` | `BLOBHUB_API_URL` | the profile's `url` | `https://api.blobhub.io/v1` |

```python theme={null}
import blobhub

hub = blobhub.connect()                          # the order above
hub = blobhub.connect(profile="staging")         # a named profile
hub = blobhub.connect(api_key=key)               # a key you hold, e.g. from a secret store
hub = blobhub.connect(anonymous=True)            # public content, no credential at all
```

`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](/cli/configuration#credentials-yaml):

```yaml theme={null}
default: work
profiles:
  work:
    key: <api key>
    url: https://api.blobhub.io/v1
```

* **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`:

| `error` | Cause | Fix |
| :- | :- | :- |
| `insecure_credentials_file` | A group or other permission bit is set. | `chmod 600 ~/.blobhub/credentials.yaml` |
| `invalid_credentials_file` | The file's content cannot be used; see below. | `blobhub login` |
| `unreadable_credentials_file` | It cannot be read, e.g. it belongs to another user. | Fix its owner. |
| `profile_not_found` | The profile named for this client is not in the file. | `blobhub login --profile <name>` |

`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`](/rest-api/auth/anonymous-signin) on the first request, keeps it in memory only, and
renews it through [Refresh Token](/rest-api/auth/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](/sdk/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](/rest-api/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:

```bash theme={null}
export BLOBHUB_API_KEY=...                       # from your CI's secret store
export BLOBHUB_API_URL=https://api.blobhub.io/v1 # optional
```

The key is never shown: not by `hub.identity`, not in a `repr`, not in an error message or a log line.

## See also

* [`blobhub login`](/cli/auth#blobhub-login) — stores a profile.
* [CLI configuration](/cli/configuration) — the credentials file and how blobhub-cli resolves a credential.
* [Service accounts](/general/service-accounts) — a key that is an account of its own, for automation.
* [Errors and retries](/sdk/errors) — `AuthError`, `PermissionDenied` and `ConfigError` among the rest.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.