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
}| Claim | Description |
|---|---|
id | User's unique identifier |
email | User's email address |
role | User's role (ADMIN, OPERATOR, VIEWER) |
firstName | User's first name |
lastName | User's last name |
exp | Token expiration timestamp (Unix) |
Token Expiration
- Tokens expire 24 hours after issuance
- Use
auth.refreshTokento 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
| Role | Access Level |
|---|---|
ADMIN | Full access to all endpoints |
OPERATOR | Can manage sensors, view reports |
VIEWER | Read-only access |
Protected vs Public Endpoints
Public Endpoints (No Auth Required)
auth.login- Loginauth.logout- Logoutsystem.health- Health checksystem.getLicense- License infosystem.getSettings- System settingssystem.timezone.getTimezoneSettings- Timezone settings
Protected Endpoints (Auth Required)
auth.me- Get current userauth.refreshToken- Refresh tokensensors.create- Create sensorsensors.update- Update sensorsensors.delete- Delete sensorreports.getAnalytics- Get analyticsreports.getReports- Get reportsstorage.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
- Store tokens securely - Use httpOnly cookies or secure storage
- Refresh proactively - Refresh tokens before they expire
- Handle expiration - Redirect to login on 401 errors
- Use HTTPS - Always transmit tokens over HTTPS
- 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();