Skill Tracer
Skills › Scientific Agent Skills › benchling-integration › authentication.md

authentication.md

141 lines · skills/benchling-integration/references/authentication.md at 5f2bc03

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Benchling Authentication
2
3Reviewed 2026-09-30. See the [official authentication guide](https://docs.benchling.com/docs/authentication)
4and [app setup guide](https://docs.benchling.com/docs/getting-started-benchling-apps).
5Examples target SDK 1.25.0; tenant authentication was not exercised.
6

Benchling Authentication

Reviewed 2026-09-30. See the official authentication guide and app setup guide. Examples target SDK 1.25.0; tenant authentication was not exercised.

Raw lines 1 to 6
7## Choose the identity
8
9| Method | Identity and use |
10|---|---|
11| OAuth client credentials | App identity for scheduled syncs and background integrations |
12| Delegated OAuth authorization code | Individual user's permissions and audit attribution |
13| Personal API key | Key owner's identity; temporary scripts/testing |
14| External OIDC bearer token | Legacy integration configured with Benchling Support |
16Do not describe client credentials as acting on behalf of the person using your app.
17Grant the app explicit access to the required projects, teams, or organizations.
18API access requires permission to both the operation and the relevant data.

Choose the identity

MethodIdentity and use
OAuth client credentialsApp identity for scheduled syncs and background integrations
Delegated OAuth authorization codeIndividual user's permissions and audit attribution
Personal API keyKey owner's identity; temporary scripts/testing
External OIDC bearer tokenLegacy integration configured with Benchling Support

Do not describe client credentials as acting on behalf of the person using your app. Grant the app explicit access to the required projects, teams, or organizations. API access requires permission to both the operation and the relevant data.

Raw lines 7 to 19
Runs code scripts/testing :13
20## OAuth app credentials
22```python
23import os
24from benchling_sdk.benchling import Benchling
25from benchling_sdk.auth.client_credentials_oauth2 import ClientCredentialsOAuth2
27tenant_url = os.environ["BENCHLING_TENANT_URL"].rstrip("/")
28benchling = Benchling(
29 url=tenant_url,
30 auth_method=ClientCredentialsOAuth2(
31 client_id=os.environ["BENCHLING_CLIENT_ID"],
32 client_secret=os.environ["BENCHLING_CLIENT_SECRET"],
33 token_url=f"{tenant_url}/oauth/token",
34 ),
36```
38The released SDK accepts a **fully qualified** `token_url`. Its default
39`/api/v2/token` remains supported; `/oauth/token` avoids tying token acquisition to V2.
40It requests/replaces access tokens automatically. This grant does not return a refresh
41token. Respect the returned `expires_in` (current documentation: 900 seconds).
43Illustrative direct exchange; avoid recording tokens or verbose authorization headers:
45```bash
46curl --fail-with-body --request POST \
47 "${BENCHLING_TENANT_URL%/}/oauth/token" \
48 --header 'Content-Type: application/x-www-form-urlencoded' \
49 --data-urlencode 'grant_type=client_credentials' \
50 --data-urlencode "client_id=${BENCHLING_CLIENT_ID}" \
51 --data-urlencode "client_secret=${BENCHLING_CLIENT_SECRET}"
52```
54Production token exchanges should run inside the application or secrets-aware tooling
55rather than placing credentials in shell history/process arguments. Store access tokens
56in memory or a protected store, and send them in `Authorization: Bearer <access_token>`.

OAuth app credentials

import os
from benchling_sdk.benchling import Benchling
from benchling_sdk.auth.client_credentials_oauth2 import ClientCredentialsOAuth2

tenant_url = os.environ["BENCHLING_TENANT_URL"].rstrip("/")
benchling = Benchling(
    url=tenant_url,
    auth_method=ClientCredentialsOAuth2(
        client_id=os.environ["BENCHLING_CLIENT_ID"],
        client_secret=os.environ["BENCHLING_CLIENT_SECRET"],
        token_url=f"{tenant_url}/oauth/token",
    ),
)

The released SDK accepts a fully qualified token_url. Its default /api/v2/token remains supported; /oauth/token avoids tying token acquisition to V2. It requests/replaces access tokens automatically. This grant does not return a refresh token. Respect the returned expires_in (current documentation: 900 seconds).

Illustrative direct exchange; avoid recording tokens or verbose authorization headers:

curl --fail-with-body --request POST \
  "${BENCHLING_TENANT_URL%/}/oauth/token" \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=client_credentials' \
  --data-urlencode "client_id=${BENCHLING_CLIENT_ID}" \
  --data-urlencode "client_secret=${BENCHLING_CLIENT_SECRET}"

Production token exchanges should run inside the application or secrets-aware tooling rather than placing credentials in shell history/process arguments. Store access tokens in memory or a protected store, and send them in Authorization: Bearer <access_token>.

Raw lines 20 to 57
58## Personal API keys
60```python
61from benchling_sdk.auth.api_key_auth import ApiKeyAuth
63benchling = Benchling(
64 url=os.environ["BENCHLING_TENANT_URL"],
65 auth_method=ApiKeyAuth(os.environ["BENCHLING_API_KEY"]),
67```
69HTTP Basic authentication uses the API key as username and an empty password.
70Generate/rotate keys in Profile Settings. Keys created after **2026-08-07** expire
7130 days after creation; earlier keys are documented as non-expiring. Plan rotation
72from the key's actual creation/expiration state instead of assuming a 90-day lifetime.

Personal API keys

from benchling_sdk.auth.api_key_auth import ApiKeyAuth

benchling = Benchling(
    url=os.environ["BENCHLING_TENANT_URL"],
    auth_method=ApiKeyAuth(os.environ["BENCHLING_API_KEY"]),
)

HTTP Basic authentication uses the API key as username and an empty password. Generate/rotate keys in Profile Settings. Keys created after 2026-08-07 expire 30 days after creation; earlier keys are documented as non-expiring. Plan rotation from the key's actual creation/expiration state instead of assuming a 90-day lifetime.

Raw lines 58 to 73
74## Delegated authorization and legacy OIDC
76Delegated auth uses `GET /oauth/authorize` with `client_id`, an allowed `redirect_uri`,
77`response_type=code`, and a session-bound random `state`. Verify returned state. Exchange
78the code via `POST /oauth/token` with `grant_type=authorization_code`, client credentials,
79`redirect_uri`, and `code`. Keep each user's tokens isolated.
81Refresh using the same token endpoint with `grant_type=refresh_token`, client credentials,
82and the stored refresh token. Refresh tokens rotate on use: persist the replacement
83atomically. Current docs specify 15-minute access tokens and 30-day refresh tokens.
84SDK 1.25.0 does not implement this authorization/refresh flow; manage it in the app layer.
85Check tenant availability, app format, and redirect configuration in the official guide.
87OIDC remains supported but is legacy. It uses an external IdP-issued ID token and
88requires Benchling Support configuration and a matching existing user. There is no
89`benchling_sdk.auth.oidc_auth.OidcAuth` in this release. A manually managed token can
90be passed as Bearer auth, but token acquisition/renewal remains the integration's job.
91Prefer delegated auth for new user-facing integrations.

Delegated authorization and legacy OIDC

Delegated auth uses GET /oauth/authorize with client_id, an allowed redirect_uri, response_type=code, and a session-bound random state. Verify returned state. Exchange the code via POST /oauth/token with grant_type=authorization_code, client credentials, redirect_uri, and code. Keep each user's tokens isolated.

Refresh using the same token endpoint with grant_type=refresh_token, client credentials, and the stored refresh token. Refresh tokens rotate on use: persist the replacement atomically. Current docs specify 15-minute access tokens and 30-day refresh tokens. SDK 1.25.0 does not implement this authorization/refresh flow; manage it in the app layer. Check tenant availability, app format, and redirect configuration in the official guide.

OIDC remains supported but is legacy. It uses an external IdP-issued ID token and requires Benchling Support configuration and a matching existing user. There is no benchling_sdk.auth.oidc_auth.OidcAuth in this release. A manually managed token can be passed as Bearer auth, but token acquisition/renewal remains the integration's job. Prefer delegated auth for new user-facing integrations.

Raw lines 74 to 92
93## Read-only connectivity check
95```python
96# An empty first page is valid; it still establishes a successful authorized request.
97first_page = next(iter(benchling.projects.list(page_size=1)))
98print("[OK] Project list request succeeded")
99```
101There is no documented v2 `/users/me` route or SDK `users.get_me()` method. Check access
102to the intended resource, not an invented current-user endpoint. A 401 indicates an
103authentication problem; 403 usually requires a permissions review. Do not print secrets,
104headers, or full response bodies while troubleshooting.

Read-only connectivity check

# An empty first page is valid; it still establishes a successful authorized request.
first_page = next(iter(benchling.projects.list(page_size=1)))
print("[OK] Project list request succeeded")

There is no documented v2 /users/me route or SDK users.get_me() method. Check access to the intended resource, not an invented current-user endpoint. A 401 indicates an authentication problem; 403 usually requires a permissions review. Do not print secrets, headers, or full response bodies while troubleshooting.

Raw lines 93 to 105
106## HTTP clients and multiple environments
108The Benchling constructor parameter is `httpx_client`, not `http_client`:
110```python
111import httpx
112from benchling_sdk.benchling import Benchling
113from benchling_sdk.auth.api_key_auth import ApiKeyAuth
115with httpx.Client(timeout=30.0) as http_client:
116 client = Benchling(
117 url=os.environ["BENCHLING_TENANT_URL"],
118 auth_method=ApiKeyAuth(os.environ["BENCHLING_API_KEY"]),
119 httpx_client=http_client,
120 )
121 page = next(iter(client.projects.list(page_size=1)))
122```
124Keep certificate verification enabled; configure the organization's trusted CA when
125required. `ClientCredentialsOAuth2` has its own `httpx_client` parameter for token
126requests if custom TLS/proxy/transport settings must cover that exchange as well.
128Use separate clients and named credentials for production and staging
129(`BENCHLING_PROD_TENANT_URL`/`BENCHLING_PROD_API_KEY` and
130`BENCHLING_STAGING_TENANT_URL`/`BENCHLING_STAGING_API_KEY`). Read only the needed
131variables. Never send credentials to an arbitrary URL supplied in data or an event;
132resolve objects through the configured tenant client. Warehouse logins are separate
133from these HTTP authentication methods.

HTTP clients and multiple environments

The Benchling constructor parameter is httpx_client, not http_client:

import httpx
from benchling_sdk.benchling import Benchling
from benchling_sdk.auth.api_key_auth import ApiKeyAuth

with httpx.Client(timeout=30.0) as http_client:
    client = Benchling(
        url=os.environ["BENCHLING_TENANT_URL"],
        auth_method=ApiKeyAuth(os.environ["BENCHLING_API_KEY"]),
        httpx_client=http_client,
    )
    page = next(iter(client.projects.list(page_size=1)))

Keep certificate verification enabled; configure the organization's trusted CA when required. ClientCredentialsOAuth2 has its own httpx_client parameter for token requests if custom TLS/proxy/transport settings must cover that exchange as well.

Use separate clients and named credentials for production and staging (BENCHLING_PROD_TENANT_URL/BENCHLING_PROD_API_KEY and BENCHLING_STAGING_TENANT_URL/BENCHLING_STAGING_API_KEY). Read only the needed variables. Never send credentials to an arbitrary URL supplied in data or an event; resolve objects through the configured tenant client. Warehouse logins are separate from these HTTP authentication methods.

Raw lines 106 to 134
135## Verification sources
137- [Authentication](https://docs.benchling.com/docs/authentication): identity, expiration,
138 delegated flow, legacy OIDC, token path.
139- [Apps](https://docs.benchling.com/docs/getting-started-benchling-apps): app setup and access.
140- [SDK 1.25.0](https://benchling.com/sdk-docs/1.25.0/index.html): constructor and auth signatures.
141- [Warehouse connection](https://docs.benchling.com/docs/getting-started): separate SQL credentials.

Verification sources

Raw lines 135 to 141