AWS Builder Center
πŸ›‘οΈ Ultimate Guide: JWT-Based Rate Limiting with AWS WAF πŸš€

πŸ›‘οΈ Ultimate Guide: JWT-Based Rate Limiting with AWS WAF πŸš€

This comprehensive guide explains how to implement rate limiting based on JWT (JSON Web Token) authorization values using AWS WAF and Lambda@Edge. The article addresses a common security challenge: controlling request rates for specific users or tokens in web applications.

πŸ“Œ Empowering Business: Cloud Network & Edge ServicesπŸ“Œ 🎯 Subject Matter Expert: WAF & Route 53 🎯
πŸš€ Master JWT Rate Limiting: A Developer's Guide to AWS WAF Security!

🌟 Why Should You Care?

Protect your Application/APIs from abuse and ensure fair usage by implementing smart rate limiting based on JWT tokens. This guide shows you how!

🎯 What You'll Need

βœ“ AWS account with proper permissions
βœ“ Basic knowledge of Lambda, CloudFront, and JWT
βœ“ Your favorite code editor

πŸ’‘ JWT Token Structure

Sample JWT token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCIsInRva2VuIjoiYWJjZGVmZzEyMyJ9
Decoding the above will result the below output: { "alg": "HS256", "typ": "JWT", "token": "abcdefg123" }
Note: Token may contain multiple fields including the timestamp and singed signature. If the JWT token is constant and change only one value for each user then using Text-transform of Base64 extension and create a rate-based rule using custom key (ie., Text transform: Base64 decode extension) would the option.

πŸ› οΈ Super Quick Setup

πŸš€ Implementation Steps

1️⃣ IAM Setup

  • πŸ‘€ Create IAM Role with Trust Relationship

2️⃣ Lambda Function Setup

  • πŸ“ Name: Any name as per your reference
  • βš™οΈ Runtime: Python 3.9
  • πŸ’» Architecture: x86_64
  • Add Trust Relationship IAM role

3️⃣ Lambda Magic ✨

  • Create a code to decode JWT header and Add a X-Token header when forwarding to Origin.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import json
import base64
from typing import Dict, Any

# Constants
HEADER_NAME = 'X-Token' # Header name for the token value

def decode_jwt_header(token: str) -> Dict[str, Any]:
"""
Decode the JWT header and extract token information.

Args:
token (str): JWT token string

Returns:
Dict[str, Any]: Decoded JWT header data

Raises:
Exception: If token decoding fails
"""

try:
# Remove 'Bearer ' prefix if present
if token.startswith('Bearer '):
token = token.split(' ')[1]

# Extract and decode header segment
header_segment = token.split('.')[0]
padding = '=' * (4 - (len(header_segment) % 4))
decoded_header = base64.urlsafe_b64decode(header_segment + padding)

return json.loads(decoded_header)
except Exception as e:
raise Exception(f"Error decoding JWT header: {str(e)}")

def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
"""
AWS Lambda handler to process CloudFront requests and add X-Token header.

Args:
event (Dict[str, Any]): Lambda event object
context (Any): Lambda context object

Returns:
Dict[str, Any]: Modified request object
"""

try:
request = event['Records'][0]['cf']['request']
headers = request['headers']

# Return unmodified request if no authorization header
if 'authorization' not in headers:
return request

# Process authorization header
auth_header = headers['authorization'][0]['value']
decoded_header = decode_jwt_header(auth_header)

# Add X-Token header if token exists in decoded header
if 'token' in decoded_header:
request['headers'][HEADER_NAME.lower()] = [{
'key': HEADER_NAME,
'value': str(decoded_header['token'])
}]
print(f"Successfully added {HEADER_NAME}: {decoded_header['token']}")

# Clean up headers by removing CloudFront-Viewer details
headers_to_remove = [
header for header in headers
if header.startswith('cloudfront-viewer-')
]
for header in headers_to_remove:
headers.pop(header, None)

return request

except Exception as e:
print(f"Error processing request: {str(e)}")
return event['Records'][0]['cf']['request'] # Return original request on error


4️⃣ CloudFront Configuration

  • Create a origin and behavior
  • Add Lambda Function Association to the behavior.
  • Event Type: Origin Request

5️⃣ WAF Rule Configuration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
"Name": "JWT-Rate-Based",
"Priority": 0,
"Statement": {
"RateBasedStatement": {
"Limit": 10,
"EvaluationWindowSec": 300,
"AggregateKeyType": "CUSTOM_KEYS",
"CustomKeys": [
{
"Header": {
"Name": "X-Token",
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
]
}
}
]
}
},
"Action": {
"Block": {}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": true,
"MetricName": "JWT-Rate-Based"
}
}
πŸ§ͺ Test It Out:
curl -H "Authorization: Bearer JWT_TOKEN" https://[your-cloudfront]/path

πŸ’‘ Pro Tip

For constant JWT tokens with single varying value, use Base64 decode text transformation in your rate-based rule! (ie., Text transform: Base64 decode extension).
Any opinions in this article are those of the individual author and may not reflect the opinions of AWS.
Enjoyed reading this content? Let the author know!

Your likes, comments, shares, and saves help creators reach more builders.

Loading recommendations

Loading article