Error with signed writable URL: The request signature we calculated does not match the signature you provided
I'm uploading a dummy file to Google Cloud Storage, and then signing a read/write URL before passing it to another service hosted separately. Unfortunately, I'm receiving a 403 response, with the message:
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
The code I'm using to create the dummy object and sign the URL:
const string BASE64_JSON_CREDS = "UklQIFN0YW4gTGVl"; // credentials of service account with "Storage Admin" role (entire json file as received from Google's Console)
const string BUCKET = "testbucket";
const string FILENAME = "test.jpg";
byte imageBytes = File.ReadAllBytes(@"test.jpg");
GoogleCredential credentials = null;
using (var stream = new MemoryStream(Convert.FromBase64String(BASE64_JSON_CREDS)))
{
credentials = GoogleCredential.FromStream(stream);
}
StorageClient storageClient = StorageClient.Create(credentials);
var bucket = await storageClient.GetBucketAsync(BUCKET);
await storageClient.UploadObjectAsync(bucket.Name, FILENAME, null, new MemoryStream());
var scopedCreds = credentials.CreateScoped("https://www.googleapis.com/auth/devstorage.read_write").UnderlyingCredential as ServiceAccountCredential;
var urlSigner = UrlSigner.FromServiceAccountCredential(scopedCreds);
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100));
Some test code I've written for the sake of this question (I've also tried HttpWebRequest
):
var handler = new HttpClientHandler()
{
// Proxy = new WebProxy("localhost", 8888)
};
var client = new HttpClient(handler);
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.Remove("Content-Type");
var response = await client.PutAsync(url, content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("yay");
}
else
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
Console.ReadKey();
When proxied through Fiddler, the request looks like this:
PUT https://storage.googleapis.com/testbucket/test.jpg?GoogleAccessId=testbucket@testproject.iam.gserviceaccount.com&Expires=1543209340&Signature=j1cagZ9MHZQAIeYrzbm95MWsIdFMvX1Em13il%2F2nEB1qx9xGB6%2BUzt6vo2OVuRp2TlW1G1TtyX32lxbH%2Fb51dr49eFBcSSm9H8rSXtuEXci02dY%2Fe%2FV0n4kpVwDjpiq4QVSMM%2BaCEdrUtPxT69BSoDuRqh6UHkeOL6VqLgcHGKQcXraZCrEaCXCJfNBwBlPcoXzOD708Nasl99ahxGwcPY6s1FXLCiAiP0VDJSRrPqbE8LHyRLLTgCk9r2H4pEW%2BpGpjEWj3DVpDC334%2BQQFttzDNuZQnUMtZi%2BGz5rqQbU5hBLgthb%2B13884uL4eUalnoSuRfR9JPKIJP7xk3%2FH4g%3D%3D HTTP/1.1
Content-Length: 21925
Host: storage.googleapis.com
{IMAGE_CONTENT}
And the response is:
HTTP/1.1 403 Forbidden
X-GUploader-UploadID: AEnB2UoklkZmIP8odWSx14Y0ZDgxjM8ZM94SCfNgAONG1giFTd9cncH8bAMK3s7I7v2DC1NwVirOrNbTjnBzdS2o1tOGX2pLBg
Content-Type: application/xml; charset=UTF-8
Content-Length: 314
Date: Thu, 22 Nov 2018 01:15:39 GMT
Server: UploadServer
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>PUT
1543209340
/testbucket/test.jpg</StringToSign></Error>
Looking at Google's UrlSigner code, the lines listed above are:
var signatureLines = new List<string>
{
requestMethod.ToString(),
contentMD5,
contentType,
expiryUnixSeconds
};
I found suggestion in this question that the Content-Type
header does need to be set, so I made the following changes:
// New signing code
var headers = new Dictionary<string, IEnumerable<string>>() { { "Content-Type", new string { "image/jpeg" } } };
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), requestHeaders: headers);
// New put code (I removed the line removing Content-Type)
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
but this hasn't fixed things. The new "StringToSign" value reflects the change:
PUT
image/jpeg
1543214247
/teams-storage-test-bucket/test.jpg
So the headers it should (to my mind) be checking for are correct vs what's being sent. The generated URL works for GET (I can download the empty file), but not for the PUT. Is there a solution?
c# google-cloud-platform google-cloud-storage pre-signed-url
add a comment |
I'm uploading a dummy file to Google Cloud Storage, and then signing a read/write URL before passing it to another service hosted separately. Unfortunately, I'm receiving a 403 response, with the message:
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
The code I'm using to create the dummy object and sign the URL:
const string BASE64_JSON_CREDS = "UklQIFN0YW4gTGVl"; // credentials of service account with "Storage Admin" role (entire json file as received from Google's Console)
const string BUCKET = "testbucket";
const string FILENAME = "test.jpg";
byte imageBytes = File.ReadAllBytes(@"test.jpg");
GoogleCredential credentials = null;
using (var stream = new MemoryStream(Convert.FromBase64String(BASE64_JSON_CREDS)))
{
credentials = GoogleCredential.FromStream(stream);
}
StorageClient storageClient = StorageClient.Create(credentials);
var bucket = await storageClient.GetBucketAsync(BUCKET);
await storageClient.UploadObjectAsync(bucket.Name, FILENAME, null, new MemoryStream());
var scopedCreds = credentials.CreateScoped("https://www.googleapis.com/auth/devstorage.read_write").UnderlyingCredential as ServiceAccountCredential;
var urlSigner = UrlSigner.FromServiceAccountCredential(scopedCreds);
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100));
Some test code I've written for the sake of this question (I've also tried HttpWebRequest
):
var handler = new HttpClientHandler()
{
// Proxy = new WebProxy("localhost", 8888)
};
var client = new HttpClient(handler);
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.Remove("Content-Type");
var response = await client.PutAsync(url, content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("yay");
}
else
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
Console.ReadKey();
When proxied through Fiddler, the request looks like this:
PUT https://storage.googleapis.com/testbucket/test.jpg?GoogleAccessId=testbucket@testproject.iam.gserviceaccount.com&Expires=1543209340&Signature=j1cagZ9MHZQAIeYrzbm95MWsIdFMvX1Em13il%2F2nEB1qx9xGB6%2BUzt6vo2OVuRp2TlW1G1TtyX32lxbH%2Fb51dr49eFBcSSm9H8rSXtuEXci02dY%2Fe%2FV0n4kpVwDjpiq4QVSMM%2BaCEdrUtPxT69BSoDuRqh6UHkeOL6VqLgcHGKQcXraZCrEaCXCJfNBwBlPcoXzOD708Nasl99ahxGwcPY6s1FXLCiAiP0VDJSRrPqbE8LHyRLLTgCk9r2H4pEW%2BpGpjEWj3DVpDC334%2BQQFttzDNuZQnUMtZi%2BGz5rqQbU5hBLgthb%2B13884uL4eUalnoSuRfR9JPKIJP7xk3%2FH4g%3D%3D HTTP/1.1
Content-Length: 21925
Host: storage.googleapis.com
{IMAGE_CONTENT}
And the response is:
HTTP/1.1 403 Forbidden
X-GUploader-UploadID: AEnB2UoklkZmIP8odWSx14Y0ZDgxjM8ZM94SCfNgAONG1giFTd9cncH8bAMK3s7I7v2DC1NwVirOrNbTjnBzdS2o1tOGX2pLBg
Content-Type: application/xml; charset=UTF-8
Content-Length: 314
Date: Thu, 22 Nov 2018 01:15:39 GMT
Server: UploadServer
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>PUT
1543209340
/testbucket/test.jpg</StringToSign></Error>
Looking at Google's UrlSigner code, the lines listed above are:
var signatureLines = new List<string>
{
requestMethod.ToString(),
contentMD5,
contentType,
expiryUnixSeconds
};
I found suggestion in this question that the Content-Type
header does need to be set, so I made the following changes:
// New signing code
var headers = new Dictionary<string, IEnumerable<string>>() { { "Content-Type", new string { "image/jpeg" } } };
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), requestHeaders: headers);
// New put code (I removed the line removing Content-Type)
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
but this hasn't fixed things. The new "StringToSign" value reflects the change:
PUT
image/jpeg
1543214247
/teams-storage-test-bucket/test.jpg
So the headers it should (to my mind) be checking for are correct vs what's being sent. The generated URL works for GET (I can download the empty file), but not for the PUT. Is there a solution?
c# google-cloud-platform google-cloud-storage pre-signed-url
For your line that is loading the credentials are you loading the entire json file base64 encoded or just part of it:const string BASE64_JSON_CREDS=
. To create credentials correctly you need both theclient_email
andprivate_key
which are included in the credentials json file.
– John Hanley
Nov 22 '18 at 4:01
@John The entire file as received from Google. The same credentials are allowing me to upload files, download files, and delete files via theServiceClient
and, also allowing me create resumable uploads (via REST API because I need an Angular web front-end to perform the upload).
– John
Nov 22 '18 at 4:08
You need to specify the HTTP method and headers in your calll tourlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
– John Hanley
Nov 22 '18 at 4:22
@John Can you add that as an answer so that I can accept my humiliation and give you the upvotes you deserve? :-) I naively assumed (not looking at the overloads carefully enough) that specifying the scope was the equivalent of specifying the verb for S3, etc.
– John
Nov 22 '18 at 4:25
add a comment |
I'm uploading a dummy file to Google Cloud Storage, and then signing a read/write URL before passing it to another service hosted separately. Unfortunately, I'm receiving a 403 response, with the message:
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
The code I'm using to create the dummy object and sign the URL:
const string BASE64_JSON_CREDS = "UklQIFN0YW4gTGVl"; // credentials of service account with "Storage Admin" role (entire json file as received from Google's Console)
const string BUCKET = "testbucket";
const string FILENAME = "test.jpg";
byte imageBytes = File.ReadAllBytes(@"test.jpg");
GoogleCredential credentials = null;
using (var stream = new MemoryStream(Convert.FromBase64String(BASE64_JSON_CREDS)))
{
credentials = GoogleCredential.FromStream(stream);
}
StorageClient storageClient = StorageClient.Create(credentials);
var bucket = await storageClient.GetBucketAsync(BUCKET);
await storageClient.UploadObjectAsync(bucket.Name, FILENAME, null, new MemoryStream());
var scopedCreds = credentials.CreateScoped("https://www.googleapis.com/auth/devstorage.read_write").UnderlyingCredential as ServiceAccountCredential;
var urlSigner = UrlSigner.FromServiceAccountCredential(scopedCreds);
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100));
Some test code I've written for the sake of this question (I've also tried HttpWebRequest
):
var handler = new HttpClientHandler()
{
// Proxy = new WebProxy("localhost", 8888)
};
var client = new HttpClient(handler);
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.Remove("Content-Type");
var response = await client.PutAsync(url, content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("yay");
}
else
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
Console.ReadKey();
When proxied through Fiddler, the request looks like this:
PUT https://storage.googleapis.com/testbucket/test.jpg?GoogleAccessId=testbucket@testproject.iam.gserviceaccount.com&Expires=1543209340&Signature=j1cagZ9MHZQAIeYrzbm95MWsIdFMvX1Em13il%2F2nEB1qx9xGB6%2BUzt6vo2OVuRp2TlW1G1TtyX32lxbH%2Fb51dr49eFBcSSm9H8rSXtuEXci02dY%2Fe%2FV0n4kpVwDjpiq4QVSMM%2BaCEdrUtPxT69BSoDuRqh6UHkeOL6VqLgcHGKQcXraZCrEaCXCJfNBwBlPcoXzOD708Nasl99ahxGwcPY6s1FXLCiAiP0VDJSRrPqbE8LHyRLLTgCk9r2H4pEW%2BpGpjEWj3DVpDC334%2BQQFttzDNuZQnUMtZi%2BGz5rqQbU5hBLgthb%2B13884uL4eUalnoSuRfR9JPKIJP7xk3%2FH4g%3D%3D HTTP/1.1
Content-Length: 21925
Host: storage.googleapis.com
{IMAGE_CONTENT}
And the response is:
HTTP/1.1 403 Forbidden
X-GUploader-UploadID: AEnB2UoklkZmIP8odWSx14Y0ZDgxjM8ZM94SCfNgAONG1giFTd9cncH8bAMK3s7I7v2DC1NwVirOrNbTjnBzdS2o1tOGX2pLBg
Content-Type: application/xml; charset=UTF-8
Content-Length: 314
Date: Thu, 22 Nov 2018 01:15:39 GMT
Server: UploadServer
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>PUT
1543209340
/testbucket/test.jpg</StringToSign></Error>
Looking at Google's UrlSigner code, the lines listed above are:
var signatureLines = new List<string>
{
requestMethod.ToString(),
contentMD5,
contentType,
expiryUnixSeconds
};
I found suggestion in this question that the Content-Type
header does need to be set, so I made the following changes:
// New signing code
var headers = new Dictionary<string, IEnumerable<string>>() { { "Content-Type", new string { "image/jpeg" } } };
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), requestHeaders: headers);
// New put code (I removed the line removing Content-Type)
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
but this hasn't fixed things. The new "StringToSign" value reflects the change:
PUT
image/jpeg
1543214247
/teams-storage-test-bucket/test.jpg
So the headers it should (to my mind) be checking for are correct vs what's being sent. The generated URL works for GET (I can download the empty file), but not for the PUT. Is there a solution?
c# google-cloud-platform google-cloud-storage pre-signed-url
I'm uploading a dummy file to Google Cloud Storage, and then signing a read/write URL before passing it to another service hosted separately. Unfortunately, I'm receiving a 403 response, with the message:
The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.
The code I'm using to create the dummy object and sign the URL:
const string BASE64_JSON_CREDS = "UklQIFN0YW4gTGVl"; // credentials of service account with "Storage Admin" role (entire json file as received from Google's Console)
const string BUCKET = "testbucket";
const string FILENAME = "test.jpg";
byte imageBytes = File.ReadAllBytes(@"test.jpg");
GoogleCredential credentials = null;
using (var stream = new MemoryStream(Convert.FromBase64String(BASE64_JSON_CREDS)))
{
credentials = GoogleCredential.FromStream(stream);
}
StorageClient storageClient = StorageClient.Create(credentials);
var bucket = await storageClient.GetBucketAsync(BUCKET);
await storageClient.UploadObjectAsync(bucket.Name, FILENAME, null, new MemoryStream());
var scopedCreds = credentials.CreateScoped("https://www.googleapis.com/auth/devstorage.read_write").UnderlyingCredential as ServiceAccountCredential;
var urlSigner = UrlSigner.FromServiceAccountCredential(scopedCreds);
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100));
Some test code I've written for the sake of this question (I've also tried HttpWebRequest
):
var handler = new HttpClientHandler()
{
// Proxy = new WebProxy("localhost", 8888)
};
var client = new HttpClient(handler);
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.Remove("Content-Type");
var response = await client.PutAsync(url, content);
if (response.IsSuccessStatusCode)
{
Console.WriteLine("yay");
}
else
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
}
Console.ReadKey();
When proxied through Fiddler, the request looks like this:
PUT https://storage.googleapis.com/testbucket/test.jpg?GoogleAccessId=testbucket@testproject.iam.gserviceaccount.com&Expires=1543209340&Signature=j1cagZ9MHZQAIeYrzbm95MWsIdFMvX1Em13il%2F2nEB1qx9xGB6%2BUzt6vo2OVuRp2TlW1G1TtyX32lxbH%2Fb51dr49eFBcSSm9H8rSXtuEXci02dY%2Fe%2FV0n4kpVwDjpiq4QVSMM%2BaCEdrUtPxT69BSoDuRqh6UHkeOL6VqLgcHGKQcXraZCrEaCXCJfNBwBlPcoXzOD708Nasl99ahxGwcPY6s1FXLCiAiP0VDJSRrPqbE8LHyRLLTgCk9r2H4pEW%2BpGpjEWj3DVpDC334%2BQQFttzDNuZQnUMtZi%2BGz5rqQbU5hBLgthb%2B13884uL4eUalnoSuRfR9JPKIJP7xk3%2FH4g%3D%3D HTTP/1.1
Content-Length: 21925
Host: storage.googleapis.com
{IMAGE_CONTENT}
And the response is:
HTTP/1.1 403 Forbidden
X-GUploader-UploadID: AEnB2UoklkZmIP8odWSx14Y0ZDgxjM8ZM94SCfNgAONG1giFTd9cncH8bAMK3s7I7v2DC1NwVirOrNbTjnBzdS2o1tOGX2pLBg
Content-Type: application/xml; charset=UTF-8
Content-Length: 314
Date: Thu, 22 Nov 2018 01:15:39 GMT
Server: UploadServer
Alt-Svc: quic=":443"; ma=2592000; v="44,43,39,35"
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>PUT
1543209340
/testbucket/test.jpg</StringToSign></Error>
Looking at Google's UrlSigner code, the lines listed above are:
var signatureLines = new List<string>
{
requestMethod.ToString(),
contentMD5,
contentType,
expiryUnixSeconds
};
I found suggestion in this question that the Content-Type
header does need to be set, so I made the following changes:
// New signing code
var headers = new Dictionary<string, IEnumerable<string>>() { { "Content-Type", new string { "image/jpeg" } } };
var url = urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), requestHeaders: headers);
// New put code (I removed the line removing Content-Type)
var content = new ByteArrayContent(imageBytes, 0, imageBytes.Length);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/jpeg");
but this hasn't fixed things. The new "StringToSign" value reflects the change:
PUT
image/jpeg
1543214247
/teams-storage-test-bucket/test.jpg
So the headers it should (to my mind) be checking for are correct vs what's being sent. The generated URL works for GET (I can download the empty file), but not for the PUT. Is there a solution?
c# google-cloud-platform google-cloud-storage pre-signed-url
c# google-cloud-platform google-cloud-storage pre-signed-url
edited Nov 22 '18 at 4:09
John
asked Nov 22 '18 at 1:24
JohnJohn
11.9k32038
11.9k32038
For your line that is loading the credentials are you loading the entire json file base64 encoded or just part of it:const string BASE64_JSON_CREDS=
. To create credentials correctly you need both theclient_email
andprivate_key
which are included in the credentials json file.
– John Hanley
Nov 22 '18 at 4:01
@John The entire file as received from Google. The same credentials are allowing me to upload files, download files, and delete files via theServiceClient
and, also allowing me create resumable uploads (via REST API because I need an Angular web front-end to perform the upload).
– John
Nov 22 '18 at 4:08
You need to specify the HTTP method and headers in your calll tourlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
– John Hanley
Nov 22 '18 at 4:22
@John Can you add that as an answer so that I can accept my humiliation and give you the upvotes you deserve? :-) I naively assumed (not looking at the overloads carefully enough) that specifying the scope was the equivalent of specifying the verb for S3, etc.
– John
Nov 22 '18 at 4:25
add a comment |
For your line that is loading the credentials are you loading the entire json file base64 encoded or just part of it:const string BASE64_JSON_CREDS=
. To create credentials correctly you need both theclient_email
andprivate_key
which are included in the credentials json file.
– John Hanley
Nov 22 '18 at 4:01
@John The entire file as received from Google. The same credentials are allowing me to upload files, download files, and delete files via theServiceClient
and, also allowing me create resumable uploads (via REST API because I need an Angular web front-end to perform the upload).
– John
Nov 22 '18 at 4:08
You need to specify the HTTP method and headers in your calll tourlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
– John Hanley
Nov 22 '18 at 4:22
@John Can you add that as an answer so that I can accept my humiliation and give you the upvotes you deserve? :-) I naively assumed (not looking at the overloads carefully enough) that specifying the scope was the equivalent of specifying the verb for S3, etc.
– John
Nov 22 '18 at 4:25
For your line that is loading the credentials are you loading the entire json file base64 encoded or just part of it:
const string BASE64_JSON_CREDS=
. To create credentials correctly you need both the client_email
and private_key
which are included in the credentials json file.– John Hanley
Nov 22 '18 at 4:01
For your line that is loading the credentials are you loading the entire json file base64 encoded or just part of it:
const string BASE64_JSON_CREDS=
. To create credentials correctly you need both the client_email
and private_key
which are included in the credentials json file.– John Hanley
Nov 22 '18 at 4:01
@John The entire file as received from Google. The same credentials are allowing me to upload files, download files, and delete files via the
ServiceClient
and, also allowing me create resumable uploads (via REST API because I need an Angular web front-end to perform the upload).– John
Nov 22 '18 at 4:08
@John The entire file as received from Google. The same credentials are allowing me to upload files, download files, and delete files via the
ServiceClient
and, also allowing me create resumable uploads (via REST API because I need an Angular web front-end to perform the upload).– John
Nov 22 '18 at 4:08
You need to specify the HTTP method and headers in your calll to
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
– John Hanley
Nov 22 '18 at 4:22
You need to specify the HTTP method and headers in your calll to
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
– John Hanley
Nov 22 '18 at 4:22
@John Can you add that as an answer so that I can accept my humiliation and give you the upvotes you deserve? :-) I naively assumed (not looking at the overloads carefully enough) that specifying the scope was the equivalent of specifying the verb for S3, etc.
– John
Nov 22 '18 at 4:25
@John Can you add that as an answer so that I can accept my humiliation and give you the upvotes you deserve? :-) I naively assumed (not looking at the overloads carefully enough) that specifying the scope was the equivalent of specifying the verb for S3, etc.
– John
Nov 22 '18 at 4:25
add a comment |
1 Answer
1
active
oldest
votes
In your call to Sign()
include the HTTP Method and Content-Type headers:
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53422663%2ferror-with-signed-writable-url-the-request-signature-we-calculated-does-not-mat%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
In your call to Sign()
include the HTTP Method and Content-Type headers:
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
add a comment |
In your call to Sign()
include the HTTP Method and Content-Type headers:
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
add a comment |
In your call to Sign()
include the HTTP Method and Content-Type headers:
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
In your call to Sign()
include the HTTP Method and Content-Type headers:
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
answered Nov 22 '18 at 4:27
John HanleyJohn Hanley
14.8k2528
14.8k2528
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
add a comment |
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
I feel like an idiot now. Thank you for your assistance.
– John
Nov 22 '18 at 4:28
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
@John - There are so many APIs, signing methods, credentials, ...
– John Hanley
Nov 22 '18 at 4:29
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53422663%2ferror-with-signed-writable-url-the-request-signature-we-calculated-does-not-mat%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
For your line that is loading the credentials are you loading the entire json file base64 encoded or just part of it:
const string BASE64_JSON_CREDS=
. To create credentials correctly you need both theclient_email
andprivate_key
which are included in the credentials json file.– John Hanley
Nov 22 '18 at 4:01
@John The entire file as received from Google. The same credentials are allowing me to upload files, download files, and delete files via the
ServiceClient
and, also allowing me create resumable uploads (via REST API because I need an Angular web front-end to perform the upload).– John
Nov 22 '18 at 4:08
You need to specify the HTTP method and headers in your calll to
urlSigner.Sign(bucket.Name, FILENAME, TimeSpan.FromHours(100), HttpMethod.Put, contentHeaders: new Dictionary<string, IEnumerable<string>> { { "Content-Type", new { "image/jpeg" } } });
– John Hanley
Nov 22 '18 at 4:22
@John Can you add that as an answer so that I can accept my humiliation and give you the upvotes you deserve? :-) I naively assumed (not looking at the overloads carefully enough) that specifying the scope was the equivalent of specifying the verb for S3, etc.
– John
Nov 22 '18 at 4:25