API Authentication¶
Overview¶
The UptimeHunt API uses JWT (JSON Web Token) based authentication to secure all API endpoints. This guide provides comprehensive documentation for implementing authentication in your applications, including token management, user registration, login workflows, and password reset functionality.
Authentication Flow¶
Token Types¶
UptimeHunt issues two types of tokens:
| Token Type | Lifetime | Purpose |
|---|---|---|
| Access Token | 15 minutes | Authenticates API requests |
| Refresh Token | 7 days | Generates new access tokens |
Token Management Workflow¶
- Initial Authentication: User registers or logs in to receive both access and refresh tokens
- API Requests: Include access token in the
Authorizationheader for authenticated requests - Token Refresh: When access token expires, use refresh token to obtain new access token
- Re-authentication: When refresh token expires, user must log in again
Base URL¶
All API endpoints use the following base URL:
Authentication Endpoints¶
User Registration¶
Create a new user account and receive authentication tokens.
Endpoint: POST /v1/auth/register
Authentication: Not required
Request Headers:
Request Body:
{
"email": "user@example.com",
"password": "securepassword123",
"first_name": "John",
"last_name": "Doe"
}
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Valid email address (must be unique) | |
| password | string | Yes | Password (minimum 8 characters) |
| first_name | string | No | User's first name |
| last_name | string | No | User's last name |
Success Response (201 Created):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe",
"date_joined": "2024-01-15T10:30:00Z"
}
}
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | Email and password are required | Missing required fields |
| 400 | User with this email already exists | Email already registered |
cURL Example:
curl -X POST https://app.uptimehunt.io/api/v1/auth/register \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123",
"first_name": "John",
"last_name": "Doe"
}'
User Login¶
Authenticate existing user and receive authentication tokens.
Endpoint: POST /v1/auth/login
Authentication: Not required
Request Headers:
Request Body:
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | User's email address | |
| password | string | Yes | User's password |
Success Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900,
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe",
"date_joined": "2024-01-15T10:30:00Z"
}
}
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | Must include "email" and "password" | Missing required fields |
| 400 | Invalid credentials | Incorrect email or password |
| 400 | User account is disabled | Account has been deactivated |
cURL Example:
curl -X POST https://app.uptimehunt.io/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"password": "securepassword123"
}'
Refresh Access Token¶
Generate a new access token using a valid refresh token.
Endpoint: POST /v1/auth/refresh
Authentication: Not required (uses refresh token)
Request Headers:
Request Body:
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| refresh_token | string | Yes | Valid refresh token |
Success Response (200 OK):
{
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 900
}
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | Refresh token is required | Missing refresh token |
| 401 | Invalid refresh token | Token is invalid, expired, or malformed |
cURL Example:
curl -X POST https://app.uptimehunt.io/api/v1/auth/refresh \
-H "Content-Type: application/json" \
-d '{
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}'
Get Current User¶
Retrieve authenticated user information.
Endpoint: GET /v1/auth/me
Authentication: Required
Request Headers:
Success Response (200 OK):
{
"data": {
"id": 1,
"email": "user@example.com",
"first_name": "John",
"last_name": "Doe",
"date_joined": "2024-01-15T10:30:00Z"
}
}
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 401 | Authentication credentials were not provided | Missing Authorization header |
| 401 | Given token not valid for any token type | Invalid or expired access token |
cURL Example:
curl -X GET https://app.uptimehunt.io/api/v1/auth/me \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Update User Profile¶
Update authenticated user's profile information.
Endpoint: PUT /v1/auth/profile or PATCH /v1/auth/profile
Authentication: Required
Request Headers:
Request Body (all fields optional for PATCH):
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| string | No | New email address (must be unique) | |
| first_name | string | No | Updated first name |
| last_name | string | No | Updated last name |
Success Response (200 OK):
{
"data": {
"id": 1,
"email": "newemail@example.com",
"first_name": "Jane",
"last_name": "Smith",
"date_joined": "2024-01-15T10:30:00Z"
},
"message": "Profile updated successfully"
}
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | A user with this email already exists | Email already in use |
| 401 | Authentication credentials were not provided | Missing or invalid token |
cURL Example:
curl -X PUT https://app.uptimehunt.io/api/v1/auth/profile \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Smith"
}'
Change Password¶
Change authenticated user's password.
Endpoint: POST /v1/auth/change-password
Authentication: Required
Request Headers:
Request Body:
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| current_password | string | Yes | Current password for verification |
| new_password | string | Yes | New password (minimum 8 characters) |
Success Response (200 OK):
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | Current password is incorrect | Wrong current password provided |
| 400 | This field is required | Missing required field |
| 400 | Ensure this field has at least 8 characters | Password too short |
| 401 | Authentication credentials were not provided | Missing or invalid token |
cURL Example:
curl -X POST https://app.uptimehunt.io/api/v1/auth/change-password \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
-H "Content-Type: application/json" \
-d '{
"current_password": "oldpassword123",
"new_password": "newsecurepassword456"
}'
Security Notice
A confirmation email is sent to the user after successfully changing their password.
Request Password Reset¶
Request a password reset link via email.
Endpoint: POST /v1/auth/password-reset/request
Authentication: Not required
Request Headers:
Request Body:
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| string | Yes | Email address of the account | |
| frontend_url | string | No | Base URL for password reset link (defaults to configured frontend URL) |
Success Response (200 OK):
{
"status": "PASSWORD_RESET_SENT",
"detail": "If an account with that email exists, a password reset link has been sent."
}
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | Email is required | Missing email field |
| 500 | Failed to send password reset email | Email service unavailable |
cURL Example:
curl -X POST https://app.uptimehunt.io/api/v1/auth/password-reset/request \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"frontend_url": "https://app.uptimehunt.com"
}'
Security Design
The response is intentionally vague to prevent email enumeration attacks. The same response is returned whether the email exists or not.
Confirm Password Reset¶
Complete the password reset process using the token from email.
Endpoint: POST /v1/auth/password-reset/confirm
Authentication: Not required
Request Headers:
Request Body:
{
"uid": "MQ",
"token": "c5h7ke-8f9a2b3c4d5e6f7g8h9i0j1k2",
"new_password": "newsecurepassword456"
}
Request Schema:
| Field | Type | Required | Description |
|---|---|---|---|
| uid | string | Yes | Base64-encoded user ID from reset email |
| token | string | Yes | Password reset token from email |
| new_password | string | Yes | New password (minimum 8 characters) |
Success Response (200 OK):
Error Responses:
| Status Code | Error | Description |
|---|---|---|
| 400 | UID, token, and new password are required | Missing required fields |
| 400 | Invalid reset link | Invalid or malformed UID/token |
| 400 | Invalid or expired reset link | Token has expired or already used |
| 400 | Password must be at least 8 characters long | Password too short |
cURL Example:
curl -X POST https://app.uptimehunt.io/api/v1/auth/password-reset/confirm \
-H "Content-Type: application/json" \
-d '{
"uid": "MQ",
"token": "c5h7ke-8f9a2b3c4d5e6f7g8h9i0j1k2",
"new_password": "newsecurepassword456"
}'
Confirmation Email
A confirmation email is sent to the user after successfully resetting their password.
Using Authentication Tokens¶
Token Storage¶
Store tokens securely in your application:
- Web Applications: Use secure HTTP-only cookies or browser localStorage
- Mobile Applications: Use secure storage mechanisms (Keychain, KeyStore)
- Server-to-Server: Use environment variables or secure credential storage
Making Authenticated Requests¶
Include the access token in the Authorization header for all authenticated API requests:
Example Request:
curl -X GET https://app.uptimehunt.io/api/v1/services \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Handling Token Expiration¶
Access tokens expire after 15 minutes. Implement token refresh logic:
// JavaScript/TypeScript example
async function apiRequest(url, options = {}) {
let accessToken = localStorage.getItem('access_token');
// Add authorization header
options.headers = {
...options.headers,
'Authorization': `Bearer ${accessToken}`
};
let response = await fetch(url, options);
// If token expired, refresh and retry
if (response.status === 401) {
const refreshToken = localStorage.getItem('refresh_token');
// Refresh the token
const refreshResponse = await fetch('/api/v1/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refresh_token: refreshToken })
});
if (refreshResponse.ok) {
const { access_token } = await refreshResponse.json();
localStorage.setItem('access_token', access_token);
// Retry original request with new token
options.headers['Authorization'] = `Bearer ${access_token}`;
response = await fetch(url, options);
} else {
// Refresh failed, redirect to login
window.location.href = '/login';
}
}
return response;
}
# Python example using requests
import requests
from datetime import datetime, timedelta
class APIClient:
def __init__(self, base_url):
self.base_url = base_url
self.access_token = None
self.refresh_token = None
self.token_expiry = None
def login(self, email, password):
response = requests.post(
f"{self.base_url}/v1/auth/login",
json={"email": email, "password": password}
)
response.raise_for_status()
data = response.json()
self.access_token = data['access_token']
self.refresh_token = data['refresh_token']
# Token expires in 900 seconds (15 minutes)
self.token_expiry = datetime.now() + timedelta(seconds=data['expires_in'])
return data['user']
def refresh_access_token(self):
response = requests.post(
f"{self.base_url}/v1/auth/refresh",
json={"refresh_token": self.refresh_token}
)
response.raise_for_status()
data = response.json()
self.access_token = data['access_token']
self.token_expiry = datetime.now() + timedelta(seconds=data['expires_in'])
def request(self, method, endpoint, **kwargs):
# Refresh token if expired or about to expire
if self.token_expiry and datetime.now() >= self.token_expiry - timedelta(minutes=1):
self.refresh_access_token()
headers = kwargs.pop('headers', {})
headers['Authorization'] = f"Bearer {self.access_token}"
response = requests.request(
method,
f"{self.base_url}{endpoint}",
headers=headers,
**kwargs
)
# Handle token expiration
if response.status_code == 401:
self.refresh_access_token()
headers['Authorization'] = f"Bearer {self.access_token}"
response = requests.request(
method,
f"{self.base_url}{endpoint}",
headers=headers,
**kwargs
)
return response
# Usage
client = APIClient("https://app.uptimehunt.io/api")
client.login("user@example.com", "password123")
response = client.request("GET", "/v1/services")
services = response.json()
Security Best Practices¶
Token Security¶
- Secure Storage: Never store tokens in plain text or client-side code
- HTTPS Only: Always use HTTPS in production to prevent token interception
- Token Rotation: Implement regular token refresh to minimize security risks
- Logout: Invalidate tokens on logout by removing them from storage
Password Security¶
- Minimum Length: Enforce minimum 8-character passwords
- Complexity: Use passwords with mixed character types
- Unique Passwords: Never reuse passwords across services
- Password Managers: Recommend using password managers
API Security¶
- Input Validation: Validate all input data on the client and server
- Error Handling: Don't expose sensitive information in error messages
- Monitoring: Monitor authentication attempts for suspicious activity
Common Authentication Errors¶
401 Unauthorized¶
Cause: Missing, invalid, or expired authentication token
Solutions:
- Verify token is included in Authorization header
- Check token format: Bearer {token}
- Refresh expired access token using refresh token
- Re-authenticate if refresh token is expired
400 Bad Request¶
Cause: Invalid request parameters or validation errors
Solutions: - Verify all required fields are provided - Check field formats (email, password length) - Review error response for specific validation messages
403 Forbidden¶
Cause: Valid authentication but insufficient permissions
Solutions: - Verify user has necessary permissions - Check resource ownership - Contact administrator for access
JWT Token Structure¶
UptimeHunt uses JWT tokens with the following configuration:
| Setting | Value | Description |
|---|---|---|
| Algorithm | HS256 | HMAC with SHA-256 |
| Access Token Lifetime | 15 minutes | Validity period for access tokens |
| Refresh Token Lifetime | 7 days | Validity period for refresh tokens |
| Header Type | Bearer | Authorization header type |
| User ID Claim | user_id | Claim containing user identifier |
Token Payload Example¶
{
"user_id": 1,
"token_type": "access",
"exp": 1705318200,
"iat": 1705317300,
"jti": "abc123def456"
}
| Claim | Description |
|---|---|
| user_id | Unique identifier for the authenticated user |
| token_type | Token type (access or refresh) |
| exp | Expiration timestamp (Unix time) |
| iat | Issued at timestamp (Unix time) |
| jti | JWT ID (unique token identifier) |
Related Documentation¶
- Services API - Managing monitoring services
- Projects API - Organizing services with projects
- Account Management - User guide for account settings
- Registration Guide - User registration walkthrough