Upload error: Upload error: 403
gastongouron opened this issue · comments
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:
- Rails API using aws-sdk through the
'aws-sdk', '~> 3'
gem - 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**.
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