> For the complete documentation index, see [llms.txt](https://docs.akenza.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akenza.io/device-management/your-data-flow/device-connector/device-security/generating-sas-tokens.md).

# 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="https://2165942204-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MMKXTFIN5ZlLOjBlfC4%2Fuploads%2Fgit-blob-38b4dbfc82ddacb93773420369e116aa4bfb668f%2Fimage%20(517).png?alt=media" 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
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

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

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.akenza.io/device-management/your-data-flow/device-connector/device-security/generating-sas-tokens.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
