How to upload images using postman to azure blob storage - azure

I have been trying to upload an image to my blob container folder using postman
Here is the link Authorization of Azure Storage service REST API am using to generate signature and am attaching filename file field in the body while body.
var key = "[Storage account key]";
var strTime = (new Date()).toUTCString();
var strToSign = 'PUT\n\nimage/jpeg; charset=UTF-8\n\nx-ms-date:' + strTime + '\nx-ms-meta-m1:v1\nx-ms-meta-m2:v2\n/colony7/folder-customer-profilepic/Home - explorar.jpg';
var secret = CryptoJS.enc.Base64.parse(key);
var hash = CryptoJS.HmacSHA256(strToSign, secret);
var hashInBase64 = CryptoJS.enc.Base64.stringify(hash);
var auth = "SharedKey colony7:"+hashInBase64;
I have used these https://learn.microsoft.com/en-us/rest/api/storageservices/put-block ,https://learn.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
references for above code.
I have turned on cors also. Kindly share the solution as to how would i upload a jpg or png image to my blob using postman.
Thanks in advance

If we want to upload an image to the azure storage, please have a try to use the Put blob API not Put block API.
And have a try to use the following strToSign.
"PUT\n\n\n{Content-Length}\n\n{Content-Type}\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:{date}\nx-ms-version:2015-12-11\n/accountname/container/blobname"
I test it on my side, it works correctly on site.
Headers :
Body:
Note: we could get the Content-Length from the file size.

Not really an answer to your question, but I see a number of issues that could cause this problem you're facing. Some of the issues I noticed are:
Request URL does not include the name of the file you're uploading. Your request URL should be https://colony7.blob.core.windows.net/folder-customer-profilepic/Home - explorar.jpg.
Content type request header is sent as image/jpg. However, in your stringToSign it is set as image/jpeg; charset=UTF-8. Both of them should exactly match.
Content length header is missing in stringToSign.
Based on the documentation here, your stringToSign corresponds to SharedKeyLite however when creating the authorization header, you are using SharedKey.
Your CanonicalizedHeaders does not include x-ms-version.
If you intend to use SharedKey, then your stringToSign should be constructed differently. Please see the documentation link you shared for more details.
Please fix these errors and update your question with the latest screenshots/values.

