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 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.
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.
# JWT authentication example# First, get a tokentoken_response=requests.post("https://api.sms-gate.app/3rdparty/v1/auth/token",auth=("username","password"),json={"ttl":3600,"scopes":["messages:send"]})iftoken_response.status_code==201:token_data=token_response.json()access_token=token_data["access_token"]# Then use the tokenresponse=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)
importrequestsimporttimefromdatetimeimportdatetime,timedelta,timezoneclassSMSGatewayClient:def__init__(self,gateway_url,username,password):self.gateway_url=gateway_urlself.username=usernameself.password=passwordself.access_token=Noneself.refresh_token=Noneself.token_expires_at=Nonedefget_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})ifresponse.status_code==201:token_data=response.json()self.access_token=token_data["access_token"]self.refresh_token=token_data["refresh_token"]# Parse expiration timeself.token_expires_at=datetime.fromisoformat(token_data["expires_at"].replace("Z","+00:00"))returnself.access_tokenelse:raiseException(f"Failed to get token: {response.status_code} - {response.text}")defrefresh_access_token(self):"""Refresh the access token using the refresh token"""ifnotself.refresh_token:raiseException("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"})ifresponse.status_code==200:token_data=response.json()self.access_token=token_data["access_token"]self.refresh_token=token_data["refresh_token"]# Parse expiration timeself.token_expires_at=datetime.fromisoformat(token_data["expires_at"].replace("Z","+00:00"))returnself.access_tokenelse:raiseException(f"Failed to refresh token: {response.status_code} - {response.text}")defensure_valid_token(self,scopes):"""Ensure we have a valid token, refresh if needed"""if(self.access_tokenisNoneorself.token_expires_atisNoneordatetime.now(timezone.utc)+timedelta(minutes=5)>=self.token_expires_at):ifself.refresh_token:self.refresh_access_token()else:self.get_token(scopes)returnself.access_tokendefsend_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}})ifresponse.status_code==401:# Token might be expired or invalid, try refreshingifself.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}})ifresponse.status_code==202:returnresponse.json()else:raiseException(f"Failed to send message: {response.status_code} - {response.text}")exceptExceptionase:print(f"Error sending message: {str(e)}")raise# Usage exampleclient=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