9

Does anyone know if it's possible to access the images stored in a rich text area over the API using the username-password flow? I have images in Knowledge Articles that I would like to expose through our app but am unable to figure out a solution. Our app is a standalone webapp which communicates with salesforce through an integration user who is authenticated via OAuth. The only fix we've found so far is to login to login.salesforce.com using a headless browser (zombie.js), grab the value of the sid from the cookies, and use that sid in an HTTP get request to the image hosted at

https://c.<instance-id>.content.force.com/servlet/rtaImage

which works but introduces a lot of unwanted overhead.The answer in How to set public inline images in knowledge base article works great but I don't wish to expose all articles as public. However, when I follow the same steps but make the article non-public I just get an "Image Not Available" error:

enter image description here

So alternatively, if there is a way to fetch these images using an access_token then we could proxy all image requests through our outstanding API connection to solve the problem.

Update

After further investigation, we figured out that this is possible using Daniel's solution as long as you provide the access_token as a valid cookie object. Initially, we were creating the cookie as a String but were only able to get things working once we created it using the jar() function within the request library. When using the username-password flow or the SOAP API, the web scope is not supported but the access_token will still work as a valid sid.

In case anyone else needs this, here is a code snippet which will fetch an rtaImage from Salesforce without making the KB public. Internally, we're using promises but it's not a requirement:

var Q = require('q')
var request = require('request')
var jsforce = require('jsforce')    
var jar = request.jar()
var imageToGet = 'https://c.<instance-id>.content.force.com/servlet/rtaImage?eid=<eid>&feoid=<feoid>&refid=<refid>'

// Initialize a connection to salesforce
var conn = new jsforce.Connection({
  // you can change loginUrl to connect to sandbox or prerelease env.
  loginUrl : 'https://test.salesforce.com'
});

// First, login to Salesforce
Q.npost(conn, 'login', ['foo@example.com', 'p4ssword'])
  // Then generate a cookie containing the access_token from your valid
  // session with Salesforce and issue an HTTP GET request for the image.
  .then(function(userInfo) {
    jar.setCookie('sid=' + conn.accessToken, conn.instanceUrl)
    return Q.nfcall(request.get, imageToGet, {jar: jar, encoding: null})
  })
  // Finally, do something with the fetched image.
  .then(function(args) {
    var res = args[0]
    var body = args[1] // <-- You now have a Buffer object containing the image

    console.log(body.length)
  })
  .fail(console.error)
  .done(console.error) 
6

You might be able to use the OAuth accessToken in a cookie with the HTTP GET request to servlet/rtaImage depending on the scope you requested when getting it.

I believe you will need to use the full or web scopes to then make web requests or use frontdoor.jsp.

See:

The cookie will have the name sid and the domain ".salesforce.com".

You basically want to use the OAuth accessToken in place of the Session Id.

Note that the accessToken takes the same form as a session Id, but can't always be used to authenticate with the website. Your mileage may vary.

  • What should the cookie look like then? Instead of sid=<sid> it would be oauth=<access_token>? – Jason Sims Jul 23 '14 at 2:27
  • @JasonSims It should look exactly like the cookie your web browser uses. This will be the same as the cookie you get from the headless browser. The only difference is you can use the accessToken from OAuth in place of the session id value. sid=<access_token> – Daniel Ballinger Jul 23 '14 at 2:29
  • Ah yea, I had tried this but when requesting in that manner the response comes back as 302 - Found redirect instead of returning the image. The same HTTP GET request with a sid from the browser works great though. – Jason Sims Jul 23 '14 at 2:32
  • Yes, that is the OAuth established session Id not being valid on the website. I think it comes back to the requested OAuth scope. Did you ask for api rather than full – Daniel Ballinger Jul 23 '14 at 2:40
  • I enabled all scopes on the connected app for troubleshooting but was unable to figure out how to specify a scope when authenticating with the username-password OAuth flow. – Jason Sims Jul 23 '14 at 2:41
1

I confirm Daniel Ballinger's solution on this page.

The scope needed for the OAuth token is "web: Provide access to your data via the Web (web)". According to the Salesforce documentation on Scope Parameter Values, this "Allows the ability to use the access_token on the Web" which I presume means using the Access Token as a cookie?

Steps to download a Rich Text Area (RTA) image via OAuth and curl, or similar programmatic methods:

  1. Make sure you have the correct scope for your OAuth access token. Go to the "Connected Apps" page for your OAuth connected app in Salesforce. Under "API (Enable OAuth Settings)" make sure the scope "web: Provide access to your data via the Web (web)" is included.

  2. If you were using an old refresh token with the old scope, re-authorize and get a new one with the new scope which includes "web".

  3. Get the URL of the RTA image by browsing the Knowledge article and inspecting the image src URL in your browser. The URL should look like

    https://example--c.eu3.content.force.com/servlet/rtaImage?eid=ka0w0000000U2CV&feoid=00Nw0000008eLoi&refid=0EMw00000004lzh
    
  4. Make a curl request setting your cookie "sid" to the OAuth access token value e.g.

    curl -ik --cookie 'sid=MyOauthAccessToken' 'https://example--c.eu3.content.force.com/servlet/rtaImage?eid=ka0w0000000U2CV&feoid=00Nw0000008eLoi&refid=0EMw00000004lzh'
    
  5. The request will return a 302 redirect. Do another curl with the redirect URL and set the same "sid" cookie value. Follow 3-4 subsequent redirects, using the returned redirect URL each time, until the response header includes a "Set-Cookie" giving you a new "sid" cookie value.

    Set-Cookie: sid=0023457000079pu!AR8AQO8byIe2NtMi8vd3bt5vVBFqJxgDU2FkQQZd7NgHIQ49CejIVh6FAHyN4mKmSu1UDRAMpWMtUSuAuea0CY123456abcd; path=/; secure
    
  6. Use the new "sid" cookie value for the next request to the redirect URL. This is the web cookie that we can use for screen scraping.

  7. The request with the new "sid" web cookie value will return the binary data of the image in the response body.

Other methods

This other answer provides more information: https://salesforce.stackexchange.com/a/46495/36144 , including using frontdoor.jsp .

We should also be able to get the web cookie that for scraping the RTA image, by programatically going to https://[YourSalesforceInstanceUrl].salesforce.com/secur/frontdoor.jsp?sid=[OAuthAccessToken].

The frontdoor.jsp method is another way of getting the web cookie, and may also involve following a series of redirects before finally getting the web cookie value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.