Reputation: 911
I'm trying to give a temporary access to a service account that has only read permission to upload an mp3 to a Google Cloud Storage bucket.
For that, I'm generating a signedurl
but i can't get it to work.
What I'm doing to generate the URL and upload the file :
const config = {
action: 'write',
expires: '03-12-2019',
contentType: 'audio/mpeg'
}
const storage = new Storage({
projectId: projectId,
keyFilename: './service-account-key.json'
})
let bucketSubDirectory = storage.bucket(bucketName).file('subdirectory/in/bucket/' + songName)
bucketSubDirectory.getSignedUrl(config, (err, url) => {
if (err) {
console.error(err)
return
}
console.log(url)
// The file is now available to be written to.
let writeStream = request.put(url, {
headers: {
'Content-Type': 'audio/mpeg'
}
})
writeStream.end('New data');
writeStream.on('complete', function (resp) {
console.log(resp.statusCode + " " + resp.statusMessage)
})
})
When I execute the script I get a 403 forbidden
response and when I try to access the generated URL from the browser I get the following :
<Error>
<Code>MalformedSecurityHeader</Code>
<Message>Your request has a malformed header.</Message><ParameterName>signature</ParameterName>
<Details>Signature was not base64 encoded</Details>
</Error>
Any idea how can I solve this problem?
Upvotes: 2
Views: 4427
Reputation: 3166
According to the node.js client library documentation, the method getSignedUrl
has a parameter config
which as a parameter contentType
:
contentType
Optional
string
If you provide this value, the client must provide this HTTP header set to the same value.
So you might need to modify your PUT
request to include this header with the value contentType: audio/mpeg
.
Also, if you enter the url in the browser you are not doing a PUT
request but a GET
one.
EDIT:
Also check that your service account which creates the signedurl
has the right permissions granted. For the code your are running you need at least the roles/storage.objectAdmin
role. To grant it:
gcloud projects add-iam-policy-binding yourProjectID --member yourServiceAccount --role "roles/storage.objectAdmin"
Once this is done, users will be able to write to the file with just a PUT
request to the url.
const request = require('request');
let url = 'yourSignedURL'
let writeStream = request.put(url, {
headers: {
'Content-Type': 'audio/mpeg'
}
})
writeStream.end('New data');
writeStream.on('complete', function (resp) {
console.log(resp.statusCode + " " + resp.statusMessage)
})
Upvotes: 2