Integration - Authentication 🔒
This guide provides a comprehensive overview of authentication in the SMSGate API. JWT authentication is the primary mechanism for securing API access, providing a robust and scalable way to authenticate requests.
Authentication Overview 🔑
The SMSGate supports multiple authentication methods to accommodate different use cases:
- Basic Authentication: Legacy username/password for backward compatibility
- JWT Bearer Tokens: Primary authentication mechanism with configurable TTL and refresh token support
JWT Authentication Availability
JWT authentication is only available in Public Cloud Server mode. In Local Server mode, only Basic Authentication is supported.
JWT authentication is recommended for all new integrations as it provides better security, scalability, and fine-grained access control through scopes.
JWT Authentication 🔐
JWT authentication uses bearer tokens to authenticate API requests. These tokens contain encoded information about the user, their permissions (scopes), and token metadata. The system supports both access tokens (short-lived) and refresh tokens (long-lived) for seamless token rotation.
Token Generation 🚀
To generate a JWT token pair (access and refresh tokens), make a POST request to the token endpoint using Basic Authentication.
Endpoint
Local Server Mode
This endpoint returns HTTP 501 Not Implemented in local server mode. Use Basic Authentication instead.
Request
curl -X POST "https://api.sms-gate.app/3rdparty/v1/auth/token" \
-u "username:password" \
-H "Content-Type: application/json" \
-d '{
"ttl": 3600,
"scopes": [
"messages:send",
"messages:read",
"devices:list"
]
}'
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
ttl | integer | No | Token time-to-live in seconds (default: server dependent) |
scopes | array | Yes | List of scopes for the token |
Response
{
"id": "w8pxz0a4Fwa4xgzyCvSeC",
"token_type": "Bearer",
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_at": "2025-11-22T08:45:00Z"
}
Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Token identifier (JTI) |
token_type | string | Token type (always "Bearer") |
access_token | string | The JWT access token |
refresh_token | string | The JWT refresh token |
expires_at | string | ISO 8601 timestamp when the token expires |
Using JWT Tokens 📝
Once you have a JWT token, include it in the Authorization header of your API requests.
Authorization Header Format
Example Request
curl -X GET "https://api.sms-gate.app/3rdparty/v1/messages" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Refreshing Tokens 🔄
Access tokens are short-lived for security. Use the refresh token to obtain a new token pair without re-authenticating with credentials.
Endpoint
Request
curl -X POST "https://api.sms-gate.app/3rdparty/v1/auth/token/refresh" \
-H "Authorization: Bearer <your-refresh-token>"
Response
{
"id": "new_token_jti",
"token_type": "Bearer",
"access_token": "new_access_token_string",
"refresh_token": "new_refresh_token_string",
"expires_at": "2025-11-22T09:45:00Z"
}
Token Rotation
Each refresh operation generates a new token pair and revokes the old one. Always use the latest refresh token.
Token Management 🔄
Revoking Tokens
To revoke a token before it expires, make a DELETE request to the token endpoint.
curl -X DELETE "https://api.sms-gate.app/3rdparty/v1/auth/token/w8pxz0a4Fwa4xgzyCvSeC" \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Token Best Practices
- Use short TTLs: Set appropriate expiration times based on your security requirements
- Request minimal scopes: Only request the scopes your application needs
- Store tokens securely: Keep tokens in secure storage, not in client-side code
- Implement token rotation: Use refresh tokens to obtain new access tokens before expiration
- Revoke unused tokens: Immediately revoke tokens that are no longer needed
- Handle refresh token expiration: Refresh tokens have a longer TTL (default: 720h) but should still be rotated periodically
JWT Scopes 🔍
Scopes define the permissions associated with a JWT token, implementing the principle of least privilege.
Scope Structure
All scopes follow the pattern: resource:action
- Resource: The entity being accessed (e.g.,
messages,devices) - Action: The operation being performed (e.g.,
send,read,write)
Available Scopes
Global Scope
| Scope | Description | Access Level |
|---|---|---|
all:any | Provides full access to all resources and operations | Full Access |
Messages Scopes
| Scope | Description | Access Level |
|---|---|---|
messages:send | Permission to send SMS messages | Write |
messages:read | Permission to read individual message details | Read |
messages:list | Permission to list and view messages | Read |
Devices Scopes
| Scope | Description | Access Level |
|---|---|---|
devices:list | Permission to list and view registered devices | Read |
devices:delete | Permission to remove/unregister devices | Delete |
Webhooks Scopes
| Scope | Description | Access Level |
|---|---|---|
webhooks:list | Permission to list and view webhook configurations | Read |
webhooks:write | Permission to create and modify webhook configurations | Write |
webhooks:delete | Permission to remove webhook configurations | Delete |
Settings Scopes
| Scope | Description | Access Level |
|---|---|---|
settings:read | Permission to read system and user settings | Read |
settings:write | Permission to modify system and user settings | Write |
Logs Scopes
| Scope | Description | Access Level |
|---|---|---|
logs:read | Permission to read system and application logs | Read |
Token Management Scopes
| Scope | Description | Access Level |
|---|---|---|
tokens:manage | Permission to generate and revoke JWT tokens | Administrative |
tokens:refresh | System scope for token refresh operations | System |
System Scopes
The tokens:refresh scope is a system scope that is automatically included in refresh tokens. You do not need to (and should not) request this scope directly when generating tokens. It is managed internally by the system to enable token rotation.
Scope Assignment by Endpoint
Messages API
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/3rdparty/v1/messages | GET | messages:list | List messages |
/3rdparty/v1/messages | POST | messages:send | Send a new message |
/3rdparty/v1/messages/:id | GET | messages:read | Get message details |
/3rdparty/v1/messages/inbox/export | POST | messages:export | Export messages |
Devices API
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/3rdparty/v1/devices | GET | devices:list | List devices |
/3rdparty/v1/devices/:id | DELETE | devices:delete | Remove device |
Webhooks API
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/3rdparty/v1/webhooks | GET | webhooks:list | List webhooks |
/3rdparty/v1/webhooks | POST | webhooks:write | Create webhook |
/3rdparty/v1/webhooks/:id | DELETE | webhooks:delete | Remove webhook |
Settings API
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/3rdparty/v1/settings | GET | settings:read | Get settings |
/3rdparty/v1/settings | PATCH | settings:write | Update settings |
/3rdparty/v1/settings | PUT | settings:write | Replace settings |
Logs API
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/3rdparty/v1/logs | GET | logs:read | Read logs |
Token Management API
| Endpoint | Method | Required Scope | Description |
|---|---|---|---|
/3rdparty/v1/auth/token | POST | tokens:manage | Generate new token |
/3rdparty/v1/auth/token/refresh | POST | Bearer refresh token | Refresh token |
/3rdparty/v1/auth/token/:jti | DELETE | tokens:manage | Revoke token |
Code Examples 💻
curl -X POST "https://api.sms-gate.app/3rdparty/v1/auth/token" \
-u "username:password" \
-H "Content-Type: application/json" \
-d '{
"ttl": 3600,
"scopes": ["messages:send", "messages:read"]
}'
import requests
import json
# Configuration
gateway_url = "https://api.sms-gate.app"
username = "your_username"
password = "your_password"
# Generate token
response = requests.post(
f"{gateway_url}/3rdparty/v1/auth/token",
auth=(username, password),
headers={"Content-Type": "application/json"},
data=json.dumps({
"ttl": 3600,
"scopes": ["messages:send", "messages:read"]
})
)
if response.status_code == 201:
token_data = response.json()
access_token = token_data["access_token"]
print(f"Token generated successfully. Expires at: {token_data['expires_at']}")
else:
print(f"Error generating token: {response.status_code} - {response.text}")
import requests
import json
# Configuration
gateway_url = "https://api.sms-gate.app"
access_token = "your_jwt_token"
# Send message
response = requests.post(
f"{gateway_url}/3rdparty/v1/messages",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
data=json.dumps({
"phoneNumbers": ["+1234567890"],
"textMessage": {"text": "Hello from JWT!"}
})
)
if response.status_code == 202:
print("Message sent successfully!")
else:
print(f"Error sending message: {response.status_code} - {response.text}")
import requests
# Configuration
gateway_url = "https://api.sms-gate.app"
refresh_token = "your_refresh_token"
# Refresh token
response = requests.post(
f"{gateway_url}/3rdparty/v1/auth/token/refresh",
headers={
"Authorization": f"Bearer {refresh_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 200:
token_data = response.json()
access_token = token_data["access_token"]
refresh_token = token_data["refresh_token"]
print(f"Token refreshed successfully. Expires at: {token_data['expires_at']}")
else:
print(f"Error refreshing token: {response.status_code} - {response.text}")
// Configuration
const gatewayUrl = "https://api.sms-gate.app";
const username = "your_username";
const password = "your_password";
// Generate token
fetch(`${gatewayUrl}/3rdparty/v1/auth/token`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Basic ' + btoa(`${username}:${password}`)
},
body: JSON.stringify({
ttl: 3600,
scopes: ["messages:send", "messages:read"]
})
})
.then(response => response.json())
.then(data => {
if (data.access_token) {
console.log('Token generated successfully. Expires at:', data.expires_at);
} else {
console.error('Error generating token:', data);
}
})
.catch(error => console.error('Error:', error));
// Configuration
const gatewayUrl = "https://api.sms-gate.app";
const accessToken = "your_jwt_token";
// Send message
fetch(`${gatewayUrl}/3rdparty/v1/messages`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${accessToken}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
phoneNumbers: ["+1234567890"],
textMessage: {text: "Hello from JWT!"}
})
})
.then(response => response.json())
.then(data => {
if (data.id) {
console.log('Message sent successfully!');
} else {
console.error('Error sending message:', data);
}
})
.catch(error => console.error('Error:', error));
// Configuration
const gatewayUrl = "https://api.sms-gate.app";
const refreshToken = "your_refresh_token";
// Refresh token
fetch(`${gatewayUrl}/3rdparty/v1/auth/token/refresh`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${refreshToken}`,
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
if (data.access_token) {
console.log('Token refreshed successfully. Expires at:', data.expires_at);
} else {
console.error('Error refreshing token:', data);
}
})
.catch(error => console.error('Error:', error));
Migration from Basic Auth to JWT 🔄
Why Migrate?
- Enhanced Security: JWT tokens provide better security than Basic Auth
- Fine-grained Access Control: Scopes allow precise permission management
Migration Steps
- Generate JWT Tokens: Use the token endpoint to create JWT tokens with appropriate scopes
- Update Client Code: Replace Basic Auth with JWT Bearer tokens
- Implement Token Management: Add token refresh and error handling
- Test Thoroughly: Ensure all functionality works with JWT authentication
Migration Example
# JWT authentication example
# First, get a token
token_response = requests.post(
"https://api.sms-gate.app/3rdparty/v1/auth/token",
auth=("username", "password"),
json={
"ttl": 3600,
"scopes": ["messages:send"]
}
)
if token_response.status_code == 201:
token_data = token_response.json()
access_token = token_data["access_token"]
# Then use the token
response = requests.post(
"https://api.sms-gate.app/3rdparty/v1/messages",
headers={
"Authorization": f"Bearer {access_token}",
"Content-Type": "application/json"
},
json={
"phoneNumbers": ["+1234567890"],
"textMessage": {"text": "Hello world!"}
}
)
Error Handling ⚠️
Error Handling Best Practices
- Check Token Expiration: Implement token refresh before expiration
- Handle 401 Errors: Re-authenticate and get a new token
- Handle 403 Errors: Verify your token has the required scopes
- Log Errors: Record authentication errors for debugging
Error Handling Example (Python)
import requests
import time
from datetime import datetime, timedelta, timezone
class SMSGatewayClient:
def __init__(self, gateway_url, username, password):
self.gateway_url = gateway_url
self.username = username
self.password = password
self.access_token = None
self.refresh_token = None
self.token_expires_at = None
def get_token(self, scopes, ttl=3600):
"""Get a new JWT token pair"""
response = requests.post(
f"{self.gateway_url}/3rdparty/v1/auth/token",
auth=(self.username, self.password),
headers={"Content-Type": "application/json"},
json={"ttl": ttl, "scopes": scopes}
)
if response.status_code == 201:
token_data = response.json()
self.access_token = token_data["access_token"]
self.refresh_token = token_data["refresh_token"]
# Parse expiration time
self.token_expires_at = datetime.fromisoformat(
token_data["expires_at"].replace("Z", "+00:00")
)
return self.access_token
else:
raise Exception(f"Failed to get token: {response.status_code} - {response.text}")
def refresh_access_token(self):
"""Refresh the access token using the refresh token"""
if not self.refresh_token:
raise Exception("No refresh token available")
response = requests.post(
f"{self.gateway_url}/3rdparty/v1/auth/token/refresh",
headers={
"Authorization": f"Bearer {self.refresh_token}",
"Content-Type": "application/json"
}
)
if response.status_code == 200:
token_data = response.json()
self.access_token = token_data["access_token"]
self.refresh_token = token_data["refresh_token"]
# Parse expiration time
self.token_expires_at = datetime.fromisoformat(
token_data["expires_at"].replace("Z", "+00:00")
)
return self.access_token
else:
raise Exception(f"Failed to refresh token: {response.status_code} - {response.text}")
def ensure_valid_token(self, scopes):
"""Ensure we have a valid token, refresh if needed"""
if (self.access_token is None or
self.token_expires_at is None or
datetime.now(timezone.utc) + timedelta(minutes=5) >= self.token_expires_at):
if self.refresh_token:
self.refresh_access_token()
else:
self.get_token(scopes)
return self.access_token
def send_message(self, recipient, message):
"""Send a message with automatic token handling"""
try:
token = self.ensure_valid_token(["messages:send"])
response = requests.post(
f"{self.gateway_url}/3rdparty/v1/messages",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json={"recipient": recipient, "textMessage": {"text": message}}
)
if response.status_code == 401:
# Token might be expired or invalid, try refreshing
if self.refresh_token:
token = self.refresh_access_token()
else:
token = self.get_token(["messages:send"])
response = requests.post(
f"{self.gateway_url}/3rdparty/v1/messages",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
},
json={"recipient": recipient, "textMessage": {"text": message}}
)
if response.status_code == 202:
return response.json()
else:
raise Exception(f"Failed to send message: {response.status_code} - {response.text}")
except Exception as e:
print(f"Error sending message: {str(e)}")
raise
# Usage example
client = SMSGatewayClient("https://api.sms-gate.app", "username", "password")
result = client.send_message("+1234567890", "Hello from JWT!")
print("Message sent:", result)
Security Considerations 🔒
Token Security
- Keep Tokens Secret: Treat JWT tokens like passwords
- Use HTTPS: Always transmit tokens over encrypted connections
- Short Expiration: Use the shortest practical TTL for your use case
- Scope Limitation: Request only the scopes you need
- Secure Storage: Store tokens securely on the server side, not in client-side code
- Revocation: Implement token revocation for compromised tokens
- Refresh Token Security: Store refresh tokens securely and rotate them periodically
Client Security
- Validate Tokens: Always validate server responses
- Error Handling: Implement proper error handling for authentication failures
- Token Storage: Store tokens securely (e.g., HttpOnly cookies, secure server-side storage)
- CSRF Protection: Implement CSRF protection for web applications
See Also 🔗
- API Reference - Complete API endpoint documentation
- Integration Guide - Overview of integration options
- Client Libraries - Pre-built libraries for various languages
- Authentication FAQ - Frequently Asked Questions about JWT authentication