+ Start a Discussion
artofbiartofbi 

Chatter API Images not showing, getting 302 found response but different MIME type

We're using the Chatter API and pulling a feed into our application.

 

We are retrieving the image URL from the Chatter API feed response and attempting to display it in the web app.  The detail from our HTTP XHR traffic analyzer is showing a 302 Found HTTP response but the following message is also showing and the profile photo of each user is missing,

 

Resource interpreted as Image but transferred with MIME type text/html: "https://na8.salesforce.com/content/session?url=https%3A%2F%2Fc.na8.content.force.com%2Fprofilephoto%2F729C0000000DXXXXX".

 

The login to the SFDC site/portal itself is timedout but we refresh the API token for the Chatter API calls and the photos don't show.

 

Can anyone offer an explanation for why this is happening? Or what the solution might be? 

Best Answer chosen by Admin (Salesforce Developers) 
Thomas CookThomas Cook

Are you using version 27 of the API, e.g. .../services/data/v27.0/chatter/users/me 

 

Bearer token URLs will only work for version 27+ of the API. The URLs should be noticeably longer than they would be otherwise, and contain ?_bearer=<big long key>

All Answers

ChrisOctagonChrisOctagon

Hi,

 

Are you including your oauth token in the requests for images?

 

If you're not able to put the oauth token in your request as a parameter, then maybe consider using our new bearer token functionality: http://www.salesforce.com/us/developer/docs/chatterapi/Content/intro_requesting_bearer_token_url.htm By setting the header

"X-Connect-Bearer-Urls: true" you will receive a photo url that can be used directly in your app without passing in an oauth token.

 

 

 

artofbiartofbi

Hi ChrisOctagon,

 

 

I finally got a chance to try this solution and it didn't work for me. I really need an example if you don't mind.

 

So, I called the oauth process per normal and added the X-Connect-Bearer-Urls: true attribute to the header but the body of the response didn't look any different.  Also, I there was no such "Bearer URL" in the body to parse as the document link you provided states.

 

Is there something that I need to add to the scope of the oauth request?

 

Can you provide a little more detail or an example?

 

This is clearly a new and seldom used feature at this point for SFDC and there aren't really any examples of use on the net.

 

Thanks in advance.

artofbiartofbi

Okay.  After going through this in a bit more detail and finding the only usage and examples of the Bearer authorization (Authorization: Bearer token) and X-Connect-Bearer-Urls: true header implementation, I believe this is a bug.

 

This can't be desired oauth functionality because, in using a Java application, and normal SFDC oauth REST protocal, I receive and store the access_token. I can use it for multiple REST request spanning hours between REST calls without having to refresh the access_token and I receive the content which I seek in the response without issue.  An example response that I may seek is chatter feed information (text, etc.).  However, after the core login.salesforce.com session timesout (approx. 20 minutes), the Java application's REST calls still return a response body per my stored access_token, however, trying to display a photoURL returned in the response body via the Java Web Application it  doesn't work because the login.salesforce.com session has expired and the images don't render.  If I attempt to use the (Authorization: Bearer token) and X-Connect-Bearer-Urls: true header implementation recommended then it causes my access_token REST requests to fail with a an INVALID SESSION response and no other information is returned in the response body.  Clearly this is not desired functionality that some components work via access_token REST requests but others don't.

 

So the question is why are the static HTML items attached to the login.salesforce.com session and not the access_token?

 

What is the best approach to submitting a bug to Salesforce.com?

Thomas CookThomas Cook

To help with this, can you answer the following?

 

1. Where is your web app running? Is it on force.com or some 3rd party site?

2. It sounds like your app may have more than one access token -- something like a session id and an Oauth token. Is this correct?

3. Are you now getting back URLs in the API response that have bearer token URLs?

4. I'm assuming your image links (the bearer token URLs with ?_bearer=... in them) are being placed inside <img> tags -- is this correct?

 

Notes: the bearer token URLs are only good for approximately 20 minutes. If you need a bearer URL after that for some reason, you need to re-request the thing you originally got the bearer token from and use the newer bearer token URLs returned with that.

artofbiartofbi

Hi Thomas,

 

1. It is running on a third party site. So we are using the REST API to call Chatter specifically.

2. Nope.  We are simply using the oauth auth_token procedure as defined here,

http://wiki.developerforce.com/page/Digging_Deeper_into_OAuth_2.0_on_Force.com

 

3. Yes, the API response body, JSON, has all of the correct information, URL, commentText, and other attributes as desired.

 

