Skip to main content
All GOV.UK Notify API requests require authentication using JSON Web Tokens (JWT). This page explains how to generate and use JWT tokens to authenticate your API requests.

Authentication Method

The API uses JWT (JSON Web Token) authentication with HS256 signing:
  1. Generate a JWT token signed with your API key secret
  2. Include the token in the Authorization header
  3. Token must be valid (not expired, correct signature)

API Keys

API keys are managed through the GOV.UK Notify admin interface. Each API key has:
  • Key ID - UUID identifying the key
  • Secret - Used to sign JWT tokens
  • Key type - Determines permissions and rate limits

Key Types

Production use - Send to any recipient
  • Can send to any phone number or email address
  • Subject to full rate limits
  • Notifications are billable
  • Used for production services
Protect live keys carefully - they can send real notifications to real users.

Generating JWT Tokens

Token Structure

A valid JWT token for Notify must include these claims:
JWT claims
{
  "iss": "<your-service-id>",
  "iat": 1234567890
}
iss
string
required
Issuer - Your service ID (UUID)
iat
integer
required
Issued at - Unix timestamp when token was created
Must be within 30 seconds of the server time. Clock skew beyond this will cause authentication to fail.

Token Signing

Tokens must be signed using HS256 (HMAC-SHA256) with your API key secret:
Python example
import jwt
import time
from uuid import UUID

def create_jwt_token(api_key_id: str, api_key_secret: str, service_id: str) -> str:
    """
    Generate a JWT token for Notify API authentication.
    
    Args:
        api_key_id: API key UUID (not used in token, but for reference)
        api_key_secret: Secret key for signing
        service_id: Service UUID
    
    Returns:
        JWT token string
    """
    headers = {
        "typ": "JWT",
        "alg": "HS256"
    }
    
    claims = {
        "iss": service_id,
        "iat": int(time.time())
    }
    
    token = jwt.encode(
        payload=claims,
        key=api_key_secret,
        algorithm="HS256",
        headers=headers
    )
    
    return token

# Usage
token = create_jwt_token(
    api_key_id="26785a09-ab16-4eb0-8407-a8282bf9f00f",
    api_key_secret="your-secret-key-here",
    service_id="d6aa2c68-a2d9-4437-ab19-3ae8eb202553"
)
Node.js example
const jwt = require('jsonwebtoken');

function createJwtToken(apiKeySecret, serviceId) {
  const claims = {
    iss: serviceId,
    iat: Math.floor(Date.now() / 1000)
  };
  
  const token = jwt.sign(claims, apiKeySecret, {
    algorithm: 'HS256'
  });
  
  return token;
}

// Usage
const token = createJwtToken(
  'your-secret-key-here',
  'd6aa2c68-a2d9-4437-ab19-3ae8eb202553'
);
Ruby example
require 'jwt'

def create_jwt_token(api_key_secret, service_id)
  claims = {
    iss: service_id,
    iat: Time.now.to_i
  }
  
  JWT.encode(claims, api_key_secret, 'HS256')
end

# Usage
token = create_jwt_token(
  'your-secret-key-here',
  'd6aa2c68-a2d9-4437-ab19-3ae8eb202553'
)

Making Authenticated Requests

Authorization Header

Include the JWT token in the Authorization header with the Bearer scheme:
cURL example
curl -X POST https://api.notifications.service.gov.uk/v2/notifications/sms \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+447900900123",
    "template_id": "f33517ff-2a88-4f6e-b855-c550268ce08a"
  }'

Complete Request Example

Python with requests
import requests
import jwt
import time

# Configuration
API_KEY_SECRET = "your-secret-key"
SERVICE_ID = "d6aa2c68-a2d9-4437-ab19-3ae8eb202553"
BASE_URL = "https://api.notifications.service.gov.uk"

# Generate token
token = jwt.encode(
    {"iss": SERVICE_ID, "iat": int(time.time())},
    API_KEY_SECRET,
    algorithm="HS256"
)

# Make request
response = requests.post(
    f"{BASE_URL}/v2/notifications/sms",
    headers={
        "Authorization": f"Bearer {token}",
        "Content-Type": "application/json"
    },
    json={
        "phone_number": "+447900900123",
        "template_id": "f33517ff-2a88-4f6e-b855-c550268ce08a",
        "personalisation": {
            "name": "John"
        }
    }
)

if response.status_code == 201:
    notification = response.json()
    print(f"Notification sent: {notification['id']}")
else:
    print(f"Error: {response.json()}")

Authentication Errors

Common authentication errors and how to fix them:
Error message: Invalid token: signatureCauses:
  • Wrong API key secret used for signing
  • Service ID doesn’t match the API key
  • Token signature is invalid
Solution:
  • Verify you’re using the correct API key secret
  • Ensure service ID matches the service that owns the API key
  • Check JWT library is using HS256 algorithm
Error message: Invalid token: API key not foundCauses:
  • API key has been revoked
  • API key ID is incorrect
  • Service ID in token doesn’t exist
Solution:
  • Check API key hasn’t been revoked in admin interface
  • Verify service ID is correct
  • Generate a new API key if needed
Error message: Error: Your system clock must be accurate to within 30 secondsCauses:
  • System clock is not synchronized
  • iat claim is more than 30 seconds in the past or future
Solution:
  • Synchronize your system clock with NTP
  • Generate a fresh token for each request
  • Don’t cache tokens for extended periods

Best Practices

Generate tokens per request

Create a new token for each API request instead of reusing tokens. This avoids clock skew issues.

Secure storage

Store API key secrets securely using environment variables or secret management systems. Never commit secrets to version control.

Key rotation

Rotate API keys periodically and when team members with access leave.

Use appropriate key type

Use test keys for development, team keys for testing, and live keys only in production.

Using Client Libraries

Official client libraries handle JWT token generation automatically:
Python client
from notifications_python_client.notifications import NotificationsAPIClient

client = NotificationsAPIClient(api_key="your-api-key-name-here")

# Client automatically generates JWT tokens for each request
response = client.send_sms_notification(
    phone_number="+447900900123",
    template_id="f33517ff-2a88-4f6e-b855-c550268ce08a"
)
See Client Libraries for more information.

Next Steps

Rate limits

Understand API rate limits

Send notifications

Start sending notifications

Build docs developers (and LLMs) love