Method: PUT.
URL scheme:
(https://{{storageName}}.blob.core.windows.net/{{Container}}/{{ImageName.png}}?{{SAS Token}})
Headers:
"Content-Type": "image/png",
"Content-Length": "{{size in Bytes}}",
"x-ms-blob-type": "BlockBlob"
Body: select binary add image
(The image name should be same in the header and the URL.)

Related

Can I use HTML5 download attribute in anchor tag using an API (instead of direct link)?

I have a web page (served from, say, www.example.com domain after user logged in) that has following html element.
<a href="../api/values/import" download>Download Import File</a>
The import file is currently saved in a azure storage as a blob. Assume that the blob (i.e. import file) requires temporary SAS token (created for logged in user) to be accessed:
https://foo.blob.core.windows.net/myfiles/import.txt?(sasTokenInfo)
All of this can be simplified if the anchor tag can be used as shown below:
<a href="https://foo.blob.core.windows.net/myfiles/import.txt?(sasTokenInfo)" download>Download Import File</a>
However this runs the risk of expired sasTokenInfo before user clicks on it. The user may linger on this page (which has other info on it) sufficiently long enough for the sasToken to expire. The simplest thing to do here is to create sasToken for longer period. But I don't want to do that.
I am trying to find out if better solution is to use the API as shown at the beginning. When the user clicks on the above anchor link (i.e "../api/values/import"), the idea is to have this API create the blob sasToken for this user and send the link (that contains this sasToken) to the above blob storage import file. The idea is not to read this file in the above API but simply send the link to it so that browser can download it directly without involving the domain www.foo.com. To facilitate this, I thought if I can have the following header information, I would be able to force the browser to download this file directly from azure blob storage on the browser's machine:
Content-Disposition: attachment; filename="https://foo.blob.core.windows.net/myfiles/import.txt"
Apparently, the value of "filename" (from Content-Disposition header value) should not contain path info (See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition). This means I am not able to set the direct blob storage related link in this header value.
Questions:
Is the API route a viable option?
If yes, then how can I send a link to a file in the azure storage through my API to the browser so that browser can automatically download the file?
What do I need to do in my asp net core web API for (2)?
What do I need to do on the client-side html pages for (2)?
If yes, then how can I send a link to a file in the azure storage through my API to the browser so that browser can automatically download the file?
I suggest you could use ajax to let the web api to generate the blob url and then create the herf html to download it inside the succss method.
More details, you could refer to below codes:
Client ajax:
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
$.ajax({
url: 'https://localhost:7204/api/values/Download',
method: 'GET',
success: function (data) {
var link = document.createElement('a');
link.href = data;
link.download = 'myFile.txt'; // Set the file name here
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
error: function () {
console.log('Failed to download file.');
}
});
</script>
Web API:
[HttpGet("Download")]
public string GetUrl() {
return "https://localhost:7204/111.txt";
}
Result:
It will download the file automatically.

Model Derivative Forge API - Field uploadKey not found in signed URL endpoint

I was looking to play around with the Forge API and am trying to translate a rvt file into a dwg. I am just following the steps given in the "Step-by-Step" tutorials and this second step in Task 2
https://forge.autodesk.com/en/docs/model-derivative/v2/tutorials/translate-to-obj/task2-upload_source_file_to_oss/
says to make a post request to this endpoint to get the signed url https://developer.api.autodesk.com/oss/v2/buckets/<YOUR_BUCKET_KEY>/objects/<YOUR_OBJECT_KEY>/signeds3upload?minutesExpiration=<LIFESPAN_OF_URL>.
I make the request and receive a '{'reason': 'Field uploadKey not found'}'. Which in the steps, it shows you get the uploadKey from this endpoint ? So either I'm missing something really big here, or these steps are too smart for a 5 year old.
Here is what I'm passing into my post request:
header = {
'Authorization': 'Bearer ' + access_token,
'Content-Type': 'application/json'
}
body = {
'ossbucketKey': 'bucketName',
'ossSourceFileObjectKey': 'test.rvt',
'access': 'full',
'policyKey': 'transient'
}
Note that the new direct-to-s3 upload consists of multiple steps:
You generate an upload URL using the GET buckets/:bucketKey/objects/:objectKey/signeds3upload
You upload your data to the URL
You complete the upload using the POST buckets/:bucketKey/objects/:objectKey/signeds3upload endpoint you mentioned, incl. the uploadKey you received in step 1
For more details you can refer to this blog post: https://forge.autodesk.com/blog/data-management-oss-object-storage-service-migrating-direct-s3-approach.

INVALID_CONTENT_HASH error using Bittex API v3

I'm using Bittrex API v3. My header setup as below:
body = {
"marketSymbol":"BTC-USD",
"direction":"SELL",
"type":"LIMIT",
"quantity":"0.6",
"limit":"6000",
"timeInForce":"IMMEDIATE_OR_CANCEL"
}
var contentHash = CryptoJS.SHA512(JSON.stringify(body)).toString(CryptoJS.enc.Hex)
But I get INVALID_CONTENT_HASH.
If anyone can solve this problem, please let me know as soon as possible.
The v3 API is expecting the content to be hashed as json (which you're doing) but the payload must also be POSTed as json with the Content-Type accordingly set to application/json.
I ran into the same problem with the json being converted to a querystring on POST.

AWS Lambda fails to return PDF file

I have created a lambda function using serverless. This function is fired via API Gateway on a GET request and should return a pdf file from a buffer. I'm using html-pdf to create the buffer and trying to return the pdf file with the following command
let response = {
statusCode: 200,
headers: {'Content-type' : 'application/pdf'},
body: buffer.toString('base64'),
isBase64Encoded : true,
};
return callback(null, response);
but the browser is just failing to load the pdf, so I don't know exactly how to return the pdf file directly to the browser. Could'nt find a solution for that.
well, I found the answer.
The settings in my response object are fine, I just had to manually change the settings in API Gateway for this to work in the browser. I have added "*/*" to binary media types under the binary settings in API Gateway console
API GATEWAY
just log into your console
choose your api
click on binary support in the dropdown
edit binary media type and add "*/*"
FRONTEND
opening the api url in new tab (target="_blank"). Probably the browser is handling the encoded base 64 response, In my case with chrome, the browser just opens the pdf in a new tab exactly like I want it to do.
After spending several hours on this I found out that if you set Content handling to Convert to binary (CONVERT_TO_BINARY) the entire response has to be base64, I would otherwise get an error: Unable to base64 decode the body.
Therefore my response now looks like:
callback(null, buffer.toString('base64'));
The Integration response:
The Method response:
And Binary Media Types:
If you have a gigantic PDF, then it will take a long time for Lambda to return it and in Lambda you are billed per 100ms.
I would save it to S3 first then let the Lambda return the S3 url to the client for downloading.
I was having a similar issue where pdf where downloaded as base64 and started happening when changed the serverles.yml file from:
binaryMediaTypes:
- '*/*'
to
binaryMediaTypes:
- 'application/pdf'
- '....other media types'
The issue is because the way AWS implemented this feature. From aws documentation here:
When a request contains multiple media types in its Accept header, API
Gateway honors only the first Accept media type. If you can't control
the order of the Accept media types and the media type of your binary
content isn't the first in the list, add the first Accept media type
in the binaryMediaTypes list of your API. API Gateway handles all
content types in this list as binary.
Basically if the first media type contained in the accept request header is not in your list in binaryMediaTypes then you will get base64 back.
I checked the request in the browser and the first media type in the accept header was text/html so I got it working after changing my settings to:
binaryMediaTypes:
- 'application/pdf'
- '....other media types'
- 'text/html'
Hope this helps anyone with the same issue.
Above solution is only for particular content-type. You can't more content type.
Follow only below two-step to resolve multiple content type issue.
Click on the checkbox of Use Lambda Proxy integration
API gateway --> API --> method --> integration request
Create your response as
let response = {
statusCode: 200,
headers: {
'Content-type': 'application/pdf',//you can change any content type
'content-disposition': 'attachment; filename=test.pdf' // key of success
},
body: buffer.toString('base64'),
isBase64Encoded: true
};
return response;
Note* - It is not secure
Instead of doing all this. It's better to use serverless-apigw-binary plugin in your serverless.yaml file.
Add
plugins:
- serverless-apigw-binary
custom:
apigwBinary:
types:
- "application/pdf"
Hope that will help someone.

DocuSign Authorization Code Grant flow returns invalid_grant error

The DocuSign documentation goes through an easy to follow authorization flow for code grant. I'm able to get the "code" from the initial GET request to /oath/auth but getting the tokens gives me an error of "invalid_grant" when I try in postman. I've followed the steps and have a request that looks like this using account-d.docusign.com for host:
POST /oauth/token
Content-Type: application/x-www-form-urlencoded
Authorization: Basic MjMwNTQ2YTctOWM1NS00MGFkLThmYmYtYWYyMDVkNTQ5NGFkOjMwODc1NTVlLTBhMWMtNGFhOC1iMzI2LTY4MmM3YmYyNzZlOQ==
grant_type=authorization_code&code=ey2dj3nd.AAAA39djasd3.dkn4449d21d
Two other members of my team have also tried with their developer accounts and all are getting invalid_grant errors. Is this no longer supported or are there common errors associated with this error that we might be able to investigate?
Re-check all of your values.
I was also getting the same invalid_grant response and could not figure out why at first. It turns out that I had a typo in the Content-Type header. I was using application/x-www-form-urlencode instead of application/x-www-form-urlencoded.
You may not be, but if you are submitting the exact Authorization Header as you've posted it here in your question (MjMwNTQ2YTctOWM1NS00MGFkLThmYmYtYWYyMDVkNTQ5NGFkOjMwODc1NTVlLTBhMWMtNGFhOC1iMzI2LTY4MmM3YmYyNzZlOQ==) it will fail with that message.
That is the base64 value for the sample integration key and sample secret key provided in their documentation. If you decode that string with an online base64decoder it will result in 230546a7-9c55-40ad-8fbf-af205d5494ad:3087555e-0a1c-4aa8-b326-682c7bf276e9. This is the same sample integration key and secret in the documentation.
Check the Authorization header you are submitting by encoding your integration key and secret (integrationKey:secret) using this online base64encoder. This will make sure the issue isn't with your base64 encoding of your integration key and secret. Once you have that value make sure your Authorization uses the word Basic before the value you got from this website. (Basic base64stringFromOnlineEncoder)
Check that the code your are submitting in the body of the post is not the sample code from their documentation. ey2dj3nd.AAAA39djasd3.dkn4449d21d is the sample code from their documentation. You may just be using that in your question as a placeholder but if you are submitting any of those values it will return invalid_grant. Make sure that the body of your post does not have any leading or trailing spaces.
Have the correct Content-Type set application/x-www-form-urlencoded
Have the correct Authorization header set Basic base64EncodedIntegrationKey:Secret
Have the correct body using the valid code received from the GET request to /oauth/auth with no leading or trailing spaces, making sure you're not using the values from your question.
If you are still having trouble and you are not doing a user application but are doing a service integration you can use Legacy Authentication to get your oAuth2 token.
Alternative Method using Legacy Authentication for Service Integrations
This method does not use a grant code. You pass in the integration key, username and password into the X-DocuSign-Authentication header in JSON format.
Demo Server: demo.docusign.net
Production Server: www.docusign.net API
Version: v2
POST https://{server}/restapi/{apiVersion}/oauth2/token
Content-Type: application/x-www-form-urlencoded
X-DocuSign-Authentication: {"IntegratorKey":"your_integrator_key","Password":"docusign_account_password","Username":"docusign_account_username"}
grant_type=password&client_id=your_integrator_key&username=docusign_account_username&password=docusign_account_password&scope=api
If you are building a user application that requires the user enter their docusign credentials to generate the token, this alternative will not work for you.
For anyone who is facing this error, I'd like to point out this note in the documentation:
Note: The obtained authorization code is only viable for 2 minutes. If more then two minutes pass between obtaining the authorization code and attempting to exchange it for an access token, the operation will fail.
I was struggling with the same error until I spotted the note and sped up my typing to meet the 2 minutes.
Hope it helps someone else.
In my case the problem was related to having set a wrong value for Content-Type header, namely "application/x-www-form-URIencoded" instead of the correct "application/x-www-form-urlencoded". Note though that in my case the problem was not a "typo" but an excessive trust in DocuSign documentation.
Indeed the wrong Content-Type is, at the time of writing, suggested directly into the documentation page where they describe the Authorization Code Grant workflow, see the image below for the relevant part.
Hopefully they will fix the documentation soon but for the time being be careful not to blindly copy & paste the code from their examples without thinking, as I initially did.
anyone have an idea what is wrong here I am getting a BadRequest with the following
{"error":"invalid_grant","error_description":"unauthorized_client"}
var client = new RestClient(ESIGNURL);
var request = new RestRequest("/oauth/token");
request.Method = Method.POST;
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddHeader("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(integrationkey+ ":" + secret)));
string body = "grant_type=authorization_code&code=" + code;
request.Parameters.Clear();
request.AddParameter("application/x-www-form-urlencoded", body, ParameterType.RequestBody);
var response = client.Execute(request);
I was getting this error as well. What I realized is I was appending the state at the end of the code before passing it to the oauth token endpoint.
This snippet is from Docusign explaining what are some other reasons for getting that error.
Invalid-error explanation
I just spent a day doing this (in NodeJS). I'll add a couple of things to the answers from before. First, I had to put:
"Content-Type": "application/x-www-form-urlencoded"
in the header. Otherwise it gave me the message:
{
"error": "invalid_grant",
"error_description": "unsupported_grant_type"
}
Second, the base64 encoding:
I used this in NodeJS and it worked
const integration_key = process.env.INTEGRATION_KEY;
const secret_key = process.env.SECRET_KEY;
const authinfo =
integration_key.toString("utf8") + ":" + secret_key.toString("utf8");
const buff2 = Buffer(authinfo, "utf8").toString("base64");
If you use "base64url" it dosen't work because it strips the == off of the end of the string. The = symbol is used as padding and apparently it's needed. You see a similar difference on this site https://www.base64encode.org/ when you toggle the url safe encoding option. If you don't have the padding on the end of your base64 encoded string (or if it's generally incorrect) you get this message:
{
"error": "invalid_grant",
"error_description": "unauthorized_client"
}
Finally, if you're using Postman (I'm using DocuSign's Postman Collection) remember to reset and save the codeFromUrl variable after you update it. Otherwise it doesn't update and you get the message:
{
"error": "invalid_grant",
"error_description": "expired_client_token"
}
This means the old URL code has expired and your new one didn't save.

Resources