馃攽 Authentication

Except for internal /in/v1 APIs, every API requires an Authorization: Bearer <token> HTTP header.

curl -H "Authorization: Bearer <token>" \
     https://<your-instance>/api/bkn-backend/v1/knowledge-networks

For deployments that use self-signed certificates, append -k (--insecure) to the curl and openbkn commands on this page. Skipping TLS verification is suitable only for development environments.

Choose one of these token acquisition methods:

MethodUse caseCoverage
CLI loginPersonal or interactive useAll service APIs
AppKey (bak_)Scripts and automationContext Loader only (retrieval and MCP, read-only)
Device authorization flowApplications acting on behalf of usersAll service APIs

BKN management REST APIs under /api/bkn-backend/v1 require an OAuth access token, including read-only requests such as GET /api/bkn-backend/v1/knowledge-networks. AppKeys are not supported by these APIs. A shared Bearer header format does not make the two credential types interchangeable.

Method 1 路 CLI login (recommended for personal use)

Sign in once with the openbkn CLI from bkn-sdk. Subsequent commands send and refresh the token automatically. Login uses the OAuth2 device authorization flow (RFC 8628).

# Browser login: prints a URL and user code for browser confirmation
# Add -k for a deployment with a self-signed certificate
openbkn auth login https://<your-instance>

# Headless or CI login: the CLI completes login and consent with credentials
openbkn auth login https://<your-instance> -u <account> -p <password> -k

Use the token subcommand when another tool or curl needs the raw token. An expired token is refreshed automatically.

openbkn auth token           # Print the current access token
openbkn auth status          # Show login status and current platform
openbkn auth whoami          # Show the current identity

# Use the token directly with curl
curl -H "Authorization: Bearer $(openbkn auth token)" \
     https://<your-instance>/api/bkn-backend/v1/knowledge-networks

Method 2 路 AppKey (for Context Loader retrieval/MCP automation)

Coverage: An AppKey is a long-lived credential for Context Loader retrieval and MCP APIs under /api/agent-retrieval/.... It supports read-only operations only. Write APIs intentionally reject AppKeys. Requests run as the issuer and have the same read scope as the issuer's OAuth token. Use an OAuth token for writes or other services.

The read-only scope above is the existing authentication-guide boundary. Execution-operation documentation also advertises AppKeys; that discrepancy needs a separate support-boundary decision. Until it is resolved, use OAuth for execution operations rather than treating MCP initialization success as evidence that all tools are supported.

Why can an active AppKey return HTTP 401?

Safe reporting active: true establishes that the key is valid and identifies its owner. Context Loader routes bak_ credentials to Safe for verification, whereas BKN management APIs validate OAuth tokens through Hydra. An active AppKey sent to a BKN management API can therefore return 401 / Public.Unauthorized before resource authorization. Changing the owner's roles or knowledge-network grants does not address this credential mismatch. Use the OAuth example above for management requests, including CLI and integration calls. Successful MCP initialize only establishes initialization; business tools still require their own authorization.

Create and manage an AppKey in the BKN Studio profile page or issue it through the API with an authenticated OAuth token. An AppKey cannot issue another AppKey. name is required; omitting expires_at uses a one-year lifetime.

# Issue a key with an authenticated OAuth token
curl -X POST https://<your-instance>/api/safe/v1/me/api-keys \
  -H "Authorization: Bearer $(openbkn auth token)" \
  -H "Content-Type: application/json" \
  -d '{"name":"my-key","expires_at":"2027-01-01T00:00:00Z"}'

# 201 response. The plaintext key appears only once; store it securely
# {"id":"...","key_id":"2882bb603277","name":"my-key",
#  "key":"bak_2882bb603277_BSxTZHTBiJXk4QoUBc0u17zSWua",
#  "masked":"bak_2882****SWua","expires_at":"...","enabled":true}

# Use the Bearer header with a Context Loader API. kn_id is required and can
# alternatively be sent in X-Kn-ID
curl -X POST https://<your-instance>/api/agent-retrieval/v1/kn/search_schema \
  -H "Authorization: Bearer bak_2882bb603277_BSxTZHTBiJXk4QoUBc0u17zSWua" \
  -H "Content-Type: application/json" \
  -d '{"query":"customer","kn_id":"<knowledge-network-id>"}'

CLI equivalent: openbkn appkey create --name my-key. Use it with openbkn --token bak_... context .... Management APIs: GET /api/safe/v1/me/api-keys lists keys, DELETE /api/safe/v1/me/api-keys/{id} revokes one, and POST /api/safe/v1/me/api-keys/{id}/regenerate rotates one.

Python example

import requests

BASE = "https://<your-instance>"
oauth_token = "<OAuth access token>"  # For example, openbkn auth token output

