Error with signed writable URL: The request signature we calculated does not match the signature you provided












0















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?










share|improve this question

























  • 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













  • 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


















0















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?










share|improve this question

























  • 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













  • 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
















0












0








0








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?










share|improve this question
















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






share|improve this question















share|improve this question













share|improve this question




share|improve this question








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 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













  • 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











  • @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 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 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







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







@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














1 Answer
1






active

oldest

votes


















3














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" } } });





share|improve this answer
























  • 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











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
});


}
});














draft saved

draft discarded


















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









3














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" } } });





share|improve this answer
























  • 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
















3














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" } } });





share|improve this answer
























  • 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














3












3








3







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" } } });





share|improve this answer













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" } } });






share|improve this answer












share|improve this answer



share|improve this answer










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



















  • 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


















draft saved

draft discarded




















































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.




draft saved


draft discarded














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





















































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







Popular posts from this blog

Wiesbaden

Marschland

Dieringhausen