package io; import com.google.gson.JsonObject; import java.io.IOException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.logging.Level; import java.util.logging.Logger; import org.apache.commons.io.Charsets; import support.ConsumerKeySecret; /** * An API requester used for application-only requests. Not all requests are * allowed, see https://dev.twitter.com/docs/auth/application-only-auth for * details. * * @author Peter Wu */ public class BearerRequester extends AbstractRequester { /** * A base64-encoded access token that authenticates requests. */ private final String access_token; /** * Instantiates a requester with the given access token. The caller should * test the token for validity. * * @param access_token The bearer token that authenticates a request. */ public BearerRequester(String access_token) { this.access_token = access_token; } /** * Instantiates an instance, requesting an access token from the provided * consumer key and secret. * * @param secrets The consumer secrets provided by Twitter. * @throws IOException if a failure occurred while acquiring a token. */ public BearerRequester(ConsumerKeySecret secrets) throws IOException { String postData = "grant_type=client_credentials"; URL url = buildUrl("oauth2/token"); HttpURLConnection conn = open(url); try { conn.setRequestMethod("POST"); // set request headers conn.addRequestProperty("Authorization", "Basic " + secrets.getBearerTokenBase64()); conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); conn.setFixedLengthStreamingMode(postData.length()); // connect and send request conn.setDoOutput(true); conn.getOutputStream().write(postData.getBytes(Charsets.UTF_8)); JsonObject resp = getResponseAsJson(conn).getAsJsonObject(); if (!resp.getAsJsonObject().getAsJsonPrimitive("token_type").getAsString().equals("bearer")) { throw new IOException("Expected bearer token type"); } access_token = resp.getAsJsonPrimitive("access_token").getAsString(); } catch (ClassCastException ex) { throw new IOException("Response was not a JsonObject"); } finally { conn.disconnect(); } } @Override protected void preconnect(URLConnection conn) throws IOException { // requests do not have to be signed, instead rely on the Bearer token conn.addRequestProperty("Authorization", "Bearer " + access_token); } /** * @return the access token that authenticates requests. */ public String getAccessToken() { return access_token; } @Override public boolean isValid() throws IOException { try { // NOTE: this actually contributes to the ratelimit (12/minute) // TODO: find alternative that does not hit the ratelimit Response obj = getJSON("application/rate_limit_status"); return obj.getResp().getAsJsonObject().has("errors"); } catch (RateLimitException ex) { return false; } } }