I am trying to fetch a jpg image from AWS S3 Bucket using a HTTP GET request in React-Native.
So far I was following these 2 documentations from Amazon :
- https://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html
- https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-header-based-auth.html
Here is the logic I implemented so far. When my component render, I am doing the following :
import { Auth } from 'aws-amplify';
import Moment from 'moment';
import sha256 from 'crypto-js/sha256';
var CryptoJS = require("crypto-js");
...
Auth.currentCredentials()
.then(async credentials => {
let awsHost = 'https://myAwsHost.amazonaws.com'
let awsPath = '/public/pathToMyImage.jpg'
let accessKeyId = credentials.accessKeyId
let secretAccessKey = credentials.secretAccessKey
let sessionToken = credentials.sessionToken
let awsDate = Moment().utc().format("YYYYMMDD")
let awsRequestDateTime = Moment().utc().format("YYYYMMDD" + "T" + "HHmmss") + "Z"
let awsRegion = "myRegion"
let awsService = "s3"
let awsRequest = "aws4_request"
let awsAlgorithm = "AWS4-HMAC-SHA256"
let awsCredentialScope = awsDate + "/" + awsRegion + "/" + awsService + "/" + awsRequest
let awsHTTPRequestMethod = "GET"
let awsSignedHeaders = "host;x-amz-content-sha256;x-amz-date;x-amz-security-token"
let awsCanonicalURI = awsHost + awsPath
let awsCanonicalQueryString = ""
// Step 1
let canonicalRequest =
awsHTTPRequestMethod + '\n' +
awsCanonicalURI + '\n' +
awsCanonicalQueryString + '\n' +
"X-Amz-Content-Sha256".toLowerCase() + ":" + sha256("") + "\n" +
"X-Amz-Date".toLowerCase() + ":" + awsRequestDateTime.trim() + "\n" +
"X-Amz-Security-Token".toLowerCase() + ":" + sessionToken + "\n" +
awsSignedHeaders + '\n' +
sha256("")
// Step 2 :
let stringToSign =
awsAlgorithm + "\n" +
awsRequestDateTime + "\n" +
awsCredentialScope + "\n" +
sha256(canonicalRequest)
// Step 3 :
let kSecret = secretAccessKey
let kDate = CryptoJS.HmacSHA256("AWS4" + kSecret, awsDate)
let kRegion = CryptoJS.HmacSHA256(kDate, awsRegion)
let kService = CryptoJS.HmacSHA256(kRegion, awsService)
let kSigning = CryptoJS.HmacSHA256(kService, awsRequest).toString(CryptoJS.enc.Hex)
let awsSignature = CryptoJS.HmacSHA256(awsDerivedSignInKey, stringToSign).toString(CryptoJS.enc.Hex)
let awsAuthorization = awsAlgorithm + " Credential=" + accessKeyId + "/" + awsCredentialScope + ", SignedHeaders=" + awsSignedHeaders + ", Signature=" + awsSignature
// Fetching the image with an HTTP GET request to AWS S3 Buckets
try {
await fetch(
awsCanonicalURI,
{
headers: {
'X-Amz-Security-Token': sessionToken,
'X-Amz-Content-Sha256': sha256("").toString(),
'X-Amz-Date': awsRequestDateTime,
'Authorization': awsAuthorization
},
}
).then(res => {
console.log("HTML status : " + res.status) // Status return : Error 403
});
} catch (error) {
console.error(error);
}
})
}
When I am trying to execute the same GET request with postman it work's and it retrieve the image from AWS S3 Buckets. The only difference between my request and the one generated by postman is the Signature.
I know that I can fetch images from S3Image
component from aws-amplify-react-native
but it is not what I am trying to achieve.
Main goal
Finally, I am looking to execute those HTTP GET Request's in order to use them in FastImage
from the module react-native-fast-image
and use it in order to cache easely images in my react-native application.
If anyone has an answer to my problem or a better alternative to what I am trying to achieve, be my guest!!