I am trying to setup a prototype environment and communicate with facebook. I have set up a test java application and I serve it through my static ip. For the facebook part I have implemented the example of this friend
http://www.richardnichols.net/2010/06/implementing-facebook-oauth-2-0-authentication-in-java/
To solve any questions you may have regarding general connectivity with facebook, I have started my own page tab application with the below information
Page Tab URL: http://[MYIP]:8080/facebookContest/app/index.do Secure Page Tab URL:https://[MYIP]:8443/facebookContest/app/index.do
I have already checked that both urls are functional and do return my "hello world" localy. I added this application to a test facebook page that I created, using this url: http://www.facebook.com/dialog/pagetab?app_id=[MYAPPID]&next=http://[MYIP]:8080/facebookContest/app/index.do
FYI, If I disable all facebook authorization/communication logic, the static content of the application is shown correctly inside facebook. So it seems that an initial communication with facebook is established.
The Facebook.java code
package com.facebookContest.fb;
import com.visural.common.StringUtil;
public class Facebook {
// get these from your FB Dev App
private static final String api_key = "[MYKEY]";
private static final String secret = "MYSECRET";
private static final String client_id = "[MYKEY]";
// set this to your servlet URL for the authentication servlet/filter
private static final String redirect_uri = "http://[MYIP]:8080/facebookContest/app/index.do";
/// set this to the list of extended permissions you want
private static final String[] perms = new String[] {"publish_stream", "email"};
public static String getAPIKey() {
return api_key;
}
public static String getSecret() {
return secret;
}
public static String getLoginRedirectURL() {
return "http://graph.facebook.com/oauth/authorize?client_id=" +
client_id + "&display=page&redirect_uri=" +
redirect_uri+"&scope="+StringUtil.delimitObjectsToString(",", perms);
}
public static String getAuthURL(String authCode) {
return "http://graph.facebook.com/oauth/access_token?client_id=" +
client_id+"&redirect_uri=" +
redirect_uri+"&client_secret="+secret+"&code="+authCode;
}
}
the FacebookUserService.java
package com.facebookContest.fb;
import java.net.URL;
import org.json.JSONObject;
import com.visural.common.IOUtil;
class FacebookUserService {
public void authFacebookLogin(String accessToken, int expires) {
try {
JSONObject resp = new JSONObject(
IOUtil.urlToString(new URL("https://graph.facebook.com/me?access_token=" + accessToken)));
String id = resp.getString("id");
String firstName = resp.getString("first_name");
String lastName = resp.getString("last_name");
String email = resp.getString("email");
// custom code
} catch (Throwable ex) {
throw new RuntimeException("failed login", ex);
}
}
}
My filter class FBOAuth.java code:
package com.facebookContest.fb;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import com.visural.common.StringUtil;
public class FBOAuth implements Filter {
@Autowired
FacebookUserService facebookUserService;
public void init(FilterConfig fc) throws ServletException {
}
public void doFilter(ServletRequest srvlReq, ServletResponse srvReq, FilterChain fc) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)srvlReq;
HttpServletResponse response = (HttpServletResponse)srvReq;
String code = srvlReq.getParameter("signed_request");
if (StringUtil.isNotBlankStr(code)) {
String authURL = Facebook.getAuthURL(code);
URL url = new URL(authURL);
try {
String result = readURL(url);
String accessToken = null;
Integer expires = null;
String[] pairs = result.split("&");
for (String pair : pairs) {
String[] kv = pair.split("=");
if (kv.length != 2) {
throw new RuntimeException("Unexpected auth response");
} else {
if (kv[0].equals("access_token")) {
accessToken = kv[1];
}
if (kv[0].equals("expires")) {
expires = Integer.valueOf(kv[1]);
}
}
}
if (accessToken != null && expires != null) {
facebookUserService.authFacebookLogin(accessToken, expires);
response.sendRedirect("http://[MYIP]:8080/facebookContest/app/index.do");
} else {
throw new RuntimeException("Access token and expires not found");
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
private String readURL(URL url) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
InputStream is = url.openStream();
int r;
while ((r = is.read()) != -1) {
baos.write(r);
}
return new String(baos.toByteArray());
}
public void destroy() {
}
}
on line 45
String result = readURL(url);
The filter does a get with the following url as copied from the debugger -seems correct to me-
The exception thrown on String result = readURL(url);
is this
java.io.IOException: Server returned HTTP response code: 400 for URL: http://graph.facebook.com/oauth/access_token?client_id=[MYAPPID]&redirect_uri=http://[MYIP]:8080/facebookContest/app/index.do&client_secret=[MYAPPSECRET]&code=GdbObQHyYPvIKnkShMBv8Wry-UNPAQWAMmSVyXe5n_k.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTM1ODUwNDQ4OCwicGFnZSI6eyJpZCI6IjM1NDcxOTMwNDYzNTQ4MSIsImxpa2VkIjpmYWxzZSwiYWRtaW4iOnRydWV9LCJ1c2VyIjp7ImNvdW50cnkiOiJnciIsImxvY2FsZSI6ImVsX0dSIiwiYWdlIjp7Im1pbiI6MjF9fX0
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
at java.net.URL.openStream(URL.java:1037)
at com.facebookContest.fb.FBOAuth.readURL(FBOAuth.java:78)
at com.facebookContest.fb.FBOAuth.doFilter(FBOAuth.java:44)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Ιαν 18, 2013 12:21:30 ΜΜ org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [facebookContest] in context with path [/facebookContest] threw exception
java.lang.RuntimeException: java.io.IOException: Server returned HTTP response code: 400 for URL: http://graph.facebook.com/oauth/access_token?client_id=[MYAPPID]&redirect_uri=http://[MYIP]:8080/facebookContest/app/index.do&client_secret=[MYAPPSECRET]&code=GdbObQHyYPvIKnkShMBv8Wry-UNPAQWAMmSVyXe5n_k.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTM1ODUwNDQ4OCwicGFnZSI6eyJpZCI6IjM1NDcxOTMwNDYzNTQ4MSIsImxpa2VkIjpmYWxzZSwiYWRtaW4iOnRydWV9LCJ1c2VyIjp7ImNvdW50cnkiOiJnciIsImxvY2FsZSI6ImVsX0dSIiwiYWdlIjp7Im1pbiI6MjF9fX0
at com.facebookContest.fb.FBOAuth.doFilter(FBOAuth.java:71)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
at java.lang.Thread.run(Thread.java:722)
Caused by: java.io.IOException: Server returned HTTP response code: 400 for URL: http://graph.facebook.com/oauth/access_token?client_id=[MYAPPID]&redirect_uri=http://[MYIP]:8080/facebookContest/app/index.do&client_secret=[MYAPPSECRET]&code=GdbObQHyYPvIKnkShMBv8Wry-UNPAQWAMmSVyXe5n_k.eyJhbGdvcml0aG0iOiJITUFDLVNIQTI1NiIsImlzc3VlZF9hdCI6MTM1ODUwNDQ4OCwicGFnZSI6eyJpZCI6IjM1NDcxOTMwNDYzNTQ4MSIsImxpa2VkIjpmYWxzZSwiYWRtaW4iOnRydWV9LCJ1c2VyIjp7ImNvdW50cnkiOiJnciIsImxvY2FsZSI6ImVsX0dSIiwiYWdlIjp7Im1pbiI6MjF9fX0
at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1625)
at java.net.URL.openStream(URL.java:1037)
at com.facebookContest.fb.FBOAuth.readURL(FBOAuth.java:78)
at com.facebookContest.fb.FBOAuth.doFilter(FBOAuth.java:44)
... 16 more
I believe that my spring/hibernate configuration is not needed, as the application seems to function properly. If anyone needs it though there is no problem providing it.
I have already read several posts indicating the error on the redirect_uri. I have checked it over and over and this is not the case. The application tab is installed on the page with the exact uri that I call when the exception is thrown.
I also couldn't find an answer here HTTP 400 error when trying to get access token
Please feel free to direct me on any piece of documentation that might help.
Thanks very much!
I managed to solve this problem so I thought I could share the solution, if anyone else reaches this problem.
The error message of the exception comes with a json response with more information. What you could do to see the response is just paste the url that you construct to any browser. I do it as shown below.
public static String getAuthURL(String authCode) {
return "https://graph.facebook.com/oauth/access_token?"+
"client_id=" + client_id +
"&redirect_uri=" + redirect_uri +
"&client_secret=" + secret +
"&code=" + authCode;
}
The error message will be displayed. And will give you information about what went wrong. In my case I was trying the authorization GET through http and the error message directed that such action, should be done over https.
I corrected this problem and I finally got the access_token.