You can get a consumer key and secret for your Twitter application here.
OAuthConsumer consumer = new DefaultOAuthConsumer(
// the consumer key of this app (replace this with yours)
"iIlNngv1KdV6XzNYkoLA",
// the consumer secret of this app (replace this with yours)
"exQ94pBpLXFcyttvLoxU2nrktThrlsj580zjYzmoM");
OAuthProvider provider = new DefaultOAuthProvider(
"http://twitter.com/oauth/request_token",
"http://twitter.com/oauth/access_token",
"http://twitter.com/oauth/authorize");
/****************************************************
* The following steps should only be performed ONCE
***************************************************/
// we do not support callbacks, thus pass OOB
String authUrl = provider.retrieveRequestToken(consumer, OAuth.OUT_OF_BAND);
// bring the user to authUrl, e.g. open a web browser and note the PIN code
// ...
String pinCode = // ... you have to ask this from the user, or obtain it
// from the callback if you didn't do an out of band request
// user must have granted authorization at this point
provider.retrieveAccessToken(consumer, pinCode);
// store consumer.getToken() and consumer.getTokenSecret(),
// for the current user, e.g. in a relational database
// or a flat file
// ...
/****************************************************
* The following steps are performed everytime you
* send a request accessing a resource on Twitter
***************************************************/
// if not yet done, load the token and token secret for
// the current user and set them
consumer.setTokenWithSecret(ACCESS_TOKEN, TOKEN_SECRET);
// create a request that requires authentication
URL url = new URL("http://twitter.com/statuses/mentions.xml");
HttpURLConnection request = (HttpURLConnection) url.openConnection();
// sign the request
consumer.sign(request);
// send the request
request.connect();
// response status should be 200 OK
int statusCode = request.getResponseCode();
Here is what you typically do step by step:
- When your users want to access Twitter through your application for the first time, you should display some kind of notification which indicates that an authentication process is about to start
- Call OAuthProvider.retrieveRequestToken(callback) on the OAuthProvider. If your application can receive callbacks via URLs, you can be informed about successful authorization by providing a callback URL here. If you cannot receive callbacks (e.g. because you're developing a desktop application), then you must pass "oob" here (for "out of band").
- On method return, you have to send the user to the URL returned by it. The user now must grant your application access to Twitter - this step is out of the reach of your application, because it happens in the Web browser.
- Call OAuthProvider.retrieveAccessToken() with the PIN code generated by Twitter in the previous step. If your interaction style is out-of-band, then you must ask the user to enter this value somewhere, since there is no way to get it programatically. If however you defined a callback URL before, then the PIN code will be passed to your application automatically with that callback as an "oauth_verifier" parameter.
- On method return, call OAuthConsumer.getToken() and OAuthConsumer.getTokenSecret(), associate them with the user who triggered the authorization procedure, and store them away safely.
- Any OAuthConsumer configured with these values can now sign HTTP requests in order to access protected resources on Twitter on behalf of that user.
You can also download this example code as a Java/Eclipse project and go from there. This example application executes all steps above sequentially in the console. If run successfully, its output should be something like this:
Fetching request token from Twitter...
Request token: g1re4iYfknOYMB62JZkddjwhCfvfn4WPdZrzgscMOA
Token secret: wKStK0dmhPcuFxBki3imJv7yVNXgRndmW4LSmuCg
Now visit:
http://twitter.com/oauth/authorize?oauth_token=g1re4iYfknOYMB62JZkddjwhCfvfn4WPdZrzgscMOA
... and grant this app authorization
Enter the PIN code and hit ENTER when you're done:
xxxxxxx
Fetching access token from Twitter...
Access token: 14418463-Xt70aZ8b2jz19MzY7JnQJ6HglPh0Hc5p939gLH5YI
Token secret: TkG689FOx7amgdX2ta6epE5MYsmZxVuO9ith7FtJrs
Sending request to Twitter...
Response: 200 OK
Thanks Kerry for sharing this via our Google group!
NOTE: This example assumes that you're using Apache HttpClient for HTTP messaging.
We'll need to tweak some of HttpClient's defaults, like so:
public HttpParams getParams() {
// Tweak further as needed for your app
HttpParams params = new BasicHttpParams();
// set this to false, or else you'll get an
// Expectation Failed: error
HttpProtocolParams.setUseExpectContinue(params, false);
return params;
}
// Your actual method might look like this:
public void updateProfileBackground(User user, File file) {
try {
// Create a new consumer using the commons implementation
OAuthConsumer consumer = new CommonsHttpOAuthConsumer(consumerKey,
consumerSecret);
consumer.setTokenWithSecret(getUserAccessToken(user),
getUserTokenSecret(user));
HttpPost uploadBackgroundPost = new HttpPost(
UPDATE_PROFILE_BACKGROUND_IMAGE_URL);
// The body of a multi-part post isn't needed
// for the generation of the signature
consumer.sign(uploadBackgroundPost);
// only works in strict mode
MultipartEntity entity = new MultipartEntity(
HttpMultipartMode.STRICT);
// Twitter checks against supported file types
FileBody imageBody = new FileBody(file, "image/png");
entity.addPart("image", imageBody);
uploadBackgroundPost.setEntity(entity);
DefaultHttpClient httpClient = new DefaultHttpClient(getParams());
// If you're interested in the headers,
// implement and add a request interceptor that prints them
httpClient.addRequestInterceptor(new PrintRequestInterceptor());
System.out.println(httpClient.execute(uploadBackgroundPost,
new BasicResponseHandler()));
} catch (Exception e) {
// do some proper exception handling here
e.printStackTrace();
}
}
Now oddly enough, if the multi-part form data is not being formatted exactly to Twitter's preferences you won't get an error message, but the background image will be set to a broken link! You might see the image url being constructed as:
http://a3.twimg.com/profile_background_images/test.png
instead of:
http://a3.twimg.com/profile_background_images/5463125/test.png
(Notice the missing folder)
Additionally here's an example if you're using Apache HttpClient2.x, which uses a different API than HttpClient 4.x.
First off you'll need to make your own adapter for the MultipartPostMethod (or if you're adventurous HttpMethod more generally).
Something along the lines of:
public class HttpClient2OAuthConsumer extends AbstractOAuthConsumer {
public HttpClient2OAuthConsumer(String consumerKey,
String consumerSecret, SignatureMethod signatureMethod) {
super(consumerKey, consumerSecret, signatureMethod);
}
protected oauth.signpost.http.HttpRequest wrap(Object request) {
if (!(request instanceof MultipartPostMethod))
throw new IllegalArgumentException(
"This consumer expects requests of type MultipartPostMethod");
else
return new HttpRequestAdapter((MultipartPostMethod) request);
}
}
And:
public class HttpRequestAdapter implements oauth.signpost.http.HttpRequest {
private MultipartPostMethod method;
public HttpRequestAdapter(MultipartPostMethod method) {
this.method = method;
}
public String getContentType() {
Header contentHeader = method.getRequestHeader("Content-Type");
return (contentHeader == null) ? "" : contentHeader.getValue();
}
public String getHeader(String s) {
return method.getRequestHeader(s).getValue();
}
public InputStream getMessagePayload() throws IOException {
return new FileInputStream(method.getFileData());
}
public String getMethod() {
return method.getName();
}
public String getRequestUrl() {
try {
return method.getURI().getURI();
} catch (URIException e) {
e.printStackTrace();
}
return null;
}
public void setHeader(String s, String s1) {
method.setRequestHeader(s, s1);
}
}
This method will look very similar.
public void updateProfileBackgroundHttpCommons(User user, File file) {
try {
HttpClient client = new HttpClient();
// make a new consumer with our own implementation
OAuthConsumer consumer = new HttpClient2OAuthConsumer(consumerKey,
consumerSecret);
consumer.setTokenWithSecret(getUserAccessToken(user),
getUserTokenSecret(user));
MultipartPostMethod mp = new MultipartPostMethod(
UPDATE_PROFILE_BACKGROUND_IMAGE_URL);
FilePart image = new FilePart("image", file, "image/png", null); // again specify the type
// charset cannot be set to a type.
// httpclient2.x mistakenly adds one to a filepart by default
image.setCharSet(null);
mp.addPart(image);
mp.setStrictMode(false);
consumer.sign(mp);
client.executeMethod(mp);
for (Header header : mp.getRequestHeaders()) {
System.out.println(header.toExternalForm());
}
System.out.println(mp.getResponseBodyAsString());
} catch (Exception e) {
// do some proper exception handling here
e.printStackTrace();
}
}
And that's it.