Skip to main content

Authentication

The SDK sends a bearer token on every request. It gets that token in one of three ways: a Personal Access Token you pass or put in the environment (recommended), a username and password it exchanges for a session token (interactive use only), or a custom auth strategy object. Separately, data-API keys (dk_…) authenticate callers of your published APIs, not the SDK itself.

Personal Access Tokens​

A Personal Access Token (PAT) is an hf_… secret tied to your user. It carries your permissions, optionally narrowed, and is the right credential for scripts, notebooks and CI.

import os
from honeyframeapi import HoneyframeClient

client = HoneyframeClient(
"https://platform.your-domain.com",
token=os.environ["HONEYFRAME_TOKEN"],
)

A token passed this way is used as-is (TokenAuth). It is never refreshed: when it expires or is revoked, calls raise HoneyframeAuthError.

Minting and revoking from code​

pat = client.create_pat("nightly-export", expires_days=30)
print(pat["token"]) # the full hf_… secret — shown ONCE, store it now

for t in client.list_pats(): # metadata only, never the secret
print(t["id"], t["name"], t.get("expires_at"))

client.revoke_pat(pat_id) # an id from list_pats()

create_pat(name="", *, expires_days=90):

expires_daysResult
90 (default)Expires after 90 days.
1 … 730Expires after that many days. Values above 730 raise ValueError.
0Never expires. Opt in deliberately.
NoneSends no lifetime; the platform applies its own default (90 days).

The 90-day default and the 0–730 validation are 0.1.8+; 0.1.7 sends no lifetime unless you pass one.

Narrowing a token​

The platform can pin a PAT to one organization or project, make it read-only, and limit it to a list of capability scopes. create_pat does not take those arguments; mint a narrowed token from the UI, or post the documented body through client.request (0.1.8+):

pat = client.request("POST", "/api/auth/tokens", json={
"name": "dashboard-reader",
"expires_days": 30,
"scope_project_id": 7,
"read_only": True,
"scopes": ["dataset.*", "dashboard.view"],
})

The fields and their rules (a scope is a ceiling, never a grant; a narrowed token can only mint equally narrow tokens) are documented in Authentication → Personal Access Tokens.

Rotation​

Rotate a PAT by minting the replacement, deploying it wherever the old one is used, then revoking the old one with revoke_pat. Prefer short lifetimes for tokens that live in CI systems.

Username and password​

For interactive use, the client can sign in with your email and password. It exchanges them for a session token (8 hours by default) and signs in again automatically when a request returns 401 (LoginAuth).

import getpass
from honeyframeapi import HoneyframeClient

client = HoneyframeClient(
"https://platform.your-domain.com",
username="you@your-domain.com",
password=getpass.getpass(),
)

Prefer a PAT for anything unattended: a password grants everything your account can do, cannot be narrowed, and has to be stored somewhere the job can read it. Never write a password into a script.

Choosing the credential: precedence​

The client resolves its credential in this order and uses the first one found:

  1. an auth= object (a subclass of AuthBase);
  2. token=;
  3. username= together with password=;
  4. the HONEYFRAME_TOKEN environment variable;
  5. the HONEYFRAME_USERNAME and HONEYFRAME_PASSWORD environment variables.

If none is found, the constructor raises HoneyframeConfigError before any request is sent.

Environment variables​

HoneyframeClient(...) and HoneyframeClient.from_env() read the same variables; keyword arguments win over the environment.

VariableUsed for
HONEYFRAME_URLbase_url, when not passed.
HONEYFRAME_TOKENA PAT (or a session token you already hold).
HONEYFRAME_USERNAME, HONEYFRAME_PASSWORDPassword sign-in, when no token is set.
HONEYFRAME_PROJECT_IDThe default project (an integer).
HONEYFRAME_ALLOW_INSECURE_HTTPSet to 1 to allow a plain-http:// URL to a non-loopback host (see below).

The organization is not read from the environment. Pass org_id= to the constructor, call client.using(org_id=...), or use the CLI's -o/--org flag.