4. No, we are not using that syntax. Perhaps that is the problem.  Could you provide a cleaner example of that syntax?  Currently we are simply placing the image URL returned from the REST response body into an <img> tag as is.  So, where is the documentation or example of including the "?_bearer=" suffix/qs

 

I see your note about the session timeout at 20 minutes which appears to be the same as the login.salesforce.com timeout which we've found to be accurate but I'm not sure of the relationship there.

 

Can you tell me are the bearer token and the auth_token the same?  If not, how could I test or validate the difference?  I'm not seeing where they would be different or event requested differently.  I do see some example showing the password authentication method where they retrieve the bearer token by passing the username/password to SFDC to get the token which is not a possibility for our implementation.

 

Any help is much appreciated, especially on the #4 reponse above.

Thomas CookThomas Cook

Are you using version 27 of the API, e.g. .../services/data/v27.0/chatter/users/me 

 

Bearer token URLs will only work for version 27+ of the API. The URLs should be noticeably longer than they would be otherwise, and contain ?_bearer=<big long key>

This was selected as the best answer
artofbiartofbi

We've been using v26.0.

 

I'll switch over to v27.0 and test.

artofbiartofbi

Great I just tried the solution and it appears to have been successful on my first execution and initial validations.

 

Some things to keep in mind are:

  • It must be version 27 , i.e.: v27.0
  • The header name/value pair is case-sensitive

 

Thanks again for the assistance guys.

HeliusHelius

Hi all, I don't think I'm quite understanding the solution provided. My problem is exactly, or close to, the original issue.

 

Here is the function code:

 

function profile($instance_url, $access_token){
        // ERRRRROOOOAAAAAARRRRRRR Section.
        if (!isset($access_token) || $access_token == "") { die("Error - access token missing from session!"); }
        if (!isset($instance_url) || $instance_url == "") { die("Error - instance URL missing from session!"); }
        //MAIN variables
        //set Access Token given by salesforce oauth/oauth_callback
        $access_token = $_SESSION['access_token'];
        $instance_url = $_SESSION['instance_url'];
        //set Url to use - Search variable is at end of line; q=
        $url =  $instance_url . '/services/data/v27.0/chatter/users/me';
        // START OF CURLOPT // BEGIN FORMING CURL COMMAND
        $curl = curl_init($url);
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_HEADER, false);
            curl_setopt($curl, CURLOPT_HTTPHEADER, array("Authorization: OAuth $access_token"));
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($curl, CURLOPT_TIMEOUT, '5');
            
        //HANDLE THE RESPONSE
        $json_response = curl_exec($curl);
        $profile_response = json_decode($json_response, true);
        curl_close($curl);
        
        echo '<div id="profile">';
        echo '<a href="' . $instance_url . '/' . $profile_response['id'] . '">';
        echo '<span class="p_photo"><img src="'. $profile_response['photo']['smallPhotoUrl'] .'"/></span>';
        echo '<span class="name">' . $profile_response['name'] . '</span>';
        echo '<span class="commentcount">Comment Count: ' . $profile_response['chatterActivity']['commentCount'] . '</span>';
        echo '<span class="likereceived"> Likes Received: ' . $profile_response['chatterActivity']['commentReceivedCount'] . '</span>';
        
        echo '</a>';
        echo '</div>';
        
}

I get the same error for the image that artofbi got. The image only loads after I go directly to the image URL and load it in the browser, then the widget I'm building can see the image.

Can someone give me an example of using the bearer code? Also, is that actually a solution in my case? I don't see how that is going to resolve my issue... Shouldn't there be a way to set the mime type after I receive it? I hope someone can point me in the right direction.

ChrisOctagonChrisOctagon

Helius,

 

The regular URLs that the Chatter REST API produces are not embeddable in img tags because they require authentication. If you request "bearer urls" then they will be usable in img tags because the authentication is built into the URLs.

 

Please add the following header option:

 

X-Connect-Bearer-Urls: true

 

to your request.

 

- Chris

HeliusHelius

Thanks, that was it. I tried that earlier and must have had something wrong in my code. It's working now and thank you again for your elaboration.

ScreenScreen

Helius,

 

Basically what I did in order to get this working correctly was to add a Header to my GET request which seeks to retrieve the latest feed.  The header was for X-Connect-Bearer-Urls, for example in my Java code using an OAuth library,

 

oauthRequest.addHeader("X-Connect-Bearer-Urls", "true");

 

I've just reviewed my code and that is the only additional item that it took in order to get the issue resolved.

 

Hopefully that makes sense to you.