# Generating SAS Tokens

## Prerequisites

To use Shared Access Signature tokens as authorization method, create a new HTTP device connector and select the device authentication **Shared Access Signature.**

<figure><img src="/files/UlkKKgUfOUTtnbKEUq2G" alt=""><figcaption></figcaption></figure>

Setup a new device with the data flow and copy the deviceId, the primary signing key and use it in the following code example to generate a token.

## Generating tokens

{% tabs %}
{% tab title="JavaScript" %}

```javascript
import crypto from "crypto";
import axios from "axios";

const generateSasToken = (
  signingKey,
  resourceUri,
  expiryInSeconds,
  deviceConnectorIdAudience,
  deviceIdAudience
) => {
  let query = `deviceConnectorIdAudience=${deviceConnectorIdAudience}\n`;
  if (deviceIdAudience !== null) {
    query += `deviceIdAudience=${deviceIdAudience}\n`;
  }
  query += `expiry=${expiryInSeconds}`;
  const encodedQuery = encodeURIComponent(query);

  let hmac = crypto.createHmac("sha256", Buffer.from(signingKey, "base64url"));
  hmac.update(encodedQuery);

  let signature = encodeURIComponent(hmac.digest("base64"));
  let token = `sig=${signature}&exp=${expiryInSeconds}&aud=${encodeURIComponent(
    resourceUri
  )}`;
  return Buffer.from(token).toString("base64");
};

// generate the token
const baseUrl = "https://data-gateway.akenza.io"
const expiry = Math.ceil(Date.now() / 1000 + 60 * 60 * 24); // 1d
const signingKey = "<primaryOrSecondarySigningKey>";
const deviceConnectorId = "<yourDeviceConnectorId>";
const deviceId = "<yourPhysicalDEviceId>";
const resourceUri = `https://akenza.io/device-connectors/${deviceConnectorId}/devices/${deviceId}`;
const token = generateSasToken(
    signingKey,
    resourceUri,
    expiry,
    deviceConnectorId,
    deviceId
  );
  
// send the uplink
const url = `${baseUrl}/v3/capture?deviceId=${deviceId}&topic=default`;
const options = {
    headers: {
      "Content-Type": "application/json",
      "x-access-signature": token,
    },
  };
const body = { param1: "value" };
const response = await axios.post(url, body, options);
```

{% endtab %}

{% tab title="Python" %}

```python
from base64 import b64encode, urlsafe_b64decode
from hashlib import sha256
from time import time
from urllib import parse
from hmac import HMAC
import os
import requests


def generate_sas_token(signing_key, resource_uri, expiry_in_seconds, device_connector_id, device_id):
    query = f"deviceConnectorIdAudience={device_connector_id}\n"
    if device_id:
        query += f"deviceIdAudience={device_id}\n"
    query += f"expiry={expiry_in_seconds}"
    query = parse.quote_plus(query).encode('utf-8')

    padded_signing_key = signing_key
    missing_padding = len(signing_key) % 4
    if missing_padding:
        padded_signing_key += '=' * (4 - missing_padding)
    padded_signing_key = urlsafe_b64decode(padded_signing_key)

    signature = b64encode(HMAC(padded_signing_key, query, sha256).digest()).decode("utf-8")
    encoded_signature = parse.quote_plus(signature.encode('utf-8'))
    token = f"sig={encoded_signature}&exp={expiry_in_seconds}&aud={parse.quote_plus(resource_uri)}"

    return b64encode(token.encode('utf-8')).decode("utf-8")


if __name__ == "__main__":
    base_url = "https://data-gateway.akenza.io"
    signing_key = "<primaryOrSecondarySigningKey>"
    device_id = "<yourPhysicalDEviceId>"
    device_connector_id = "<yourDeviceConnectorId>"
    expiry = round(time() + 60 * 60 * 24)
    resource_uri = f"https://akenza.io/device-connectors/{device_connector_id}/devices/{device_id}"
    token = generate_sas_token(signing_key, resource_uri, expiry, device_connector_id, device_id)

    headers = {
        'Content-Type': 'application/json',
        "x-access-signature": token
    }

    body = {
        "param1": "value"
    }

    response = requests.request("POST", f"{base_url}/v3/capture", headers=headers, json=body, timeout=10)
    response.raise_for_status()

    print("uplink sent")
```

{% endtab %}

{% tab title="Java" %}

```java
/**
 * Generates a SAS signature
 *
 * @param query the query to hash
 * @param key   the recommended key length is 32 bytes (256 bits)
 * @return the shared access signature
 */
public static String generateSignature(String query, String key) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
    String stringToSign = URLEncoder.encode(query, StandardCharsets.UTF_8);

    byte[] decodedKey = Base64.getUrlDecoder().decode(key);

    Mac sha256HMAC = Mac.getInstance("HmacSHA256");
    SecretKeySpec secretKey = new SecretKeySpec(decodedKey, "HmacSHA256");
    sha256HMAC.init(secretKey);
    Base64.Encoder encoder = Base64.getEncoder();

    String signature = new String(encoder.encode(
        sha256HMAC.doFinal(stringToSign.getBytes(StandardCharsets.UTF_8))), StandardCharsets.UTF_8);

    return URLEncoder.encode(signature, StandardCharsets.UTF_8);
}
```

{% endtab %}
{% endtabs %}


---

# 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.akenza.io/akenza.io/get-started/your-data-flow/device-connector/device-security/generating-sas-tokens.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.
