{"id":54,"date":"2013-04-24T16:38:42","date_gmt":"2013-04-25T00:38:42","guid":{"rendered":"http:\/\/www.bridgefarmconsulting.com\/blog\/?p=54"},"modified":"2013-04-24T16:38:42","modified_gmt":"2013-04-25T00:38:42","slug":"twitter-authentication","status":"publish","type":"post","link":"https:\/\/www.bridgefarmconsulting.com\/blog\/twitter-authentication\/","title":{"rendered":"Twitter Authentication"},"content":{"rendered":"<p>If you are interacting with Twitter, you hopefully know that the old 1.0 API (that didn&#8217;t need authentication) is being <a href=\"https:\/\/dev.twitter.com\/blog\/planning-for-api-v1-retirement\">retired<\/a> next week. So this sort of query won&#8217;t work anymore:<br \/>\n<a href=\"https:\/\/api.twitter.com\/1\/users\/show.json?screen_name=britishboyindc\">https:\/\/api.twitter.com\/1\/users\/show.json?screen_name=britishboyindc<\/a><\/p>\n<p>Instead, you have to authenticate against Twitter first, get a token, and then make you request(s). On the plus side, you get access to the far richer 1.1 API, which will let you do the query above for 100 accounts at once. So if you just need to update some basic stats every night for a few hundred accounts, this makes life much easier (when people complain about Limits in Salesforce &#8211; tell them to try Twitter&#8217;s API!)<\/p>\n<p>The <a href=\"https:\/\/dev.twitter.com\/docs\/auth\/application-only-auth\">authentication instructions<\/a> look a little intimidating compared with the previous method that didn&#8217;t involve any effort, but they are actually pretty straight forward to implement in Salesforce. I am using the Application Auth process, since I don&#8217;t need to post as a user.<\/p>\n<p>First, generate your consumer key + consumer secret key per the instructions. I suggest storing them in a Custom Setting &#8211; I have one called social_media_settings to store the two keys.<\/p>\n<p>Then you&#8217;ll need a method to generate the bearer:<\/p>\n<pre class=\"brush: java; gutter: true; first-line: 1; highlight: []; html-script: false\">private String getBearerToken() {\r\n\/\/Encode them\r\nString keyencoded = EncodingUtil.urlEncode(socialsettings.API_Key__c, &#039;UTF-8&#039;);\r\nString secretkeyencoded = EncodingUtil.urlEncode(socialsettings.API_Secret_Key__c, &#039;UTF-8&#039;);\r\n\r\n\/\/Create Final Key String\r\nString sFinal = keyencoded + &#039;:&#039; + secretkeyencoded;\r\n\/\/Convert to Blob\r\nBlob headerValue = Blob.valueOf(sFinal);\r\n\r\n\/\/Build Request\r\nHttpRequest req = new HttpRequest();\r\nreq.setEndpoint(&#039;https:\/\/api.twitter.com\/oauth2\/token&#039;);\r\nreq.setMethod(&#039;POST&#039;);\r\n\r\n\/\/Add Auth Header\r\nString authorizationHeader = &#039;Basic &#039; + EncodingUtil.base64Encode(headerValue);\r\nreq.setHeader(&#039;Authorization&#039;, authorizationHeader);\r\n\r\n\/\/You need to add this to the request - proved easy to miss in instructions...\r\nreq.setBody(&#039;grant_type=client_credentials&#039;);\r\n\r\n\/\/Make request\r\nHttp http = new Http();\r\nHTTPResponse res = http.send(req);\r\nString stoken;\r\n\/\/Parse JSON for Bearer Token\r\nJSONParser parser = JSON.createParser(res.getBody());\r\nwhile (parser.nextToken() != null) {\r\nif (parser.getCurrentToken() == JSONToken.FIELD_NAME &amp;&amp; parser.getText() == &#039;access_token&#039;){\r\nparser.nextToken();\r\nstoken = parser.getText();\r\n}\r\n}\r\n\/\/Return Token so it can be used in next call\r\nreturn stoken;\r\n}<\/pre>\n<p>Now you have the a way to get the Bearer Code, you can authenticate your request like this:<\/p>\n<pre class=\"brush: java; gutter: true; first-line: 1; highlight: []; html-script: false\">private void submittotwitter () {\r\nHttpRequest req2 = new HttpRequest();\r\n\/\/I actually store the endpoint in the same custom setting and build dynamically, but for purposes of demo:\r\nreq2.setEndpoint(&#039;https:\/\/api.twitter.com\/1.1\/users\/lookup.json?screen_name=britishboyindc,salesforce&#039;);\r\nreq2.setMethod(&#039;GET&#039;);\r\n\r\n\/\/Call Bearer token Method\r\n\/\/Note - unless invalidated, I believe you can store this and keep using it indefinitely, but again, to demo concept\r\nString authorizationHeader = &#039;Bearer &#039; + getBearerToken();\r\nreq2.setHeader(&#039;Authorization&#039;, authorizationHeader);\r\n\r\nHttp http = new Http();\r\nHTTPResponse res = http.send(req2);\r\nString sBody = res.getBody();\r\n\r\n\/\/I have a Twitter Results class to de-serialize the results into (See below)\r\nMap &lt;String, TwitterResults&gt; TwitterResultsMap = new Map&lt;String, TwitterResults&gt; ();\r\n\r\n\/\/You can generate one here: http:\/\/json2apex.herokuapp.com\/makeApex\r\n\/\/I can then pass the results back as a return, or set the map as s public variable on the class\r\n\r\n\/\/Use native JSON parser to turn results into a list of TwitterResults\r\nList tresults = TwitterResults.parse(sBody);\r\n\/\/The key is set to be the twitter handle name that I am storing in SFDC\r\nFor (TwitterResults t: tresults) {\r\nTwitterResultsMap.put(t.screen_name, t);\r\n}\r\n\r\n}<\/pre>\n<p>So now I have the result data (followers_count, statuses_count) for all the twitter handles I queried for a map I can reference and use to update my contacts in Salesforce. There is much more you can do of course!<\/p>\n<pre class=\"brush: java; gutter: true; first-line: 1; highlight: []; html-script: false\">public class TwitterResults {\r\n\r\n    public Integer id;\r\n    public Integer listed_count;\r\n    public String screen_name;\r\n    public String url;\r\n    public Integer followers_count;\r\n    public Integer friends_count;\r\n    public Integer statuses_count;\r\n\r\n    public static List&lt;TwitterResults&gt; parse(String json) {\r\n        return (List&lt;TwitterResults&gt;) System.JSON.deserialize(json, List&lt;TwitterResults&gt;.class);\r\n    }<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>If you are interacting with Twitter, you hopefully know that the old 1.0 API (that didn&#8217;t need authentication) is being retired next week. So this sort of query won&#8217;t work anymore: https:\/\/api.twitter.com\/1\/users\/show.json?screen_name=britishboyindc Instead, you have to authenticate against Twitter first, get a token, and then make you request(s). On the plus side, you get access [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[3,4],"tags":[],"class_list":["post-54","post","type-post","status-publish","format-standard","hentry","category-apex","category-apis"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/posts\/54","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/comments?post=54"}],"version-history":[{"count":13,"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/posts\/54\/revisions"}],"predecessor-version":[{"id":67,"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/posts\/54\/revisions\/67"}],"wp:attachment":[{"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/media?parent=54"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/categories?post=54"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.bridgefarmconsulting.com\/blog\/wp-json\/wp\/v2\/tags?post=54"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}