Question

I'm attempting to use the Tumblr API in an Android app to authorize users and make text and photo posts. I'm using the Scribe library. So for, I can successfully obtain an access token and use it to get user info. I can also make text posts without any issues. This tells me that I'm signing requests correctly.

However, I've spent the last week and a half attempting to make photo posts without success. I continuously receive 401 errors (Not Authorized) I've read through many posts on the Tumblr support forum as well as here on Stack Overflow, but was unable to find a solution.

I'm reluctant to include the Jumblr library because I'm trying to keep my app as lean as possible. That said, I reviewed the Jumblr code and decided to mimic how photo posts are sent (https://github.com/tumblr/jumblr/blob/master/src/main/java/com/tumblr/jumblr/request/MultipartConverter.java). I'm still receiving the exact same error.

Below is an example my multipart POST request and the response I receive. I've replace the blog name, and OAuth signature, consumer key, and token variables, and have removed the binary image data for brevity sake. Everything else is untouched. I have a few questions...

  1. Are there any other variables that should be included in the multipart section? A Stack Overflow user stated that placing the "oauth_" signature variables in there fixed his problem. I didn't have success with this, but maybe there was something I was missing.

  2. The Jumblr app doesn't appear to do any encoding of the image data, although the Tumblr documentation states that it should be URL encoded. Right now I'm sending it as the Jumblr app appears to (raw binary). Is this correct?

  3. Does anything else in my request look incorrect?

REQUEST:

NOTE: I learned that the OAuth signature should be generated WITHOUT the multipart form. My code takes that into account when building this request!

POST http://api.tumblr.com/v2/blog/**REMOVED**.tumblr.com/post HTTP/1.1
Content-Type: multipart/form-data, boundary=cbe6b79db1b3cbe6b79e104e
Authorization: OAuth oauth_signature="**REMOVED**", oauth_version="1.0", oauth_nonce="3181201716", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="**REMOVED**", oauth_timestamp="1388791537", oauth_token="**REMOVED**"
Content-Length: 1001
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.3; SM-N900T Build/JSS15J)
Host: api.tumblr.com
Connection: Keep-Alive
Accept-Encoding: gzip

--cbe6b79db1b3cbe6b79e104e
Content-Disposition: form-data; name="type"

photo
--cbe6b79db1b3cbe6b79e104e
Content-Disposition: form-data; name="caption"

Another pic test...
--cbe6b79db1b3cbe6b79e104e
Content-Disposition: form-data; name="data[0]"; filename="postr_media_file_1388791537-1709648435.jpg"
Content-Type: image/jpeg

---- BINARY DATA REMOVED FOR BREVITY ----

RESPONSE:

HTTP/1.1 401 Not Authorized
Server: nginx
Date: Fri, 03 Jan 2014 23:25:39 GMT
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Connection: close
Set-Cookie: tmgioct=52c746f34266840643527780; expires=Mon, 01-Jan-2024 23:25:39 GMT; path=/; httponly
P3P: CP="ALL ADM DEV PSAi COM OUR OTRo STP IND ONL"

3c
{"meta":{"status":401,"msg":"Not Authorized"},"response":[]}
Was it helpful?

Solution

I posted the answer in the "Tumblr API Discussion" Google Group. This is what I did:

The key to doing it correctly is NOT just signing without the multipart form!!! Here are the steps...

  1. Add all fields EXCEPT the data field as regular url encoded POST body variables
  2. Sign the request
  3. Remove ALL off the post variables you just added from the request
  4. Add the multipart form, including the data field this time

Some things to consider...

  • The Content-Type in the header should be "multipart/form-data"
  • The Content-Disposition of all form parts should be "form-data" and, of course, include a valid "name" attribute (ie. type, caption, etc...)
  • The Content-Disposition of the data part should also include a "filename" attribute
  • The only form part that should contain a Content-Type is data, and it should be set to the mime type of the file you are uploading (ie. "image/jpeg")
  • I used "data[0]" as the name of the data field. I haven't tested this with just "data", but according to everything I've read it should work that way as well. If you are creating a photo set, I believe you simple add additional parts (ie. data1. data[2], etc...). Again, I haven't tested anything except "data[0]", so do your due diligence!!!
  • I did NOT encode the binary image data!!! I saw people spending considerable amount of time on this in other posts when adding the image as a POST body variable. If doing this as a multipart form, you can skip the encoding and send raw binary data! ;-)

I hope this helps someone! I've spent two weeks banging my head on random solid objects trying to figure this out. The implementation is very easy to do, but there is zero documentation available on how exactly to build POST requests for photos properly. The official docs really should include that. If I had know what I just posted above I could have completed this in minutes instead of weeks!!!

The last request I posted earlier is still valid, but here it is again. Just remember what I mentioned about the signature!!!

REQUEST:

POST http://api.tumblr.com/v2/blog/REMOVED.tumblr.com/post HTTP/1.1
Content-Type: multipart/form-data, boundary=c60f7c041c02c60f7c046e9b
Authorization: OAuth oauth_signature="***REMOVED***", oauth_version="1.0", oauth_nonce="315351812", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="***REMOVED***", oauth_timestamp="1388785116", oauth_token="***REMOVED***"
Content-Length: 1001
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.3; SM-N900T Build/JSS15J)
Host: api.tumblr.com
Connection: Keep-Alive
Accept-Encoding: gzip

--c60f7c041c02c60f7c046e9b
Content-Disposition: form-data; name="type"

photo
--c60f7c041c02c60f7c046e9b
Content-Disposition: form-data; name="caption"

Another pic test...
--c60f7c041c02c60f7c046e9b
Content-Disposition: form-data; name="data[0]"; filename="postr_media_file_1388785116-1709648435.jpg"
Content-Type: image/jpeg

***** BINARY DATA REMOVED FOR BREVITY *****
--c60f7c041c02c60f7c046e9b--
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top