Develop a Facebook-App with Spring-Social – Part VI: Sign In Users Through The Canvas-Page

In this series of Mini-How-Tow’s I will describe how to develop a facebook app with the help of Spring-Social

In the last part of this series, we refactored our authentication-concept, so that it can be replaced by Spring Security later on more easy.

In this part, we will turn our app into a real Facebook-App, that is rendered inside Facebook and signs in users through the signed_request.

The Source is With You

You can find the source-code on http://juplo.de/git/examples/facebook-app/ and browse it via gitweb. Check out part-06 to get the source for this part of the series.

What The *#&! Is a signed_request

If you add the platform Facebook Canvas to your app, you can present your app inside of Facebook. It will be accessible on a URL like https://apps.facebook.com/YOUR_NAMESPACE then and if a (known!) user accesses this URL, facebook will send a signed_request, that already contains some data of this user an an authorization to retrieve more.

Sign In Users With signed_request In 5 Simple Steps

As I first tried to extend the simple example, this article-series is based on, I stumbled across multiple misunderstandings. But now, as I guided you around all that obstacles, it is fairly easy to refine our app, so that is can sign in users through the signed_request, send to a Canvas-Page.

You just have to:

  1. Add the platform “Facebook Canvas” in the settings of your app and choose a canvas-URL.
  2. Reconfigure your app to support HTTPS, because Facebook requires the canvas-URL to be secured by SSL.
  3. Configure the CanvasSignInController.
  4. Allow the URL of the canvas-page to be accessed unauthenticated.
  5. Enable Sign-Up throw your canvas-page.

That is all, there is to do. But now, step by step…

Step 1: Turn Your App Into A Canvas-Page

Go to the settings-panel of your app on https://developers.facebook.com/apps and click on Add Platform. Choose Facebook Canvas. Pick a secure URL, where your app will serve the canvas-page.

For example: https://localhost:8443.

Be aware, that the URL has to be publicly available, if you want to enable other users to access your app. But that also counts for the Website-URL http://localhost:8080, that we are using already.

Just remember, if other people should be able to access your app later, you have to change these URL’s to something, they can access, because all the content of your app is served by you, not by Facebook. A Canvas-App just embedds your content in an iFrame inside of Facebook.

Step 2: Reconfigure Your App To Support HTTPS

Add the following lines to your src/main/resources/application.properties:

server.port: 8443
server.ssl.key-store: keystore
server.ssl.key-store-password: secret

I have included a self-signed keystore with the password secret in the source, that you can use for development and testing. But of course, later, you have to create your own keystore with a certificate that is signed by an official certificate authority, that is known by the browsers of your users.

Since your app now listens on 8443 an uses HTTPS, you have to change the URL, that is used for the platform “Website”, if you want your sign-in-page to continue to work in parallel to the sign-in through the canvas-page.

For now, you can simply change it to https://locahost:8443/ in the settings-panel of your app.

Step 3: Configure the CanvasSignInController

To actually enable the automatic handling of the signed_request, that is, decoding the signed_request and sign in the user with the data provided in the signed_request, you just have to add the CanvasSignInController as a bean in your SocialConfig:

@Bean
public CanvasSignInController canvasSignInController(
    ConnectionFactoryLocator connectionFactoryLocator,
    UsersConnectionRepository usersConnectionRepository,
    Environment env
    )
{
  return
      new CanvasSignInController(
          connectionFactoryLocator,
          usersConnectionRepository,
          new UserCookieSignInAdapter(),
          env.getProperty("facebook.app.id"),
          env.getProperty("facebook.app.secret"),
          env.getProperty("facebook.app.canvas")
          );
}

Step 4: Allow the URL Of Your Canvas-Page To Be Accessed Unauthenticated

Since we have “secured” all of our pages except of our sign-in-page /signin*, so that they can only be accessed by an authenticated user, we have to explicitly allow unauthenticated access to our new special sign-in-page.

To achieve that, we have to refine our UserCookieInterceptor as follows. First add a pattern for all pages, that are allowed to be accessed unauthenticated:

private final static Pattern PATTERN = Pattern.compile("^/signin|canvas");

Then match the requests against this pattern, instead of the fixed string /signin:

if (PATTERN.matcher(request.getServletPath()).find())
  return true;

Step 5: Enable Sign-Up Through Your Canvas-Page

Facebook always sends a signed_request to your app, if a user visits your app through the canvas-page. But on the first visit of a user, the signed_request does not authenticate the user. In this case, the only data that is presented to your page is the language and locale of the user and his or her age.

Because the data, that is needed to sign in the user, is missing, the CanvasSignInController will issue an explicit authentication-request to the Graph-API via a so called Server-Side Log-In. This process includes a redirect to the Login-Dialog of Facebook and then a second redirect back to your app. It requires the specification of a full absolute URL to redirect back to.

Since we are configuring the canvas-login-in, we want, that new users are redirected to the canvas-page of our app. Hence, you should use the Facebook-URL of your app: https://apps.facebook.com/YOUR_NAMESPACE. This will result in a call to your canvas-page with a signed_request, that authenticates the new user, if the user accepts to share the requested data with your app.

Any other page of your app would work as well, but the result would be a call to the stand-alone version of your app (the version of your app that is called the “Website”-platform of your app by Facebook), meaning, that your app is not rendered inside of Facebook. Also it requires one more call of your app to the Graph-API to actually sign-in the new user, because Facebook sends the signed_request only the canvas-page of your app.

To specify the URL I have introduced a new attribute facebook.app.canvas that is handed to the CanvasSignInController. You can specifiy it, when starting your app:

mvn spring-boot:run \
    -Dfacebook.app.id=YOUR_ID \
    -Dfacebook.app.secret=YOUR_SECRET \
    -Dfacebook.app.canvas=https://apps.facebook.com/YOUR_NAMESPACE

Be aware, that this process requires the automatic sign-up of new users, that we enabled in part 3 of this series. Otherwise, the user would be redirected to the sign-up-page of your application, after he allowed your app to access the requested data. Obviously, that would be very confusing for the user, so we really nead automati sign-up in this use-case!

Coming Next…

In the next part of this series, I will show you, how you can debug the calls, that Spring Social makes to the Graph-API, by turning on the debugging of the classes, that process the HTTP-requests and -responses, that your app is making.

Funded by the Europian Union

This article was published in the course of a resarch-project, that is funded by the European Union and the federal state Northrhine-Wetphalia.

Europäische Union: Investitionen in unsere Zukunft - Europäischer Fonds für regionale Entwicklung EFRE.NRW 2014-2020: Invesitionen in Wachstum und Beschäftigung

Leave a Reply

Your email address will not be published. Required fields are marked *