Skip to content

Authentication

This guide covers authentication mechanisms for the Smart City TVMS API.

Overview

The API uses JWT (JSON Web Tokens) for authentication. Tokens are issued upon successful login and must be included in subsequent requests.

Authentication Flow

┌──────────────┐         ┌──────────────┐         ┌──────────────┐
│    Client    │         │     API      │         │   Database   │
└──────┬───────┘         └──────┬───────┘         └──────┬───────┘
       │                        │                        │
       │  POST /trpc/auth.login │                        │
       │───────────────────────▶│                        │
       │  { email, password }   │                        │
       │                        │  Verify credentials    │
       │                        │───────────────────────▶│
       │                        │                        │
       │                        │◀───────────────────────│
       │                        │  User data             │
       │                        │                        │
       │◀───────────────────────│                        │
       │  { token, user }       │                        │
       │                        │                        │
       │  GET /trpc/sensors.getAll                       │
       │  Authorization: Bearer {token}                  │
       │───────────────────────▶│                        │
       │                        │  Verify JWT            │
       │                        │                        │
       │◀───────────────────────│                        │
       │  { sensors: [...] }    │                        │
       │                        │                        │

Obtaining a Token

Login Request

bash
curl -X POST "https://api.itms.solutions/trpc/auth.login" \
  -H "Content-Type: application/json" \
  -d '{
    "json": {
      "email": "admin@itms.solutions",
      "password": "Admin@123"
    }
  }'

Login Response

json
{
  "result": {
    "data": {
      "json": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6ImFkbWluLTAwMSIsImVtYWlsIjoiYWRtaW5AaXRtcy5zb2x1dGlvbnMiLCJyb2xlIjoiQURNSU4iLCJmaXJzdE5hbWUiOiJTeXN0ZW0iLCJsYXN0TmFtZSI6IkFkbWluaXN0cmF0b3IiLCJleHAiOjE3MzE3NjAwMDB9.xxxxx",
        "user": {
          "id": "admin-001",
          "email": "admin@itms.solutions",
          "firstName": "System",
          "lastName": "Administrator",
          "role": "ADMIN"
        }
      }
    }
  }
}

Using the Token

Include the token in the Authorization header for all protected requests:

bash
curl -X GET "https://api.itms.solutions/trpc/sensors.getAllSensors" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Token Structure

The JWT contains the following claims:

json
{
  "id": "admin-001",
  "email": "admin@itms.solutions",
  "role": "ADMIN",
  "firstName": "System",
  "lastName": "Administrator",
  "exp": 1731760000
}
ClaimDescription
idUser's unique identifier
emailUser's email address
roleUser's role (ADMIN, OPERATOR, VIEWER)
firstNameUser's first name
lastNameUser's last name
expToken expiration timestamp (Unix)

Token Expiration

  • Tokens expire 24 hours after issuance
  • Use auth.refreshToken to obtain a new token before expiration
  • Expired tokens return 401 Unauthorized

Refreshing a Token

bash
curl -X POST "https://api.itms.solutions/trpc/auth.refreshToken" \
  -H "Authorization: Bearer YOUR_CURRENT_TOKEN"

Response:

json
{
  "result": {
    "data": {
      "json": {
        "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "expiresIn": 86400,
        "user": {
          "id": "admin-001",
          "email": "admin@itms.solutions",
          "firstName": "System",
          "lastName": "Administrator",
          "role": "ADMIN"
        }
      }
    }
  }
}

User Roles

RoleAccess Level
ADMINFull access to all endpoints
OPERATORCan manage sensors, view reports
VIEWERRead-only access

Protected vs Public Endpoints

Public Endpoints (No Auth Required)

  • auth.login - Login
  • auth.logout - Logout
  • system.health - Health check
  • system.getLicense - License info
  • system.getSettings - System settings
  • system.timezone.getTimezoneSettings - Timezone settings

Protected Endpoints (Auth Required)

  • auth.me - Get current user
  • auth.refreshToken - Refresh token
  • sensors.create - Create sensor
  • sensors.update - Update sensor
  • sensors.delete - Delete sensor
  • reports.getAnalytics - Get analytics
  • reports.getReports - Get reports
  • storage.getStats - Storage stats

Error Handling

Invalid Credentials

json
{
  "error": {
    "json": {
      "message": "Invalid credentials",
      "code": -32001,
      "data": {
        "code": "UNAUTHORIZED",
        "httpStatus": 401
      }
    }
  }
}

Missing Token

json
{
  "error": {
    "json": {
      "message": "No token provided",
      "code": -32001,
      "data": {
        "code": "UNAUTHORIZED",
        "httpStatus": 401
      }
    }
  }
}

Expired Token

json
{
  "error": {
    "json": {
      "message": "Invalid or expired token",
      "code": -32001,
      "data": {
        "code": "UNAUTHORIZED",
        "httpStatus": 401
      }
    }
  }
}

Best Practices

  1. Store tokens securely - Use httpOnly cookies or secure storage
  2. Refresh proactively - Refresh tokens before they expire
  3. Handle expiration - Redirect to login on 401 errors
  4. Use HTTPS - Always transmit tokens over HTTPS
  5. Clear on logout - Remove tokens from storage on logout

Client Implementation Example

JavaScript/TypeScript

typescript
// Login and store token
async function login(email: string, password: string) {
  const response = await fetch('https://api.itms.solutions/trpc/auth.login', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ json: { email, password } }),
  });

  const data = await response.json();
  const token = data.result.data.json.token;

  localStorage.setItem('authToken', token);
  return data.result.data.json.user;
}

// Make authenticated request
async function fetchSensors() {
  const token = localStorage.getItem('authToken');

  const response = await fetch('https://api.itms.solutions/trpc/sensors.getAllSensors', {
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  });

  return response.json();
}

// Refresh token
async function refreshToken() {
  const token = localStorage.getItem('authToken');

  const response = await fetch('https://api.itms.solutions/trpc/auth.refreshToken', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${token}`,
    },
  });

  const data = await response.json();
  const newToken = data.result.data.json.token;

  localStorage.setItem('authToken', newToken);
  return newToken;
}

tRPC Client

typescript
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
import superjson from 'superjson';

const client = createTRPCProxyClient({
  transformer: superjson,
  links: [
    httpBatchLink({
      url: 'https://api.itms.solutions/trpc',
      headers() {
        const token = localStorage.getItem('authToken');
        return {
          authorization: token ? `Bearer ${token}` : '',
        };
      },
    }),
  ],
});

// Login
const { token, user } = await client.auth.login.mutate({
  email: 'admin@itms.solutions',
  password: 'Admin@123',
});

// Authenticated request
const sensors = await client.sensors.getAllSensors.query();

SCS Smart City - Traffic, Gateway, Camera, and NVR Platform