Skip to content
OpenAppPhysical access, fully managed
Login

Authentication

The SDK authenticates via OpenApp API keys. Tokens have the shape {origin}_openapp_{secret}, where {origin} is a bare origin (no path). The SDK sends the token in the X-API-Key header and uses {origin}/api/v1 as the API root unless you override it.

  1. Log in to the OpenApp dashboard.
  2. Go to Settings → API keys.
  3. Click Add, pick Organization for new keys, give it a name, pick an expiry.
  4. Copy the token — it is shown only once.

You need the api_keys:create role in the target organization.

from openapp_sdk import Client
client = Client.connect(api_key="https://openapp.house_openapp_YOUR_SECRET")

Client.connect / AsyncClient.connect parse the token, configure the HTTP client, and return a ready-to-use client. No additional setup.

If you are pointing at a staging / on-prem backend that does not match the token’s embedded origin, pass base_url explicitly. It is the full API root, including /api/v1:

client = Client.connect(
api_key="...",
base_url="https://staging.openapp.house/api/v1",
)

This is primarily useful during development or when testing through a proxy.

The SDK does not read environment variables by default — we prefer explicit configuration in code. If you want env-var driven setup, wrap it yourself:

import os
from openapp_sdk import Client
def open_client() -> Client:
token = os.environ["OPENAPP_API_KEY"]
return Client.connect(api_key=token)

API keys are immutable; to rotate, mint a new key and delete the old one.

# Create a replacement.
new_key = client.api_keys.create(name="prod-ci", expires_in_days=90)
# Deploy new_key["token"] to your secret store, then:
client.api_keys.delete(new_key["id"]) # only once new_key is in use

Pluggable token providers for unattended rotation in long-running services are a planned extension point; for now, the Python SDK treats the token as fixed per client.

  • Never logs the token. repr(ApiKey(...)) elides the secret.
  • Never sends the token as a query string.
  • Never caches it to disk.
SymptomLikely cause
AuthError: invalid token formatThe token is missing the _openapp_ separator. Re-copy from the dashboard.
ConfigError: base URL could not be derivedToken prefix is not a bare origin (not a valid URL, or it contains a path); re-copy the token or override with base_url=....
AuthError: unauthorized (401)Token revoked, expired, or pointing at the wrong backend.