Skip to content

Getting 403 Forbidden with presigned_post with Boto3

0

Better formatting in the Stackoverflow thread: https://stackoverflow.com/questions/68162325/getting-403-forbidden-when-trying-to-upload-file-to-aws-s3-with-presigned-post-u/68165136#68165136

I've tried researching other threads here on SO and other forums, but still can't overcome this issue. I'm generating a presigned post to S3 and trying to upload a file to it using these headers, but getting a 403: Forbidden.

Permissions The IAM user loaded in with Boto3 has permissions to list, read and write to S3.

CORS CORS from all origins and all headers are allowed

[
{
"AllowedHeaders": [
""
],
"AllowedMethods": [
"GET",
"HEAD",
"POST",
"PUT"
],
"AllowedOrigins": [
"
"
],
"ExposeHeaders": []
}
]
The code The code is based on Python in Django as well as Javascript. This is the logic:

First the file is retrieved from the HTML, and used to call a function for retrieving the signed URL.

(function () {
document.getElementById("file-input").onchange = function () {
let files = document.getElementById("file-input").files;
let file = files[0];
Object.defineProperty(file, "name", {
writeable: true,
value: ${uuidv4()}.pdf

    })  
    if (!file) {  
        return alert("No file selected");  
    }  
    getSignedRequest(file);  
}  

})();
Then a GET request is sent to retrieve the signed URL, using a Django view (described in the next section after this one)

function getSignedRequest(file) {
var xhr = new XMLHttpRequest();
xhr.open("GET", "/sign_s3?file_name=" _ file.name _ "&file_type=" + file.type)
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
let response = JSON.parse(xhr.responseText)
uploadFile(file, response.data, response.url)
}
else {
alert("Could not get signed URL")
}
}
};
xhr.send()
}
The Django view generating the signed URL

def Sign_s3(request):

S3_BUCKET = os.environ.get("BUCKET_NAME")  

if (request.method == "GET"):  
    file_name = request.GET.get('file_name')  
    file_type = request.GET.get('file_type')  
      
    s3 = boto3.client('s3', config = boto3.session.Config(signature_version = 's3v4'))  
      
    presigned_post = s3.generate_presigned_post(  
    Bucket = S3_BUCKET,  
    Key = file_name,  
    Fields = {"acl": "public-read", "Content-Type": file_type},  
    Conditions = \[  
    {"acl": "public-read"},  
    {"Content-Type": file_type}  
    ],  
    ExpiresIn = 3600  
)  


return JsonResponse({  
    "data": presigned_post,  
    "url": "https://%s.s3.amazonaws.com/%s" % (S3_BUCKET, file_name)  
})  

Finally the file should be uploaded to the bucket (this is where I'm getting the 403 error)

function uploadFile(file, s3Data, url) {
let xhr = new XMLHttpRequest();
xhr.open("POST", s3Data.url)

        let postData = new FormData()  
        for (key in s3Data.fields) {  
            postData.append(key, s3Data.fields\[key])  
        }  

        postData.append("file", file)  

        xhr.onreadystatechange = function () {  
            if (xhr.readyState === 4) {  
                if (xhr.status === 200 || xhr.status === 204) {  
                    document.getElementById("cv-url").value = url  
                }  
                else {  
                    alert("Could not upload file")  
                }  
            }  
        };  
        xhr.send(postData)  
    }  

The network request This is how the network request looks in the browser

Network request 1 Network request 2 Network request 3

Edited by: torrentfisken on Jun 28, 2021 7:49 AM

asked 5 years ago1K views
1 Answer
0

Had to give public access

answered 5 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.