I have a code which uses aws-amplify and authenticates.
Code:
signRequest(host: any, path: any, method: any, accessKey: any, secretKey: any, region: any, service: any) {
const amzDate = this.getAmzDate();
const dateStamp = this.getDate(); // Prepare canonical request
const canonicalURI = path;
const canonicalQueryString = '';
const canonicalHeaders = `host:${host}\n` + `x-amz-date:${amzDate}\n`;
const signedHeaders = 'host;x-amz-date';
const payloadHash = CryptoJS.SHA256('').toString(CryptoJS.enc.Hex);
const canonicalRequest = `${method}\n${canonicalURI}\n${canonicalQueryString}\n${canonicalHeaders}\n${signedHeaders}\n${payloadHash}`;
console.log("Canonical Request:", canonicalRequest);
// String to sign
const algorithm = 'AWS4-HMAC-SHA256';
const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
const stringToSign = `${algorithm}\n${amzDate}\n${credentialScope}\n${CryptoJS.SHA256(canonicalRequest).toString(CryptoJS.enc.Hex)}`;
console.log("String to Sign:", stringToSign);
// Signature
const signingKey = this.getSignatureKey(secretKey, dateStamp, region, service);
const signature = CryptoJS.HmacSHA256(stringToSign, signingKey).toString(CryptoJS.enc.Hex);
console.log("Calculated Signature:", signature);
// Authorization header
const authorizationHeader = `${algorithm} Credential=${accessKey}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${signature}`;
console.log("authorization success",authorizationHeader)
return {
'Content-Type': 'text/plain',
'x-amz-date': amzDate,
'Authorization': authorizationHeader
// 'x-amz-security-token': sessionToken // Optional, if using session-based access
};
}
getSignatureKey(key: string, dateStamp: string | CryptoJS.lib.WordArray, region: string | CryptoJS.lib.WordArray, service: string | CryptoJS.lib.WordArray) {
const kDate = CryptoJS.HmacSHA256(dateStamp, "AWS4" + key);
const kRegion = CryptoJS.HmacSHA256(region, kDate);
const kService = CryptoJS.HmacSHA256(service, kRegion);
const kSigning = CryptoJS.HmacSHA256("aws4_request", kService);
console.log("k signing key",kSigning)
console.log("get Signature key:", this.getSignatureKey);
return kSigning;
// Define your AWS and API details
host = 'https://2ydk2p26dbv2ak5fygphvcb6ey0dzrzm.lambda-url.us-east-1.on.aws/';
path = '/';
method = 'POST';
region = 'us-east-1';
service = 'lambda';
accessKey = '****';
secretKey = '****';
// sessionToken = ''; // Generate signed headers
new_headers = this.signRequest(this.host, this.path, this.method, this.accessKey, this.secretKey,this.region, this.service);
When I run that, I get this error:
Access to XMLHttpRequest at 'https://2ydk2p26dbv2ak5fygphvcb6ey0dzrzm.lambda-url.us-east-1.on.aws/' from origin 'https://function-url-ver2-1.d2qo24bmjgejow.amplifyapp.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
What should I change to make it?
The issue is that your lambda is not sending CORS(Cross origin resource sharing) headers as a response to the preflight(OPTIONS) call done by your browser. You can read more about the exact rules of CORS here(https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS).
You can setup a cors configuration in the lambda console, if you are using cdk to deploy the function url it is a field in the props, if you're using plain cloudformation it's a field in the function url config too.
https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-url.html
https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda.FunctionUrl.html
You will need to add at least an allowed origin, if you want to allow all origins you can use *
You will probably also need to add the allowed Http Methods and headers you are sending with the request.
A different solution would be to also make this lambda function url available through the same cloudfront distribution as your amplify app. They would have the same host and not require CORS