diff --git a/src/main/java/com/restfb/DefaultFacebookClient.java b/src/main/java/com/restfb/DefaultFacebookClient.java
index 79f938ab5..efdc74d8d 100644
--- a/src/main/java/com/restfb/DefaultFacebookClient.java
+++ b/src/main/java/com/restfb/DefaultFacebookClient.java
@@ -93,13 +93,15 @@ public class DefaultFacebookClient extends BaseFacebookClient implements Faceboo
/**
* Version of API endpoint.
*/
- protected Version apiVersion = Version.UNVERSIONED;
+ protected Version apiVersion;
/**
* By default this is false
, so real http DELETE is used
*/
protected boolean httpDeleteFallback;
+ protected boolean accessTokenInHeader;
+
protected DefaultFacebookClient() {
this(Version.LATEST);
}
@@ -196,6 +198,17 @@ public DefaultFacebookClient(String accessToken, String appSecret, WebRequestor
graphFacebookExceptionGenerator = new DefaultFacebookExceptionGenerator();
}
+ /**
+ * Switch between access token in header and access token in query parameters (default)
+ *
+ * @param accessTokenInHttpHeader
+ * true
use access token as header field, false
use access token as query parameter
+ * (default)
+ */
+ public void setHeaderAuthorization(boolean accessTokenInHttpHeader) {
+ this.accessTokenInHeader = accessTokenInHttpHeader;
+ }
+
/**
* override the default facebook exception generator to provide a custom handling for the facebook error objects
*
@@ -258,8 +271,8 @@ public Connection fetchConnection(String connection, Class connectionT
public Connection fetchConnectionPage(final String connectionPageUrl, Class connectionType) {
String connectionJson;
if (!isBlank(accessToken) && !isBlank(appSecret)) {
- connectionJson = makeRequestAndProcessResponse(() -> webRequestor.executeGet(String.format("%s&%s=%s", connectionPageUrl,
- urlEncode(APP_SECRET_PROOF_PARAM_NAME), obtainAppSecretProof(accessToken, appSecret))));
+ connectionJson = makeRequestAndProcessResponse(() -> webRequestor.executeGet(String.format("%s&%s=%s",
+ connectionPageUrl, urlEncode(APP_SECRET_PROOF_PARAM_NAME), obtainAppSecretProof(accessToken, appSecret))));
} else {
connectionJson = makeRequestAndProcessResponse(() -> webRequestor.executeGet(connectionPageUrl));
}
@@ -343,7 +356,8 @@ public T publish(String connection, Class objectType, List T publish(String connection, Class objectType, BinaryAttachment binaryAttachment,
Parameter... parameters) {
- List attachments = Optional.ofNullable(binaryAttachment).map(Collections::singletonList).orElse(null);
+ List attachments =
+ Optional.ofNullable(binaryAttachment).map(Collections::singletonList).orElse(null);
return publish(connection, objectType, attachments, parameters);
}
@@ -441,7 +455,8 @@ public AccessToken obtainAppAccessToken(String appId, String appSecret) {
@Override
public DeviceCode fetchDeviceCode(ScopeBuilder scope) {
verifyParameterPresence(SCOPE, scope);
- ObjectUtil.requireNotNull(accessToken, () -> new IllegalStateException("access token is required to fetch a device access token"));
+ ObjectUtil.requireNotNull(accessToken,
+ () -> new IllegalStateException("access token is required to fetch a device access token"));
String response = makeRequest("device/login", true, false, null, Parameter.with("type", "device_code"),
Parameter.with(SCOPE, scope.toString()));
@@ -453,7 +468,8 @@ public AccessToken obtainDeviceAccessToken(String code) throws FacebookDeviceTok
FacebookDeviceTokenPendingException, FacebookDeviceTokenDeclinedException, FacebookDeviceTokenSlowdownException {
verifyParameterPresence("code", code);
- ObjectUtil.requireNotNull(accessToken, () -> new IllegalStateException("access token is required to fetch a device access token"));
+ ObjectUtil.requireNotNull(accessToken,
+ () -> new IllegalStateException("access token is required to fetch a device access token"));
try {
String response = makeRequest("device/login_status", true, false, null, Parameter.with("type", "device_token"),
@@ -724,15 +740,19 @@ protected String makeRequest(String endpoint, final boolean executeAsPost, final
final String parameterString = toParameterString(parameters);
return makeRequestAndProcessResponse(() -> {
- if (executeAsDelete && !isHttpDeleteFallback()) {
- return webRequestor.executeDelete(fullEndpoint + "?" + parameterString);
- }
+ if (accessTokenInHeader) {
+ webRequestor.setAccessToken(this.accessToken);
+ }
- if (executeAsPost) {
- return webRequestor.executePost(fullEndpoint, parameterString, binaryAttachments);
- }
+ if (executeAsDelete && !isHttpDeleteFallback()) {
+ return webRequestor.executeDelete(fullEndpoint + "?" + parameterString);
+ }
+
+ if (executeAsPost) {
+ return webRequestor.executePost(fullEndpoint, parameterString, binaryAttachments);
+ }
- return webRequestor.executeGet(fullEndpoint + "?" + parameterString);
+ return webRequestor.executeGet(fullEndpoint + "?" + parameterString);
});
}
@@ -749,7 +769,7 @@ public String obtainAppSecretProof(String accessToken, String appSecret) {
/**
* returns if the fallback post method (true
) is used or the http delete (false
)
*
- * @return
+ * @return {@code true} if POST is used instead of HTTP DELETE (default)
*/
public boolean isHttpDeleteFallback() {
return httpDeleteFallback;
@@ -836,7 +856,7 @@ protected String toParameterString(Parameter... parameters) {
* If an error occurs when building the parameter string.
*/
protected String toParameterString(boolean withJsonParameter, Parameter... parameters) {
- if (!isBlank(accessToken)) {
+ if (!isBlank(accessToken) && !accessTokenInHeader) {
parameters = parametersWithAdditionalParameter(Parameter.with(ACCESS_TOKEN_PARAM_NAME, accessToken), parameters);
}
diff --git a/src/main/java/com/restfb/DefaultWebRequestor.java b/src/main/java/com/restfb/DefaultWebRequestor.java
index 558de2879..049a22baf 100644
--- a/src/main/java/com/restfb/DefaultWebRequestor.java
+++ b/src/main/java/com/restfb/DefaultWebRequestor.java
@@ -70,6 +70,8 @@ public class DefaultWebRequestor implements WebRequestor {
private DebugHeaderInfo debugHeaderInfo;
+ private ThreadLocal accessToken = new ThreadLocal<>();
+
/**
* By default this is true, to prevent breaking existing usage
*/
@@ -79,6 +81,11 @@ protected enum HttpMethod {
GET, DELETE, POST
}
+ @Override
+ public void setAccessToken(final String accessToken) {
+ this.accessToken = ThreadLocal.withInitial(() -> accessToken);
+ }
+
@Override
public Response executeGet(String url) throws IOException {
return execute(url, HttpMethod.GET);
@@ -116,6 +123,8 @@ public Response executePost(String url, String parameters, List
@@ -333,6 +348,8 @@ private Response execute(String url, HttpMethod httpMethod) throws IOException {
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setRequestMethod(httpMethod.name());
+ initHeaderAccessToken(httpUrlConnection);
+
// Allow subclasses to customize the connection if they'd like to - set
// their own headers, timeouts, etc.
customizeConnection(httpUrlConnection);
diff --git a/src/main/java/com/restfb/WebRequestor.java b/src/main/java/com/restfb/WebRequestor.java
index e90a1ee43..d1186f63b 100644
--- a/src/main/java/com/restfb/WebRequestor.java
+++ b/src/main/java/com/restfb/WebRequestor.java
@@ -93,6 +93,8 @@ public String toString() {
}
}
+ void setAccessToken(String accessToken);
+
/**
* Given a Facebook API endpoint URL, execute a {@code GET} against it.
*
diff --git a/src/test/java/com/restfb/ClasspathWebRequestor.java b/src/test/java/com/restfb/ClasspathWebRequestor.java
index ad25be9dd..9a1b99569 100644
--- a/src/test/java/com/restfb/ClasspathWebRequestor.java
+++ b/src/test/java/com/restfb/ClasspathWebRequestor.java
@@ -61,6 +61,11 @@ public Response executePost(String url, String parameters) {
return response;
}
+ @Override
+ public void setAccessToken(String accessToken) {
+
+ }
+
/**
* @see com.restfb.WebRequestor#executeGet(java.lang.String)
*/
diff --git a/src/test/java/com/restfb/DefaultWebRequestorTest.java b/src/test/java/com/restfb/DefaultWebRequestorTest.java
index 9251961be..bb7e5d503 100644
--- a/src/test/java/com/restfb/DefaultWebRequestorTest.java
+++ b/src/test/java/com/restfb/DefaultWebRequestorTest.java
@@ -57,6 +57,19 @@ class DefaultWebRequestorTest {
@BeforeEach
void setup() throws IOException {
doReturn(mockUrlConnection).when(requestor).openConnection(any(URL.class));
+ requestor.setAccessToken(null);
+ }
+
+ @Test
+ void checkGet_withAccessToken() throws IOException {
+ requestor.setAccessToken("accesstoken");
+ String resultString = "This is just a simple Test";
+ when(mockUrlConnection.getResponseCode()).thenReturn(200);
+ InputStream stream = new ByteArrayInputStream(resultString.getBytes(StandardCharsets.UTF_8));
+ when(mockUrlConnection.getInputStream()).thenReturn(stream);
+ WebRequestor.Response response = requestor.executeGet("http://www.example.org");
+
+ verify(mockUrlConnection).setRequestProperty("Authorization", "Bearer accesstoken");
}
@Test
@@ -75,6 +88,7 @@ void checkGet() throws IOException {
verify(mockUrlConnection).setReadTimeout(180000);
verify(mockUrlConnection).setUseCaches(false);
verify(mockUrlConnection).setRequestMethod(DefaultWebRequestor.HttpMethod.GET.name());
+ verify(mockUrlConnection, never()).setRequestProperty(eq("Authorization"), anyString());
verify(mockUrlConnection).connect();
verify(requestor).executeGet(anyString());
verify(requestor, never()).executePost(anyString(), anyString());
@@ -83,6 +97,19 @@ void checkGet() throws IOException {
verify(requestor).fetchResponse(mockUrlConnection);
}
+ @Test
+ void checkPost_withAccessToken() throws IOException {
+ requestor.setAccessToken("accesstoken");
+ when(mockUrlConnection.getOutputStream()).thenReturn(mockOutputStream);
+ String resultString = "This is just a simple Test";
+ when(mockUrlConnection.getResponseCode()).thenReturn(200);
+ InputStream stream = new ByteArrayInputStream(resultString.getBytes(StandardCharsets.UTF_8));
+ when(mockUrlConnection.getInputStream()).thenReturn(stream);
+ WebRequestor.Response response = requestor.executePost(exampleUrl, "");
+
+ verify(mockUrlConnection).setRequestProperty("Authorization", "Bearer accesstoken");
+ }
+
@Test
void checkPost_NoBinary() throws IOException {
when(mockUrlConnection.getOutputStream()).thenReturn(mockOutputStream);
@@ -101,6 +128,7 @@ void checkPost_NoBinary() throws IOException {
verify(mockUrlConnection).setUseCaches(false);
verify(mockUrlConnection).setDoOutput(true);
verify(mockUrlConnection).setRequestMethod(DefaultWebRequestor.HttpMethod.POST.name());
+ verify(mockUrlConnection, never()).setRequestProperty(eq("Authorization"), anyString());
verify(mockUrlConnection).connect();
verify(requestor).executePost(same(exampleUrl), anyString());
verify(requestor, never()).executeGet(anyString());
@@ -132,6 +160,7 @@ void checkPost_WithBinary() throws IOException {
verify(mockUrlConnection).setUseCaches(false);
verify(mockUrlConnection).setDoOutput(true);
verify(mockUrlConnection).setRequestProperty("Connection", "Keep-Alive");
+ verify(mockUrlConnection, never()).setRequestProperty(eq("Authorization"), anyString());
verify(mockUrlConnection).setRequestMethod(DefaultWebRequestor.HttpMethod.POST.name());
verify(mockUrlConnection).connect();
verify(requestor).executePost(same(exampleUrl), anyString(), anyList());
diff --git a/src/test/java/com/restfb/FakeWebRequestor.java b/src/test/java/com/restfb/FakeWebRequestor.java
index 8e1a60394..7ff8566af 100644
--- a/src/test/java/com/restfb/FakeWebRequestor.java
+++ b/src/test/java/com/restfb/FakeWebRequestor.java
@@ -41,6 +41,8 @@ public class FakeWebRequestor implements WebRequestor {
private Response predefinedResponse;
+ private String accessToken;
+
public FakeWebRequestor() {
this(null);
}
@@ -49,6 +51,11 @@ public FakeWebRequestor() {
this.predefinedResponse = predefinedResponse;
}
+ @Override
+ public void setAccessToken(String accessToken) {
+ this.accessToken = accessToken;
+ }
+
@Override
public Response executeGet(String url) throws IOException {
this.savedUrl = url;