> This page is for Developers.

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.iot.telia.lt/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.iot.telia.lt/_mcp/server.

> Understand JSON Web Token (JWT) structure, decode and inspect tokens, and handle token expiration in API requests.

JSON Web Tokens (JWTs) are signed JSON objects that authenticate your API requests.
After you authenticate with [application tokens](/developers/auth/application-tokens) (or, temporarily, [user credentials](/developers/auth/user-credentials) for specific cross-Workspace APIs), the API returns a JWT called `auth_token`.

## Use the auth token

Include the `auth_token` in the `Authorization` header of every API request using the Bearer scheme:

```http
Authorization: Bearer YOUR_AUTH_TOKEN
```

The following example shows how to include the `auth_token` when creating a new user:

### Request

POST [https://iot.telia.lt/api/v1/user](https://iot.telia.lt/api/v1/user)

```curl
curl -X POST https://iot.telia.lt/api/v1/user \
     -H "Authorization: Bearer <token>" \
     -H "Content-Type: application/json" \
     -d '{
  "username": "eabbot@flatland.org",
  "name": "Edwin Abbott",
  "organisation": {
    "id": 123
  },
  "roles": [
    {
      "id": 1
    },
    {
      "id": 2
    }
  ]
}'
```

```python
import requests

url = "https://iot.telia.lt/api/v1/user"

payload = {
    "username": "eabbot@flatland.org",
    "name": "Edwin Abbott",
    "organisation": { "id": 123 },
    "roles": [{ "id": 1 }, { "id": 2 }]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}

response = requests.post(url, json=payload, headers=headers)

print(response.json())
```

```javascript
const url = 'https://iot.telia.lt/api/v1/user';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"username":"eabbot@flatland.org","name":"Edwin Abbott","organisation":{"id":123},"roles":[{"id":1},{"id":2}]}'
};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"strings"
	"net/http"
	"io"
)

func main() {

	url := "https://iot.telia.lt/api/v1/user"

	payload := strings.NewReader("{\n  \"username\": \"eabbot@flatland.org\",\n  \"name\": \"Edwin Abbott\",\n  \"organisation\": {\n    \"id\": 123\n  },\n  \"roles\": [\n    {\n      \"id\": 1\n    },\n    {\n      \"id\": 2\n    }\n  ]\n}")

	req, _ := http.NewRequest("POST", url, payload)

	req.Header.Add("Authorization", "Bearer <token>")
	req.Header.Add("Content-Type", "application/json")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://iot.telia.lt/api/v1/user")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"username\": \"eabbot@flatland.org\",\n  \"name\": \"Edwin Abbott\",\n  \"organisation\": {\n    \"id\": 123\n  },\n  \"roles\": [\n    {\n      \"id\": 1\n    },\n    {\n      \"id\": 2\n    }\n  ]\n}"

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.post("https://iot.telia.lt/api/v1/user")
  .header("Authorization", "Bearer <token>")
  .header("Content-Type", "application/json")
  .body("{\n  \"username\": \"eabbot@flatland.org\",\n  \"name\": \"Edwin Abbott\",\n  \"organisation\": {\n    \"id\": 123\n  },\n  \"roles\": [\n    {\n      \"id\": 1\n    },\n    {\n      \"id\": 2\n    }\n  ]\n}")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('POST', 'https://iot.telia.lt/api/v1/user', [
  'body' => '{
  "username": "eabbot@flatland.org",
  "name": "Edwin Abbott",
  "organisation": {
    "id": 123
  },
  "roles": [
    {
      "id": 1
    },
    {
      "id": 2
    }
  ]
}',
  'headers' => [
    'Authorization' => 'Bearer <token>',
    'Content-Type' => 'application/json',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://iot.telia.lt/api/v1/user");
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"username\": \"eabbot@flatland.org\",\n  \"name\": \"Edwin Abbott\",\n  \"organisation\": {\n    \"id\": 123\n  },\n  \"roles\": [\n    {\n      \"id\": 1\n    },\n    {\n      \"id\": 2\n    }\n  ]\n}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = [
  "Authorization": "Bearer <token>",
  "Content-Type": "application/json"
]
let parameters = [
  "username": "eabbot@flatland.org",
  "name": "Edwin Abbott",
  "organisation": ["id": 123],
  "roles": [["id": 1], ["id": 2]]
] as [String : Any]

let postData = JSONSerialization.data(withJSONObject: parameters, options: [])

let request = NSMutableURLRequest(url: NSURL(string: "https://iot.telia.lt/api/v1/user")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "POST"
request.allHTTPHeaderFields = headers
request.httpBody = postData as Data

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```

> **Note**
>
> Don't confuse `auth_token` with `application_token`.
> Application tokens are long-lived credentials you use to *obtain* an auth token.
> The auth token is what you include in API request headers.

## JWT structure

A JWT consists of three parts separated by dots: `header.payload.signature`

| Part          | Description                                         |
| ------------- | --------------------------------------------------- |
| **Header**    | Contains the token type (JWT) and signing algorithm |
| **Payload**   | Contains claims about the user and token metadata   |
| **Signature** | Verifies the token hasn't been tampered with        |

## Decode and inspect tokens

To inspect a JWT's contents, use [jwt.io](https://jwt.io) or decode it in your application.

> **Warning**
>
> Never share your auth tokens publicly.
> If you use jwt.io, be aware that the token contents are visible and could be logged.
> For production debugging, decode tokens locally.

Example using Python:

```python
import base64
import json

def decode_jwt(token):
    parts = token.split('.')
    payload = parts[1]
    # Add padding if needed
    payload += '=' * (4 - len(payload) % 4)
    decoded = base64.urlsafe_b64decode(payload)
    return json.loads(decoded)
```

## Handle expired tokens

When your `auth_token` expires, API requests return a `401 Unauthorized` error.
To handle this:

1. Catch the `401` response in your application
2. Re-authenticate to get a new token (using your [application token](/developers/auth/application-tokens) or [refresh token](/developers/auth/user-credentials#refresh-your-auth-token))
3. Retry the failed request with the new token

> **Tip**
>
> To avoid failed requests, track token expiration and refresh proactively.
> For user credentials, the `auth_token` expires after 240 minutes.