The older names HUB_API_BASE, HUB_USERNAME, HUB_PASSWORD and HUB_PROJECT_ID are still read as fallbacks, but using one emits a DeprecationWarning. Rename them to the HONEYFRAME_* names.

Keep tokens off the command line​

A token passed as a command-line argument is visible to other users in the process list and lands in shell history. Use the environment variable, a secret manager, or for the CLI --token-file PATH / --token - (read from stdin); see CLI.

Organization and project scope​

Every request carries X-Org-Id and X-Project-Id headers when the client has an org_id / project_id. Project handles always send their own project id, so one client can drive several projects:

client.using(org_id=42, project_id=7) # changes the client in place, returns it
sales = client.get_project(7)
finance = client.get_project(9) # its calls carry X-Project-Id: 9

A PAT pinned to an organization or project always acts there; the headers cannot point it elsewhere.

Connection security​

0.1.8+ (0.1.7 accepts any URL and keeps the httpx defaults):

  • HTTPS only. base_url must be https://. Plain http:// is accepted only for a loopback host (localhost, 127.0.0.1, ::1). For a trusted private network, pass allow_insecure_http=True or set HONEYFRAME_ALLOW_INSECURE_HTTP=1; the client still warns. Anything else raises HoneyframeConfigError before a request is sent, because the token (and a password) would travel unencrypted.
  • Certificate checks. verify=True (the default) uses the system trust store. Pass a CA bundle path (a file or a directory) for a private certificate authority, or an ssl.SSLContext. verify=False turns certificate checks off and emits a warning; prefer a CA bundle.
  • No redirects. The client never follows redirects, so the Authorization header cannot be forwarded to another host.
  • Encoded paths. Every value the SDK puts into a URL path (dataset names, keys, slugs, ids) is percent-encoded, so a name containing /, ?, # or .. cannot re-route a request.
  • No credentials in exceptions. An exception's response.request carries no Authorization, Cookie or X-API-Key header and no body; a failed sign-in keeps no response at all. repr() of the client and the auth objects masks secrets.
  • Private files. Files the SDK writes for you (exports, downloads, PDFs, notebooks) are created readable by your user only (mode 0600).
client = HoneyframeClient(
"https://platform.internal.example",
token=os.environ["HONEYFRAME_TOKEN"],
verify="/etc/ssl/certs/internal-ca.pem",
)

Data-API keys​

A dk_… key lets an outside system call one of your published data APIs or API services without a Honeyframe account. You mint keys with the SDK; the consumer sends the key in the X-API-Key header.

asset = client.get_asset(asset_id) # a published data_api asset
key = asset.create_api_key(name="partner-feed") # an ApiKey object
print(key.key) # the dk_… secret — shown ONCE

create_api_key defaults (0.1.8+; 0.1.7 keys never expire and allow critical):

ArgumentDefaultMeaning
expires_days900 = never expires.
masking_level"masked"Values come back masked.
sensitivity_max"medium"The highest column sensitivity tier the key may read.
rate_limit100The key's rate limit, stored and enforced by the platform.
allowed_columnsallRestrict the key to these columns.

The sensitivity tiers are low < medium < high < critical. With the default "medium", columns classified high (e-mail, phone, address, date of birth) and critical (national ID, record numbers) come back as [BLOCKED], while a medium column such as a person's name comes back masked. Pass a higher tier only when the consumer needs those columns; an unknown tier raises ValueError.

Manage keys with asset.list_api_keys() and asset.revoke_api_key(key_id). API services mint keys the same way through APIService.create_key; see API services.

Custom auth strategies​

auth= accepts any subclass of honeyframeapi.AuthBase. Implement token(http) to return the current bearer string and, optionally, refresh(http) to obtain a new one after a 401 (return True to have the client retry once, False to raise).

from honeyframeapi import AuthBase, HoneyframeClient

class VaultToken(AuthBase):
def __init__(self, read_secret):
self._read = read_secret

def token(self, http):
return self._read()

client = HoneyframeClient("https://platform.your-domain.com",
auth=VaultToken(lambda: "hf_from_your_secret_store"))

Verified against honeyframeapi 0.1.8.