'Presigned PUT works from PostMan, but 403 Forbidden from C# HttpClient
I have generated a pre-signed url from S3 using the following .Net code (in a service that has the appropriate IAM role/permission for the bucket)
var key = GenerateKey(jobId, batchId);
var linkExpiresAt = _dateTimeService.Now().AddMinutes(_expiryTime);
var request = new GetPreSignedUrlRequest
{
BucketName = _bucketName,
Key = key,
Verb = HttpVerb.PUT,
ContentType = "application/json",
Expires = linkExpiresAt,
ServerSideEncryptionMethod = ServerSideEncryptionMethod.None
};
var url = _s3Client.GetPreSignedURL(request);
I can use this url in Postman to do a PUT with content 'JSON', but when I try to use it from code, I get 403
var content = new StringContent(mooStr, Encoding.ASCII, "application/json");
var fileStreamResponse = await httpClient.PutAsync(
url,
content);
Is there anything that stands out as wrong with the .Net attempt to PUT to the url?
Solution 1:[1]
If anyone comes across the same issue, I found the solution.
When I ran Fiddler, I captured the successful request from Postman and the failing request from .Net code. The only difference I could spot was that the successful one had this header (I'd changed to text/plain since my first post, but the problem remained):-
Content-Type: text/plain
and the failing one from .Net had:-
Content-Type: text/plain; charset=utf-8
A bit of a search around StackOverflow found me these posts
How to remove charset=utf8 from Content-Type header generated by HttpClient.PostAsJsonAsync()?
How do I not exclude charset in Content-Type when using HttpClient?
I edited the captured request in Fiddler and removed the charset and it worked. Altering my original code to the following worked (note - setting text/plain on the StringContent didn't work):-
var content = new StringContent(mooStr);
content.Headers.ContentType = MediaTypeHeaderValue.Parse("text/plain");
var fileStreamResponse = await httpClient.PutAsync(
Url,
content);
Solution 2:[2]
Following code worked for me (for posting a file of type IFormFile):
public async Task<bool> UploadObject(string preSignedUrl)
{
try
{
using (var client = new HttpClient())
{
StreamContent streamContent = new StreamContent(file.OpenReadStream());
var result = await client.PutAsync(preSignedUrl, streamContent);
if (result.StatusCode != HttpStatusCode.OK)
{
throw new Exception();
}
}
return true;
}
catch (Exception e)
{
....
}
return false;
}
Create the preSignedUrl with the IAmazonS3 package.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Pete Roberts |
| Solution 2 | Wouter |
