Skip to content

Authentication

MenoTime uses JWT (JSON Web Token) based authentication to secure API access. All API requests (except /login) require a valid JWT token in the Authorization header.

Overview

The authentication flow follows industry best practices:

  1. Login: Exchange credentials for an access token and refresh token
  2. Authorize Requests: Include the access token in the Authorization header
  3. Refresh Tokens: Use the refresh token to obtain a new access token when it expires
  4. Logout: Invalidate tokens when no longer needed

Login Endpoint

Exchange your credentials for JWT tokens.

Endpoint: POST /auth/login

Request

{
  "email": "provider@hospital.com",
  "password": "your_secure_password"
}

Response (200 OK)

{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "bearer",
    "expires_in": 3600,
    "user": {
      "id": "usr_123456",
      "email": "provider@hospital.com",
      "role": "provider",
      "organization": "City Hospital",
      "created_at": "2024-01-15T10:30:00Z"
    }
  }
}

Parameters

Field Type Required Description
email string Yes User email address
password string Yes User password

Example Using cURL

curl -X POST https://api.menotime.timelessbiotech.com/v1/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "provider@hospital.com",
    "password": "your_secure_password"
  }'

Example Using Python

import requests

url = "https://api.menotime.timelessbiotech.com/v1/auth/login"
payload = {
    "email": "provider@hospital.com",
    "password": "your_secure_password"
}

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

access_token = data["data"]["access_token"]
refresh_token = data["data"]["refresh_token"]

Token Refresh

Access tokens expire after 1 hour. Use the refresh token to obtain a new access token without re-entering credentials.

Endpoint: POST /auth/refresh

Request

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (200 OK)

{
  "status": "success",
  "data": {
    "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "token_type": "bearer",
    "expires_in": 3600
  }
}

Example Using Python

import requests

url = "https://api.menotime.timelessbiotech.com/v1/auth/refresh"
payload = {
    "refresh_token": refresh_token
}

response = requests.post(url, json=payload)
new_token = response.json()["data"]["access_token"]

Authorization Header Format

Include the JWT token in the Authorization header of all authenticated requests:

Authorization: Bearer {access_token}

Example:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c3JfMTIzNDU2IiwiZXhwIjoxNjQwOTk1MjAwfQ...

Example Request with Authorization

curl -X GET https://api.menotime.timelessbiotech.com/v1/patients \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Role-Based Access Control

MenoTime implements role-based access control (RBAC) to restrict API access based on user roles.

Available Roles

Role Description Permissions
admin System administrator Full access to all endpoints and resources
provider Healthcare provider Create/read/update patients and visits, submit data
readonly Data analyst or researcher Read-only access to de-identified patient data
superadmin Organization administrator Manage users, organizations, billing, audit logs

Role-Based Endpoint Access

Endpoint Admin Provider Readonly Superadmin
POST /patients
GET /patients
PUT /patients/{id}
POST /visits
GET /visits
POST /users
GET /admin/logs

Response for insufficient permissions (403 Forbidden):

{
  "status": "error",
  "code": "FORBIDDEN",
  "message": "Insufficient permissions for this resource",
  "details": {
    "required_role": "admin",
    "user_role": "readonly"
  }
}

Token Expiration and Security

Token Lifetimes

Token Type Lifetime Refresh Before
Access Token 1 hour 50 minutes
Refresh Token 30 days 25 days

Security Best Practices

  1. Store tokens securely
  2. Never store tokens in plain text or browser localStorage
  3. Use secure, httpOnly cookies when possible
  4. Use environment variables for sensitive credentials

  5. Handle token expiration

  6. Implement automatic token refresh before expiration
  7. Catch 401 Unauthorized errors and refresh the token
  8. Retry the original request after refresh

  9. Logout and revocation

  10. Call the logout endpoint when a user logs out
  11. Revoked tokens are added to a blacklist
  12. Blacklist tokens cannot be refreshed

Logout Endpoint

Endpoint: POST /auth/logout

Request

{
  "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Response (200 OK)

{
  "status": "success",
  "message": "Logged out successfully"
}

Token Claims

MenoTime JWT tokens contain the following claims:

{
  "sub": "usr_123456",
  "email": "provider@hospital.com",
  "role": "provider",
  "organization_id": "org_789012",
  "iat": 1640992000,
  "exp": 1640995600,
  "iss": "menotime-api",
  "aud": "menotime-frontend"
}

Standard Claims

Claim Description
sub Subject (user ID)
email User email address
role User role (admin, provider, readonly, superadmin)
organization_id Organization ID
iat Issued at (Unix timestamp)
exp Expiration time (Unix timestamp)
iss Issuer
aud Audience

Error Responses

Invalid Credentials (401 Unauthorized)

{
  "status": "error",
  "code": "INVALID_CREDENTIALS",
  "message": "Invalid email or password"
}

Expired Token (401 Unauthorized)

{
  "status": "error",
  "code": "TOKEN_EXPIRED",
  "message": "Access token has expired. Please refresh your token.",
  "details": {
    "expired_at": "2024-02-15T15:30:00Z"
  }
}

Invalid Token Format (401 Unauthorized)

{
  "status": "error",
  "code": "INVALID_TOKEN",
  "message": "Invalid or malformed token"
}

Missing Authorization Header (401 Unauthorized)

{
  "status": "error",
  "code": "MISSING_AUTHORIZATION",
  "message": "Authorization header is required"
}

Implementation Example

Python with Requests Library

import requests
from datetime import datetime, timedelta

class MenoTimeClient:
    def __init__(self, email, password, base_url="https://api.menotime.timelessbiotech.com/v1"):
        self.base_url = base_url
        self.email = email
        self.password = password
        self.access_token = None
        self.refresh_token = None
        self.token_expiry = None

    def login(self):
        """Login and obtain tokens"""
        response = requests.post(
            f"{self.base_url}/auth/login",
            json={"email": self.email, "password": self.password}
        )
        response.raise_for_status()

        data = response.json()["data"]
        self.access_token = data["access_token"]
        self.refresh_token = data["refresh_token"]
        self.token_expiry = datetime.utcnow() + timedelta(seconds=data["expires_in"])

    def _refresh_access_token(self):
        """Refresh the access token"""
        response = requests.post(
            f"{self.base_url}/auth/refresh",
            json={"refresh_token": self.refresh_token}
        )
        response.raise_for_status()

        data = response.json()["data"]
        self.access_token = data["access_token"]
        self.token_expiry = datetime.utcnow() + timedelta(seconds=data["expires_in"])

    def _get_headers(self):
        """Get request headers with authorization"""
        if self.token_expiry and datetime.utcnow() >= self.token_expiry - timedelta(minutes=5):
            self._refresh_access_token()

        return {
            "Authorization": f"Bearer {self.access_token}",
            "Content-Type": "application/json"
        }

    def get_patients(self):
        """Fetch patients"""
        response = requests.get(
            f"{self.base_url}/patients",
            headers=self._get_headers()
        )
        response.raise_for_status()
        return response.json()

    def logout(self):
        """Logout and revoke tokens"""
        requests.post(
            f"{self.base_url}/auth/logout",
            json={"refresh_token": self.refresh_token},
            headers=self._get_headers()
        )
        self.access_token = None
        self.refresh_token = None

# Usage
client = MenoTimeClient("provider@hospital.com", "password")
client.login()
patients = client.get_patients()
client.logout()

Additional Resources