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:
- Login: Exchange credentials for an access token and refresh token
- Authorize Requests: Include the access token in the Authorization header
- Refresh Tokens: Use the refresh token to obtain a new access token when it expires
- 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 |
|---|---|---|---|
| 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
- Store tokens securely
- Never store tokens in plain text or browser localStorage
- Use secure, httpOnly cookies when possible
-
Use environment variables for sensitive credentials
-
Handle token expiration
- Implement automatic token refresh before expiration
- Catch 401 Unauthorized errors and refresh the token
-
Retry the original request after refresh
-
Logout and revocation
- Call the logout endpoint when a user logs out
- Revoked tokens are added to a blacklist
- 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()