# Authentication

> Pass your API key to the client: a credentials profile, environment variables, or keyword arguments.

Source: https://docs.stxapp.io/sdks/python/authentication/

The client needs your API key ID and its Ed25519 private key. Creating a key, how requests are signed, and why a signature fails are covered on [Authentication](/api/authentication/). The SDK signs every request and the WebSocket handshake for you, and signs again on every retry and reconnect.

There are three ways to hand the key to the client. When more than one is set, keyword arguments win over environment variables, and environment variables win over the profile. `STX`, `AsyncSTX` and `STXWebSocket` read them the same way.

## A credentials profile

Add a profile to `~/.stx/credentials`, one per exchange you use. Set `region` and `env` to the exchange the key belongs to; the values are on [Environments](/sdks/python/environments/).

```ini
[default]
region   = us
env      = demo
key_id   = your-key-id
key_file = ~/.stx/demo.pem

[my-demo]
region   = ontario
env      = demo
key_id   = another-key-id
key_file = ~/.stx/my-demo.pem
```

`STX()` with no profile reads `STX_PROFILE`, then the `[default]` section. Pick any other profile by name:

```python
from stx import STX

with STX(profile="my-demo") as client:
    print(client.me().user_id)
```

The other examples in these guides call `STX()` and `AsyncSTX()` with no arguments, so they use whichever profile or environment variables you have set. A profile can also set `host` (or `base_url`), `private_key` (instead of `key_file`) and `verify_tls`.

## Environment variables

```bash
export STX_REGION=us STX_ENV=demo
export STX_KEY_ID=your-key-id
export STX_PRIVATE_KEY=~/.stx/demo.pem   # a path, or the PEM text
```

```python
from stx import STX

with STX() as client:
    print(client.me().user_id)
```

`STX_HOST` (or `STX_BASE_URL`), `STX_PROFILE`, `STX_CREDENTIALS` (the path of the credentials file) and `STX_VERIFY_TLS` are also read.

## Keyword arguments

```python
import os

from stx import STX

with STX(
    region="us",
    env="demo",
    key_id=os.environ["MY_KEY_ID"],
    private_key=os.environ["MY_KEY_PEM"],  # a path or the PEM text
) as client:
    print(client.me().user_id)
```

An explicit `None` means none: `key_id=None` ignores `STX_KEY_ID` and the profile.

If the key lives in an HSM or KMS, pass `signer=` instead of `private_key`: a function that takes the message bytes and returns the raw 64-byte Ed25519 signature. The key never enters the process.

```python
import os

from stx import STX

def sign(message: bytes) -> bytes:
    return my_kms.sign(key="stx-trading", message=message)  # your KMS client

with STX(region="us", env="demo", key_id=os.environ["MY_KEY_ID"], signer=sign) as client:
    print(client.me().user_id)
```

## Check it works

```python
from stx import STX

with STX() as client:
    me = client.me()
    print(me.user_id, me.scope)  # scope: "read_only" or "read_write"
```

A bad key, or a machine clock that has drifted, raises `STXAuthenticationException`. A `read_only` key gets `STXForbiddenException` from the order methods.
