# Authentication and configuration

> Give the SDK client an API token, the API address and the organisation, from the environment or the constructor.

The client needs three things. Each one comes from the constructor or, if you leave it out, from an environment variable.

| Setting | TypeScript option | Python argument | Environment | Default |
|---|---|---|---|---|
| API token | `token` | `token=` | `OPENWAF_TOKEN` | none: calls fail with `no_token` |
| API address | `baseUrl` | `base_url=` | `OPENWAF_API_URL` | a built-in address that does not serve the API: always set this |
| Organisation id | `org` | `org=` | `OPENWAF_ORG` | the token's organisation, asked once with `GET /v1/orgs` |

Set the API address to `https://dash.openwaf.dev`; the SDK adds the `/v1/…` paths.

**TypeScript**

```ts
import { OpenWAF } from "./openwaf.ts";

// From the environment: OPENWAF_API_URL, OPENWAF_TOKEN, OPENWAF_ORG.
const owf = new OpenWAF();

// Or explicitly, for example in a browser extension or a worker without process.env.
const other = new OpenWAF({ baseUrl: "https://dash.openwaf.dev", token: myToken });
```
The TypeScript client reads the environment in Node.js, Bun and Deno. Elsewhere, pass the options. You can also pass your own `fetch` implementation in `fetch`.
**Python**

```py
from openwaf import OpenWAF

# From the environment: OPENWAF_API_URL, OPENWAF_TOKEN, OPENWAF_ORG.
owf = OpenWAF()

# Or explicitly, with a longer timeout (seconds, default 60).
other = OpenWAF(base_url="https://dash.openwaf.dev", token=my_token, timeout=120)
```


## The token

Create tokens in the dashboard under **API tokens**. A token has a role (**Read only**, **Tech**, **Admin**) and a scope (the whole organisation, one client or one zone); the API enforces both on every call, whatever SDK method you use. Give each script the narrowest token that works, and keep it in a secret store or an environment variable, never in code.

The client sends it as `Authorization: Bearer owf_…` on every call except the public ones (the origin TLS CA bundles).

## The organisation

Every method under `/v1/orgs/{org}` takes an optional `org`. Without it, the client uses its own: the `org` you configured, or the token's organisation, which it asks the API for once and then remembers. Call `orgId()` (TypeScript) or `org_id()` (Python) to get it.

## Zones are named by id

Zone methods take the zone's **id**, not its domain. Look it up once with `listZones` / `list_zones`:

**TypeScript**

```ts
const { items = [] } = await owf.listZones();
const zone = items.find((z) => z.name === "example.com");
```
**Python**

```py
zone = next(z for z in owf.list_zones()["items"] if z["name"] == "example.com")
```
