odysseyscience / react-s3-uploader

React component that renders an <input type="file"/> and automatically uploads to an S3 bucket

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Upload error: Upload error: 403

gastongouron opened this issue · comments

commented

Hello (and thank you very much for this awesome piece of code react-s3-uploader seems to be), I hope this is not a code related issue, otherwise i'm terribly sorry to waste anyone time:

The context:

  1. Rails API using aws-sdk through the 'aws-sdk', '~> 3' gem
  2. ReactJS client talking to amazon via the react-s3-uploader package

So everything seems to work flawlessly when I upload a file manually via rails, so I believe my rails setup is ok, it defines the following ENV vars to talk to amazon: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, S3_BUCKET.

The backend code is very minimal at this point but is supposed to do the trick for a simple upload test via react, this code is beeing called when the client hits the route /s3/signed_url with the filename as a parameter.

def sign
    filename = params["objectName"]
    content = params["contentType"]

    signer = Aws::S3::Presigner.new
    signed = signer.presigned_url(:put_object,
                     bucket: ENV['AWS_BUCKET'],
                     key: "uploads/#{filename}",
                     acl: 'public-read',
                     content_type: content)

    response.set_header('Access-Control-Allow-Origin', "http://localhost:3000") # as a test
    response.set_header('Access-Control-Allow-Credentials', "true") 
    render json: { signedUrl: signed }
end

On the client side, I use the following ReactS3Uploader:

 <ReactS3Uploader
            signingUrl={`/s3/presigned_url`}
            signingUrlMethod="GET"
            accept="image/*"
            s3path="/uploads"
            preprocess={this.onUploadStart}
            onSignedUrl={this.onSignedUrl}
            onProgress={this.onUploadProgress}
            onError={this.onUploadError}
            onFinish={this.onUploadFinish}
            signingUrlHeaders={ this.headers }
            signingUrlWithCredentials={ true } 
            uploadRequestHeaders={{ 'x-amz-acl': 'public-read' }}
            contentDisposition="auto"
            scrubFilename={(filename) => filename.replace(/[^\w\d_\-.]+/ig, '')}
            inputRef={cmp => this.uploadInput = cmp}
            autoUpload={true}
            /> 

So far the cinematic seems to work good as you can see with the console messages:

  • The user uploads a file
  • Rails in notified and contacts amazon
  • amazon replies with a signed url for the file to be uploaded via a PUT by client
  • Rails responds back to the client with a JSON payload such as signedUrl: the Url
  • The client works based on this response and does an OPTION call which results in 200
  • Wait for it...

the error

  • The clients does a ** PUT with the resource itself that results in a 403**.

screen shot 2018-10-22 at 07 17 45

When visiting the generated url which looks like: https://BUCKETNAME.s3.eu-west-3.amazonaws.com/download.jpeg?x-amz-acl=public-read&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=CREDENTIALSeu-west-3%2Fs3%2Faws4_request&X-Amz-Date=20181022T034739Z&X-Amz-Expires=900&X-Amz-SignedHeaders=content-type%3Bhost&X-Amz-Signature=8df65f77ade37bf3dfe0f3eb7de829d25b2f73e6316c5ee8b8b15f211dd9a817

I can see a detailed XML error message starting with:

<Error>
  <Code>SignatureDoesNotMatch</Code>
    <Message>
        The request signature we calculated does not match the signature you provided. Check your key and signing method.
    </Message>
     ...

At this point, (I'm stumbling on this 2 days now) I'm truly wondering if the problem lives on the client or server side. I truly believe the server is consistent in his response, signing the data with the correct credentials, filename parameters and path but I might be wrong... :) Since my latest investigations led me to doubt about clearness of amazon error messages in addition of being unsuccessful, I'm wondering if anyone have been facing a similar issue in a similar context (rails backend), and successfully went through it. Also, I'd happily provide more details if it's needed.

Thank you very much for your time <3

dupe; see comment on #191