# Issue a key. The plaintext key appears only once; store it securely
resp = requests.post(
    f"{BASE}/api/safe/v1/me/api-keys",
    headers={"Authorization": f"Bearer {oauth_token}"},
    json={"name": "my-key"},          # Optional expires_at; defaults to one year
)
app_key = resp.json()["key"]          # bak_...

# Use a read-only Context Loader retrieval API. kn_id is required and can also
# be sent in X-Kn-ID
r = requests.post(
    f"{BASE}/api/agent-retrieval/v1/kn/search_schema",
    headers={"Authorization": f"Bearer {app_key}"},
    json={"query": "customer", "kn_id": "<knowledge-network-id>"},
)

For self-signed certificates, add verify=False to every request or configure it once on a requests.Session().

Method 3 路 Integrate login into an application

An application can call platform APIs without registering a client or involving an administrator. Every deployment includes the public openbkn-sdk client for the OAuth2 device authorization flow (RFC 8628). The application asks the user to sign in once in a browser, receives a token with that user's permissions, and then uses the refresh token for long-running access.

Step 1 路 Start device authorization

curl -X POST https://<your-instance>/oauth2/device/auth \
  -d "client_id=openbkn-sdk" -d "scope=openid offline"
# -> {"device_code":"ory_dc_...","user_code":"EKgw7AQa",
#     "verification_uri_complete":"https://<your-instance>/oauth2/device/verify?user_code=EKgw7AQa",
#     "expires_in":600,"interval":5}

Step 2 路 Confirm in the user's browser

Present verification_uri_complete as a link or QR code. The user opens it, confirms the device code, signs in, and grants consent.

Step 3 路 Poll for tokens

curl -X POST https://<your-instance>/oauth2/token \
  -d "grant_type=urn:ietf:params:oauth:grant-type:device_code" \
  -d "device_code=ory_dc_..." \
  -d "client_id=openbkn-sdk"
# Before login completes: {"error":"authorization_pending"}. Retry after the
# number of seconds in interval
# After completion -> {"access_token":"...","refresh_token":"...","expires_in":3600,
#                       "scope":"openid offline","token_type":"bearer"}

Step 4 路 Call APIs and refresh the token

# Call any service API with the signed-in user's permissions
curl -H "Authorization: Bearer <access_token>" \
     https://<your-instance>/api/bkn-backend/v1/knowledge-networks

# The access token lasts one hour. Refresh it without another login.
# Every refresh rotates refresh_token; always store the latest value
curl -X POST https://<your-instance>/oauth2/token \
  -d "grant_type=refresh_token" \
  -d "refresh_token=<refresh_token>" \
  -d "client_id=openbkn-sdk"

Complete Python example

import time
import requests

BASE = "https://<your-instance>"
CLIENT_ID = "openbkn-sdk"

s = requests.Session()
# s.verify = False   # Enable for a deployment with a self-signed certificate

# 1. Start device authorization
da = s.post(f"{BASE}/oauth2/device/auth",
            data={"client_id": CLIENT_ID, "scope": "openid offline"}).json()
print("Open this URL in a browser and sign in:", da["verification_uri_complete"])

# 2. Poll until the user completes login
while True:
    time.sleep(da.get("interval", 5))
    r = s.post(f"{BASE}/oauth2/token", data={
        "grant_type": "urn:ietf:params:oauth:grant-type:device_code",
        "device_code": da["device_code"],
        "client_id": CLIENT_ID,
    }).json()
    if "access_token" in r:
        tokens = r
        break
    if r.get("error") not in ("authorization_pending", "slow_down"):
        raise RuntimeError(r)

# 3. Call an API with the signed-in user's permissions
kns = s.get(f"{BASE}/api/bkn-backend/v1/knowledge-networks",
            headers={"Authorization": f"Bearer {tokens['access_token']}"}).json()

# 4. Refresh after the one-hour access-token lifetime without another login.
#    Refreshing rotates refresh_token, so overwrite the stored value
tokens = s.post(f"{BASE}/oauth2/token", data={
    "grant_type": "refresh_token",
    "refresh_token": tokens["refresh_token"],
    "client_id": CLIENT_ID,
}).json()
Tokens are user-delegated credentials. The application acts as the user who completed login, and its permissions change with that user's grants. Fully automated services should use a dedicated service account for browser login once, then continue with refresh tokens. If the refresh token expires through inactivity or revocation, the account must sign in again.

openbkn-sdk is a public client with no secret; PKCE and the device authorization flow provide its security. Any application can use it directly. A headless script that submits the login or consent pages must URL-decode the percent-encoded *_challenge query parameter before submitting the form to avoid double encoding.

The interactive login in Method 1 uses the Method 3 device flow internally; the CLI automates it.