Skip to main content
The Tandex Electronics API uses JSON Web Tokens (JWT) for authentication. This guide explains how to authenticate, use tokens, and handle common authentication scenarios.

How JWT Authentication Works

The API implements a two-tier routing system with JWT middleware protection:
  1. Public Routes - No authentication required
  2. Secured Routes - Require valid JWT token in Authorization header
All routes under /secured/* are protected by JWT middleware that validates tokens before allowing access to the endpoint.

JWT Middleware Implementation

The authentication middleware is implemented in routes/setup/routes_setup.js:9-27:
routes/setup/routes_setup.js
var secureapp = express.Router()
app.use('/secured', secureapp)
secureapp.use((req,res,next) => {
    const bearer = req.headers['authorization']
    if(bearer){
        jwt.verify(bearer,process.env.JWT_SECRET, function(err,decode){
            if(err){
                res.status(401).json({
                    msg:'Token_invalido'
                })
            }else{
                next()
            }
        })
    }else{
        res.status(401).json({
            msg:'Sin autorización'
        })
    }
})
This middleware:
  • Extracts the token from the Authorization header
  • Verifies the token against the JWT secret
  • Returns 401 if token is missing, invalid, or expired
  • Allows the request to proceed if token is valid

Login Process

Authentication Endpoint

POST /login Authenticate a user and receive a JWT token.

Request Format

curl -X POST http://localhost:8080/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "admin@example.com",
    "password": "your_password"
  }'

Authentication Flow

The login process is implemented in routes/setup/servicios/cliente.js:54-90:
1

User lookup

The API queries the database for the user by email:
dbconn.query('SELECT * FROM heroku_1a378f873641606.usuarios where correo= ?',[email])
2

Password verification

The submitted password is compared with the stored bcrypt hash:
const encriptada = rows[0].password
bcrypt.compare(password, encriptada, function(err, result) {
    if(result == true){
        // Password is correct, generate token
    }
})
3

JWT token generation

If authentication succeeds, a JWT token is generated with 1-hour expiration:
routes/setup/servicios/cliente.js:68-70
const accessToken = jwt.sign(
    { userId: rows[0].correo, nombre: rows[0].password },
    process.env.JWT_SECRET,
    { expiresIn: "1h" }
);
4

Token response

The token is returned to the client:
res.status(200).json({
    msg:'Autenticación correcta',
    token: accessToken
})

Response Examples

{
  "msg": "Autenticación correcta",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJhZG1pbkBleGFtcGxlLmNvbSIsIm5vbWJyZSI6IiQyYiQxMCRhYmNkZWYuLi4iLCJpYXQiOjE2MzA1MDAwMDAsImV4cCI6MTYzMDUwMzYwMH0.signature"
}

Token Format and Expiration

Token Structure

JWT tokens consist of three parts separated by dots:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJhZG1pbkBleGFtcGxlLmNvbSIsImlhdCI6MTYzMDUwMDAwMCwiZXhwIjoxNjMwNTAzNjAwfQ.signature
  • Header - Algorithm and token type
  • Payload - User data (userId, nombre)
  • Signature - Verification signature using JWT_SECRET

Token Payload

The token payload contains:
{
  "userId": "admin@example.com",
  "nombre": "$2b$10$...",
  "iat": 1630500000,
  "exp": 1630503600
}
  • userId - User’s email address
  • nome - User’s hashed password (used as additional identifier)
  • iat - Issued at timestamp
  • exp - Expiration timestamp

Token Expiration

Tokens expire after 1 hour from the time of issuance. After expiration, you must authenticate again to receive a new token.
The expiration is configured in cliente.js:69:
expiresIn: "1h"

Using Tokens in Requests

Authorization Header Format

To access secured endpoints, include the JWT token in the Authorization header of your requests:
curl http://localhost:8080/secured/ENDPOINT \
  -H "Authorization: YOUR_JWT_TOKEN"
Unlike Bearer token schemes, this API expects the raw token value directly in the Authorization header (without “Bearer” prefix).

Example: Get Products

curl http://localhost:8080/secured/getProductos \
  -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiJhZG1pbkBleGFtcGxlLmNvbSIsImlhdCI6MTYzMDUwMDAwMCwiZXhwIjoxNjMwNTAzNjAwfQ.signature"

Example: Update Product

curl -X POST http://localhost:8080/secured/update_products \
  -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "clave": "PROD001",
    "descripcion": "Updated description",
    "precio": "399.99"
  }'

Example: Upload to WooCommerce

curl -X POST http://localhost:8080/secured/post_products \
  -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -H "user: admin@example.com" \
  -d '[{
    "claveProducto": "PROD001",
    "descripcionP": "Electronic Component",
    "precio": "299.99"
  }]'
Some endpoints like post_products also require a user header containing the authenticated user’s email for audit logging purposes.

Protected Endpoints

The following endpoints require JWT authentication (defined in routes_setup.js:39-56):

Product Management

  • POST /secured/update_products - Update product information
  • POST /secured/deleteProducto - Delete a product
  • POST /secured/add_producto - Add new product
  • GET /secured/getProductos - List all products
  • GET /secured/getProductosPublicados - List published products

User Management

  • POST /secured/upload_user - Create new user
  • POST /secured/update_user - Update user information
  • POST /secured/delete_user - Delete user
  • GET /secured/getUsers - List all users

WooCommerce Integration

  • POST /secured/post_products - Publish products to WooCommerce

Audit Log

  • GET /secured/getBitacora - View activity log

Error Handling

Missing Token

Request without Authorization header:
curl http://localhost:8080/secured/getProductos
Response (401):
{
  "msg": "Sin autorización"
}
This error is returned by the middleware when no Authorization header is present (routes_setup.js:23-25).

Invalid Token

Request with malformed or tampered token:
curl http://localhost:8080/secured/getProductos \
  -H "Authorization: invalid.token.here"
Response (401):
{
  "msg": "Token_invalido"
}
This error occurs when:
  • Token signature is invalid
  • Token format is malformed
  • Token was signed with different JWT_SECRET

Expired Token

Request with expired token (>1 hour old):
curl http://localhost:8080/secured/getProductos \
  -H "Authorization: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...[expired]"
Response (401):
{
  "msg": "Token_invalido"
}
Expired tokens return the same error message as invalid tokens. When you receive “Token_invalido”, first try re-authenticating to get a fresh token.

Security Best Practices

Keep JWT_SECRET Secure

The JWT_SECRET in config/default.json is critical for token security. Never commit it to version control or expose it publicly.

Use HTTPS in Production

Always use HTTPS in production to prevent token interception. Tokens sent over HTTP can be captured and reused.

Implement Token Refresh

Consider implementing a token refresh mechanism for better user experience, as tokens currently expire after 1 hour.

Store Tokens Securely

On the client side, store tokens securely (e.g., httpOnly cookies or secure storage). Avoid localStorage for sensitive applications.

Password Security

User passwords are secured using bcrypt hashing:

During Registration

routes/setup/servicios/cliente.js:280
bcrypt.hash(password, 10, function(err, data){ 
    if(data){
        dbconn.query('INSERT INTO usuarios (correo, password, ...) VALUES (?,?,...)'
            [email, data, ...])
    }
})
Passwords are hashed with a salt rounds value of 10 before storage.

During Login

routes/setup/servicios/cliente.js:65
bcrypt.compare(password, encriptada, function(err, result) {
    if(result == true){
        // Generate JWT token
    }
});
Plaintext passwords are never stored or logged. All comparisons use bcrypt’s secure comparison function.

Complete Authentication Example

Here’s a complete workflow for authenticating and making requests:
1

Step 1: Login

curl -X POST http://localhost:8080/login \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@example.com", "password": "mypassword"}'
Save the returned token.
2

Step 2: Store Token

export TOKEN="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
3

Step 3: Make Authenticated Requests

curl http://localhost:8080/secured/getProductos \
  -H "Authorization: $TOKEN"
4

Step 4: Handle Expiration

If you receive a 401 error after 1 hour, re-authenticate:
curl -X POST http://localhost:8080/login \
  -H "Content-Type: application/json" \
  -d '{"email": "admin@example.com", "password": "mypassword"}'
Update your stored token with the new one.

Next Steps

Now that you understand authentication, explore:
  • API endpoint documentation for available operations
  • User management endpoints for creating and managing accounts
  • WooCommerce integration for publishing products

API Reference

Explore all available endpoints

User Management

Learn about user roles and permissions

Build docs developers (and LLMs) love