Authentication
Authentication
NotifyHub uses JWT (JSON Web Token) authentication to secure all API requests. This guide explains how authentication works and how to manage your tokens.
Overview
Every request to the NotifyHub API (except signup and login) requires a valid JWT token in the Authorization header.
Authentication Flow:
- Sign up or log in to receive a JWT token
- Include the token in the
Authorizationheader for all requests - Token expires after 24 hours (configurable)
- Refresh by logging in again
Sign Up
Create a new organization and get your first admin account.
Endpoint
POST https://api.notifyhub.com/auth/signup
Request
Headers:
Content-Type: application/json
Body:
{
"firstName": "John",
"lastName": "Doe",
"email": "john@yourcompany.com",
"password": "SecurePassword123!",
"countryCode": "+254",
"phoneNumber": "712345678",
"companyName": "Your Company Ltd",
"sector": "Technology",
"country": "Kenya",
"role": "admin"
}Field Descriptions:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| firstName | string | Yes | User's first name |
| lastName | string | Yes | User's last name |
| email | string | Yes | Unique email address (used for login) |
| password | string | Yes | Strong password (min 8 characters) |
| countryCode | string | Yes | Phone country code (e.g., "+254") |
| phoneNumber | string | Yes | Phone number without country code |
| companyName | string | Yes | Organization/company name |
| sector | string | Yes | Industry sector |
| country | string | Yes | Country of operation |
| role | string | No | User role (defaults to "admin") |
Response
Success (201 Created):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2OTVjYzNiMDIxMjc0MGJkMWRiYTQwZDQiLCJvcmdJZCI6IjY5NWNjM2IwMjEyNzQwYmQxZGJhNDBkMiIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTY0MTIzNDU2NywiZXhwIjoxNjQxMzIwOTY3fQ.abc123...",
"user": {
"_id": "695cc3b0212740bd1dba40d4",
"firstName": "John",
"lastName": "Doe",
"email": "john@yourcompany.com",
"countryCode": "+254",
"phoneNumber": "712345678",
"role": "admin",
"organization": "695cc3b0212740bd1dba40d2",
"isActive": true,
"createdAt": "2026-01-06T08:11:28.334Z",
"updatedAt": "2026-01-06T08:11:28.334Z"
}
}Error (400 Bad Request):
{
"statusCode": 400,
"message": "Email already exists",
"error": "Bad Request"
}Example
cURL:
curl -X POST https://api.notifyhub.com/auth/signup \
-H "Content-Type: application/json" \
-d '{
"firstName": "John",
"lastName": "Doe",
"email": "john@yourcompany.com",
"password": "SecurePassword123!",
"countryCode": "+254",
"phoneNumber": "712345678",
"companyName": "Your Company Ltd",
"sector": "Technology",
"country": "Kenya"
}'JavaScript:
const response = await fetch('https://api.notifyhub.com/auth/signup', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
firstName: 'John',
lastName: 'Doe',
email: 'john@yourcompany.com',
password: 'SecurePassword123!',
countryCode: '+254',
phoneNumber: '712345678',
companyName: 'Your Company Ltd',
sector: 'Technology',
country: 'Kenya'
})
});
const { token, user } = await response.json();Login
Authenticate with existing credentials to get a new JWT token.
Endpoint
POST https://api.notifyhub.com/auth/login
Request
Headers:
Content-Type: application/json
Body:
{
"email": "john@yourcompany.com",
"password": "SecurePassword123!"
}Field Descriptions:
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| email | string | Yes | Your registered email address |
| password | string | Yes | Your account password |
Response
Success (200 OK):
{
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"_id": "695cc3b0212740bd1dba40d4",
"firstName": "John",
"lastName": "Doe",
"email": "john@yourcompany.com",
"role": "admin",
"organization": "695cc3b0212740bd1dba40d2",
"isActive": true
}
}Error (401 Unauthorized):
{
"statusCode": 401,
"message": "Invalid credentials",
"error": "Unauthorized"
}Example
cURL:
curl -X POST https://api.notifyhub.com/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@yourcompany.com",
"password": "SecurePassword123!"
}'JavaScript:
const response = await fetch('https://api.notifyhub.com/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'john@yourcompany.com',
password: 'SecurePassword123!'
})
});
const { token, user } = await response.json();
// Store token securely for subsequent requests
localStorage.setItem('notifyhub_token', token);API Key Authentication
For server-to-server integrations and external developers, NotifyHub supports API Key authentication. API Keys do not expire unless revoked and are ideal for automated systems.
Generating a Key
API Keys can be generated from the Developers > API Keys section in your dashboard. Ensure you copy the key immediately, as it will only be shown once.
Recommended Client Setup
For security, developers should store API details in their environment variables (.env):
Unified_API_URL=http://localhost:3040
Unified_API_KEY=your_generted_api_keyUsage
You can authenticate using your API Key in two ways:
1. HTTP Header (Recommended)
Add the UNIFIED-API-Key header to your request.
UNIFIED-API-Key: YOUR_API_KEY_HERE2. Query Parameter
Append the key to your request URL using the apikey parameter.
http://localhost:3040/notifications/send?apikey=YOUR_API_KEY_HERESecurity Considerations
- Keep it secret: Treat your API Key like a password. Never share it or commit it to version control.
- Server-side only: Use API Keys only in server-to-server calls. Never expose them in client-side code (browsers/mobile apps) where they can be easily extracted.
- Revoke if compromised: If a key is exposed, revoke it immediately in the dashboard and generate a new one.
Using Your Token
Include the JWT token in the Authorization header for all authenticated requests.
Header Format
Authorization: Bearer YOUR_TOKEN_HERE
Example Request
cURL:
curl -X GET https://api.notifyhub.com/users/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."JavaScript:
const token = localStorage.getItem('notifyhub_token');
const response = await fetch('https://api.notifyhub.com/users/me', {
headers: {
'Authorization': `Bearer ${token}`
}
});
const user = await response.json();Python:
import requests
token = 'YOUR_TOKEN_HERE'
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(
'https://api.notifyhub.com/users/me',
headers=headers
)
user = response.json()Token Structure
JWT tokens contain encoded information about the authenticated user:
Decoded Payload:
{
"userId": "695cc3b0212740bd1dba40d4",
"orgId": "695cc3b0212740bd1dba40d2",
"role": "admin",
"iat": 1641234567,
"exp": 1641320967
}Fields:
userId: Your unique user IDorgId: Your organization ID (all operations are scoped to this)role: Your role (adminoruser)iat: Issued at timestampexp: Expiration timestamp
Security Note: The token payload is signed but not encrypted. Never include sensitive data in custom claims.
Token Expiration
Tokens expire after 24 hours by default.
Handling Expiration
When a token expires, you'll receive a 401 Unauthorized response:
{
"statusCode": 401,
"message": "Token expired",
"error": "Unauthorized"
}Solution: Log in again to get a new token.
Best Practices
-
Store tokens securely
- Never commit tokens to version control
- Use environment variables or secure credential stores
- In browsers: Use secure, httpOnly cookies (not localStorage for production)
-
Implement token refresh logic
async function apiRequest(url, options = {}) { let token = getStoredToken(); let response = await fetch(url, { ...options, headers: { ...options.headers, 'Authorization': `Bearer ${token}` } }); // If token expired, refresh and retry if (response.status === 401) { token = await refreshToken(); // Login again response = await fetch(url, { ...options, headers: { ...options.headers, 'Authorization': `Bearer ${token}` } }); } return response; } -
Monitor token expiration
- Decode JWT to check
exptimestamp - Refresh proactively before expiration
function isTokenExpired(token) { const payload = JSON.parse(atob(token.split('.')[1])); return Date.now() >= payload.exp * 1000; } - Decode JWT to check
Roles & Permissions
NotifyHub has two user roles:
Admin
Permissions:
- ✅ All messaging operations (SMS, Email, WhatsApp)
- ✅ Create, update, delete contacts and groups
- ✅ Create, manage, launch campaigns
- ✅ View message logs and analytics
- ✅ Manage team members (create, update, deactivate users)
- ✅ Update organization credentials
- ✅ Access all endpoints
User
Permissions:
- ✅ Send messages (SMS, Email, WhatsApp)
- ✅ View contacts and groups
- ✅ View message logs
- ✅ View own profile
- ❌ Cannot create/delete contacts or groups
- ❌ Cannot manage campaigns
- ❌ Cannot manage team members
- ❌ Cannot update organization credentials
Role-Based Access Example:
// This works for both admin and user
await sendSMS('+254712345678', 'Hello!');
// This requires admin role
await createContact({name: 'John', phone: '+254712345678'});
// User role will receive: 403 ForbiddenCommon Authentication Errors
401 Unauthorized
Causes:
- Missing
Authorizationheader - Invalid or malformed token
- Token expired
- Token signature mismatch
Solution:
// Ensure token is included correctly
headers: {
'Authorization': `Bearer ${token}`, // Note the space after Bearer
'Content-Type': 'application/json'
}403 Forbidden
Cause: Insufficient permissions (trying to access admin-only endpoint with user role)
Solution: Login with an admin account or request admin permissions from your organization admin.
Security Best Practices
- Use HTTPS only: Never send tokens over unencrypted connections
- Rotate tokens regularly: Log in periodically to get fresh tokens
- Implement token storage securely:
- Backend: Environment variables or secret managers
- Frontend: Secure cookies with httpOnly flag (not localStorage)
- Validate token on every request: Don't trust client-side expiration checks
- Monitor for suspicious activity: Track unusual login patterns
- Use strong passwords: Enforce minimum 8 characters with complexity
- Enable 2FA (coming soon): Additional security layer
Testing Authentication
Quick Test Script
// test-auth.js
const BASE_URL = 'https://api.notifyhub.com';
async function testAuth() {
// 1. Login
const loginResponse = await fetch(`${BASE_URL}/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
email: 'your-email@example.com',
password: 'your-password'
})
});
const { token } = await loginResponse.json();
console.log('Token received:', token.substring(0, 20) + '...');
// 2. Test authenticated request
const userResponse = await fetch(`${BASE_URL}/users/me`, {
headers: { 'Authorization': `Bearer ${token}` }
});
const user = await userResponse.json();
console.log('Authenticated user:', user.email);
// 3. Test sending a message
const messageResponse = await fetch(`${BASE_URL}/notifications/send`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
type: 'sms',
to: '+254712345678',
message: 'Auth test successful!'
})
});
const result = await messageResponse.json();
console.log('Message sent:', result);
}
testAuth().catch(console.error);Next Steps:
- Contacts Management - Organize your recipients
- Send Messages - SMS, Email, WhatsApp guides
- API Reference - Complete endpoint documentation