# Authentication

There are two methods of authenticating on a Websocket connection.

* Authenticate Per-Connection
* Authenticate Per-Message
* Authenticate One-Off Signature

## Authenticate Per-Connection

***

In order to send authenticated requests over the websocket connection, you will have to send an `auth` message.

```json
{
  "op": "auth",
  "data": {
    "key": `[Insert API key]`,
    "secret": `[Insert API secret]`
  }
}
```

```python
// Code Example

import os
import json
import asyncio
import websockets


async def main():
    connection = await websockets.connect("wss://ws-testnet.aevo.xyz")

    auth_msg = json.dumps({
        "op": "auth",
        "data": {
            "key": os.environ["API_KEY"],
            "secret": os.environ["API_SECRET"],
        }
    })
    await connection.send(auth_msg)
    await connection.recv()  # receive the outcome of authentication here

    msg = json.dumps({"op": "status"})

    await connection.send(msg)

    print(await connection.recv())


asyncio.run(main())
```

## Authenticate Per-Message

***

> 👍 Keep your API secret safe!
>
> Using signature is a safer method of authenticating since your API secret is not passed along in the requests. This prevents potential API secret leakage during transport.

To authenticate with this method, the following fields should be sent with the request:

<br>

```json
{
  "auth": {
    "timestamp": `[Insert UNIX timestamp in nanoseconds]`,
    "signature": `[Insert HMAC SHA256 signature]`,
    "key": `[Insert API key]`
  }
}
```

* `signature` is generated by performing `HMAC_SHA256(apiSecret, message)`.
* `message` is a concatenation of `apiKey,timestamp,ws,op,data` with comma separation.
* `timestamp` is UNIX timestamp in nanoseconds.
* `ws` is a string constant with the value "ws". *Must be lowercase*.
* `apiKey`, `timestamp`, `ws`, `op`, `data` are all required. If the request does not have any `data`, use a blank space for the value of `data`.<br>

**Example:**

* `apiKey`: `API_KEY`
* `timestamp`: 1673425955575713842
* `op`: "status"
* `ws`: "ws"
* `data`: ""

```
signature = HMAC_SHA256("API_KEY,1673425955575713842,ws,status,")
```

> 📘 Note!
>
> There is a trailing comma in the message, since the `data` of "status" `op` request is empty.

```python
# Code Example

import os
import time
import json
import hmac
import hashlib
import asyncio
import websockets

API_KEY = os.environ['API_KEY']
API_SECRET = os.environ['API_SECRET']


def get_auth_payload(op, data):
    timestamp = str(time.time_ns())

    # If the body is empty, it would look like:
    # concat = 'API_KEY,1673425955575713842,ws,status,'
    concat = f"{API_KEY},{timestamp},ws,{op},{data}".encode("utf-8")
    
    signature = hmac.new(API_SECRET.encode("utf-8"), concat,
                         hashlib.sha256).hexdigest()

    auth_payload = {
        "timestamp": timestamp,
        "signature": signature,
        "key": API_KEY,
    }

    return auth_payload


async def main():
    connection = await websockets.connect("wss://ws-testnet.aevo.xyz")

    msg = json.dumps({"op": "status", "auth": get_auth_payload("status", "")})

    await connection.send(msg)

    print(await connection.recv())


asyncio.run(main())
```

## Authenticate One-Off Message

In order to send authenticated requests over the websocket connection, you will have to send an `auth` message.

```json
{
  "op": "auth",
  "data": {
    "timestamp": `[Insert UNIX timestamp in nanoseconds]`,
    "signature": `[Insert HMAC SHA256 signature]`,
    "key": `[Insert API key]`
  }
}
```

* `signature` is generated by performing `HMAC_SHA256(apiSecret, message)`.
* `message` is a concatenation of `apiKey,timestamp,ws,op,data` with comma separation.
* `timestamp` is UNIX timestamp in nanoseconds.
* `ws` is a string constant with the value "ws". *Must be lowercase*.
* `apiKey`, `timestamp`, `ws`, `op`, `data` are all required. If the request does not have any `data`, use a blank space for the value of `data`.

**Example:**

* `apiKey`: `API_KEY`
* `timestamp`: 1673425955575713842
* `op`: "auth"
* `ws`: "ws"
* `data`: ""

<br>

```python
import hmac
import hashlib
import time
import json
import websockets
import asyncio


API_KEY = os.environ['API_KEY']
API_SECRET = os.environ['API_SECRET']
 

WS_URL = "wss://ws-testnet.aevo.xyz"

def ws_signature(key: str, secret: str, op: str, body: str) -> dict:
    """
    Build the auth payload for a single websocket message.

    The string that is HMAC-ed has the form
        "<key>,<timestamp>,ws,<op>,<body>"
    where
        timestamp = Unix-nano (int64)   e.g. 1673425955575713842
        body = raw JSON text (may be "")

    Returns the JSON dict you can embed under the "auth" field.
    """
    ts_ns = str(time.time_ns())

    concat = f"{key},{ts_ns},ws,{op},{body}"
    sig = hmac.new(secret.encode(), concat.encode(), hashlib.sha256).hexdigest()

    return {
        "timestamp": ts_ns,
        "signature": sig,
        "key": key,
    }

async def main():
    async with websockets.connect(WS_URL) as ws:
        op = "auth"
        body = ""

        msg = {
            "op": op,
            "data": ws_signature(API_KEY, API_SECRET, op, body),
        }

        await ws.send(json.dumps(msg))
        print(await ws.recv())

if __name__ == "__main__":
    asyncio.run(main())
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.aevo.xyz/api-reference/websocket-api/private-operations/websocket-authentication.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
