CORS (Cross-Origin Resource Sharing) is a security feature that restricts web pages from making requests to a different domain than the one serving the web page.
When your React frontend (hosted on Amplify) calls your API Gateway, the browser checks CORS headers to determine if the request is allowed.
Ensure all Lambda functions return proper CORS headers:
const corsHeaders = {
'Access-Control-Allow-Origin': '*', // Or specific domain
'Access-Control-Allow-Headers': 'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token',
'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS'
};
// In your handler response:
return {
statusCode: 200,
headers: corsHeaders,
body: JSON.stringify(data)
};
Method 1: Using Console
Method 2: Using OPTIONS Method
Access-Control-Allow-Headers: 'Content-Type,X-Amz-Date,Authorization,X-Api-Key'
Access-Control-Allow-Methods: 'GET,POST,OPTIONS'
Access-Control-Allow-Origin: '*'
3.1. Enable API Key (Optional)
daivietblood-api-key3.2. Enable Request Validation
{
"$schema": "http://json-schema.org/draft-04/schema#",
"title": "CreateUserModel",
"type": "object",
"required": ["email", "name", "blood_type"],
"properties": {
"email": { "type": "string", "format": "email" },
"name": { "type": "string", "minLength": 1 },
"blood_type": {
"type": "string",
"enum": ["A+", "A-", "B+", "B-", "AB+", "AB-", "O+", "O-"]
},
"phone": { "type": "string" }
}
}
3.3. Enable Throttling
prod4.1. Use AWS Secrets Manager for Credentials
Instead of storing DB credentials in environment variables:
Go to Secrets Manager → Store a new secret
Secret type: Other type of secret
Key/value pairs:
DB_HOST: daivietblood-db.xxxx.rds.amazonaws.com
DB_USER: admin
DB_PASSWORD: YourSecurePassword123!
DB_NAME: daivietblood
Secret name: daivietblood/db-credentials
Update Lambda to retrieve secrets:
const { SecretsManagerClient, GetSecretValueCommand } = require('@aws-sdk/client-secrets-manager');
const client = new SecretsManagerClient({ region: 'ap-southeast-1' });
const getDbCredentials = async () => {
const command = new GetSecretValueCommand({ SecretId: 'daivietblood/db-credentials' });
const response = await client.send(command);
return JSON.parse(response.SecretString);
};
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": "arn:aws:secretsmanager:ap-southeast-1:*:secret:daivietblood/*"
}
4.2. Input Validation
Always validate input in Lambda:
const validateUser = (body) => {
const errors = [];
if (!body.email || !isValidEmail(body.email)) {
errors.push('Invalid email');
}
if (!body.name || body.name.length < 1) {
errors.push('Name is required');
}
const validBloodTypes = ['A+', 'A-', 'B+', 'B-', 'AB+', 'AB-', 'O+', 'O-'];
if (!validBloodTypes.includes(body.blood_type)) {
errors.push('Invalid blood type');
}
return errors;
};
After making changes:
prod stage