Skip to main content

Overview

Mas Agua uses JWT (JSON Web Token) Bearer authentication for securing API endpoints. Tokens are obtained during login and must be included in the Authorization header of subsequent requests.

Authentication Flow

1

Login

User authenticates with email and Cooptech token to receive a JWT token
2

Store Token

Token is stored in cookies (web) or Tauri store (desktop app)
3

Include in Requests

Token is automatically included in the Authorization header for all API requests
4

Token Refresh

If token expires, user must re-authenticate

Token Storage

Tokens are stored differently depending on the platform:

Web Application (Cookies)

import Cookies from 'js-cookie';

// Store token
Cookies.set('token', jwtToken);

// Retrieve token
const token = Cookies.get('token');

Desktop Application (Tauri Store)

import { load } from '@tauri-apps/plugin-store';

const store = await load('store.json', { autoSave: false });

// Store token
await store.set('token', jwtToken);
await store.save();

// Retrieve token
const token = await store.get('token');
Refer to src/storage/cookies-store.js for the full implementation.

Login Endpoint

POST /loginCooptech

Authenticate a user and receive a JWT token.
email
string
required
User email address
tokenApp
string
required
Cooptech application token from user profile
schemaName
string
required
Database schema name for the client
influx_name
string
required
InfluxDB database name for time-series data
import { backend } from './utils/routes/app.routes';
import { request } from './utils/js/request';

const urlToken = backend['Mas Agua'] + '/loginCooptech';
const info = {
  email: 'user@example.com',
  tokenApp: 'user_token_from_cooptech',
  schemaName: 'client_schema',
  influx_name: 'client_influx_db'
};

const response = await request(urlToken, 'POST', info);
const token = response.data;
data
string
JWT token to be used for authenticated requests
Response
{
  "data": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
See implementation at src/modules/LoginApp/utils/login.js:7-23.

Making Authenticated Requests

Using the Request Utility

The request() utility automatically handles authentication:
import { request } from './utils/js/request';
import { backend } from './utils/routes/app.routes';

// Token is automatically retrieved from storage and included
const response = await request(
  `${backend['Mas Agua']}/getVarsInflux`,
  'GET'
);

Request Implementation

The request utility retrieves the token and includes it in the Authorization header:
import axios from 'axios';
import { storage } from '../../storage/storage';
import { getData } from '../../storage/cookies-store';

export const request = async (url, method, data = false) => {
  if (!url || !method) {
    throw new Error('URL o método no proporcionados');
  }
  
  // Retrieve token from cookies or local storage
  let token = await getData('token');
  if (!token) {
    token = storage.get('tokenCooptech');
  }
  
  try {
    const response = await axios({
      method,
      url,
      data: data || {},
      withCredentials: true,
      headers: {
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        'Authorization': 'Bearer ' + token,  // JWT token
      },
    });
    return response;
  } catch (error) {
    // Error handling...
    throw error;
  }
};

Authorization Header Format

All authenticated requests must include the JWT token in the Authorization header:
Authorization: Bearer <token>

Example Request Headers

GET /api/getVarsInflux HTTP/1.1
Host: masagua.cooptech.com.ar
Content-Type: application/json
Accept: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Public Endpoints

Some endpoints do not require authentication. Use the requestPublic() utility for these:
import { requestPublic } from './utils/js/request';

const response = await requestPublic(
  `${backend['Mas Agua']}/publicEndpoint`,
  'GET'
);
Public requests omit the Authorization header but still include credentials:
const response = await axios({
  method,
  url,
  data: data || {},
  withCredentials: true,
  headers: {
    'Content-Type': 'application/json',
    'Accept': 'application/json'
    // No Authorization header
  },
});

File Upload Authentication

File upload endpoints use special access credentials instead of JWT tokens:
import { requestFile } from './utils/js/request';

const formData = new FormData();
formData.append('file', fileBlob);

const response = await requestFile(
  `${backend.Archivos}/upload`,
  'POST',
  formData
);
File requests use custom access keys:
headers: {
  'accesskey': 'ZRJGodMUp2FzrLF9N9fg',
  'secretkey': 'KYTjiz1pC6AGM1U07mlDl2mUmDvUSNqnX6iM6DjL',
  'Content-Type': 'multipart/form-data',
}
Access keys shown above are from source code. In production, these should be stored as environment variables.
See src/utils/js/request.js:72-92 for the file upload implementation.

Token Expiration

When a token expires, the API will return a 401 Unauthorized response. The client should:
  1. Detect the 401 status code
  2. Clear the stored token
  3. Redirect the user to the login page
  4. Re-authenticate to obtain a new token
try {
  const response = await request(url, method, data);
} catch (error) {
  if (error.response?.status === 401) {
    // Token expired - redirect to login
    await removeData('token');
    window.location.href = '/login';
  }
}

Security Best Practices

  • Use httpOnly cookies when possible
  • Never expose tokens in URL parameters
  • Clear tokens on logout
  • Always verify JWT signature on the server
  • Check token expiration
  • Validate user permissions
  • All API requests should use HTTPS in production
  • Never send tokens over unencrypted connections
  • Consider implementing refresh tokens for better UX
  • Automatically refresh before expiration

Next Steps

Explore Endpoints

Learn about available API endpoints and how to use them