CORS Stateless REST Service with Facebook Authentication

Introduction

This blog will demonstrate one way to enable authentication with Facebook on a Stateless CORS enabled REST service.

The CORS REST service will be created using the Ninja Framework.

Facebook authentication is via the Facebook JavaScript API.

RestFB is used to consolidate the authentication with the REST Service.

This blog is follows on from previous blogs:

  1. CORS Cross-Origin-Resource-Sharing is detailed here http://outbottle.com/understanding-cross-origin-resource-sharing-cors-by-example/.
  2. Creating the REST Service and HTML5 Client is detailed here http://outbottle.com/cors-stateless-rest-service-with-detached-html5-client/.

This blog focuses on adding authentication using Facebook to the application.

The HTML5 application and NinjaFramework Maven application are available for download at the bottom of this page.

(Disclaimer…. the term REST is used loosely…)

Why the Ninja Framework?

  • Excellent MVC framework.
  • Just works, out of the box.
  • Comes equipped with all common web-application components, e.g. JPA, Dependency Injection etc.
  • Effortless to get up and running.
  • Is stateless by default.
  • It’s an excellent choice for creating REST services for HTML5 clients, be they web applications or Cordova/PhoneGap mobile applications.

However, if you prefer Spring or Spark or the likes, no worries, the exact same principals apply. It’s a simple/minimalist application to setup in any framework.

Facebook Application

To get a Facebook application ID and secret, follow the instructions provided by Facebook here: https://developers.facebook.com/

Making it work – The OAuth 2 Dance

  • Using the Facebook JavaScript API the user logs into Facebook and receives a Facebook authentication token.
  • Using the Facebook JavaScript API the user retrieves their Facebook user profile.

     

  • The HTML5 client application sends the users Facebook profile (or part thereof) along with the Facebook authentication token to our REST service (over HTTPS).
  • Our REST service receives the Facebook authentication token from the client and retrieves the users Facebook profile using that token and RestFB.
  • Our REST service then compares the profile it received from Facebook (via RestFB) to the profile it received from the HTML5 client.
    • If the profiles match, the user is authentic. (Now the REST service generates a token for the client which identifies that client. Any time the client wants to invoke the service, it supplies that token).
    • If the profiles do not match, the client supplied a valid Facebook authentication token but for a different account; reject this user.
    • If the profile cannot be retrieved, the client may have supplied an invalid Facebook authentication token; reject this user.

This OAuth process is detailed here, there’s no point in me reinventing the wheel with diagrams etc. This resource is well work a look if in doubt about the steps outlined above.

Points of note on the above

When both profiles match we have a legitimate user, here’s what will happen or can happen next.

  • Our REST service will generate a token that is passed back to the client.
    • The token contains an ID for the client. Anytime the client makes a request, it must supply the token for identification purposes.
    • The token can optionally contain a timestamp which can be used to expire the token after an elapsed time.
    • A token would ordinarily be generated in accordance with the JSON Web Token (JWT) standard. This adds a measure of security. It also allows the token to contain a complex object (relatively speaking) and still be included in the header of the request.
  • Alternatively, to really tie our application to the Facebook authentication, RestFB can be consulted with every request exactly as it was for the initial authentication request. This means that when the Facebook authentication expires (or the user logs out) they are effectively logged out of our application / REST Service too. However, it’s probably best if the server issues a token (JWT) for this also in order to add a measure of security around passing back and forth the Facebook authentication token and email address.

Working Example

This blog details how to setup the Rest Service and the HTML5 client (This one provides details on Cross-Origin-Resource-Sharing (CORS) and how to implement it in general).

Follow those steps to end up with a REST(ish) service and a HTML5 client. Now follow these simple steps to add Facebook authentication to the application.

Serverside application

Add the Facebook application secret to the properties

Add the following property to application.conf

facebook.secret = 3e1f316b4b4d84545454545e5dc …where the value is YOUR Facebook application secret.

Adding RestFB to the POM

 

Create the FacebookAuthenticateRequest bean

 

Inject the ninjaPropeties facility

In ApplicationController.java inject the following member in order to retreive the Facebook application secret from application.conf

 Implement the authentication end point

Implement the authentication filter

Add this filter to the corresponding controller methods

 

Client-side HTML5 Application

The client application consists of two pages, login.html and index.html. When index.html is loaded the user is presented with a “get blog” button which will invoke a request to our service to fetch a blog.

Here’s what happens next:

  1. The request to “get blog” contains a HTTP Header called ‘Token-Email’
  2. This ‘Token-Email’ value is retrieved from HTML5’s localStorage. It will initially have a null value.
  3. The Server sees that this “Token-Email” header value is empty so it issues a HTTP 401 Unauthorized response.
  4. The client JavaScript handles this 401 by redirecting to login.html.
  5. login.html will log the user in to facebook.
  6. When the user is successfully logged into Facebook, Facebook issues an authentication token.
  7. The client will then authenticate with our Rest service by passing the Facebook authentication token (just received from Facebook) and email address to our service authentication end-point.
  8. The client receives a token issued by our Rest service and pops it into HTML5’s “localStorage”.
  9. A redirect back to index.html occurs.
  10. The user will hit the “get blog” button again. This time the “Token-Email” Header will have a value which is accepted by the Rest service so the blog is retrieved.

In practice, the token issued by our Rest Service would ideally be a JWT token but the concept is the same. Using JWT adds a measure of security.

Index.html

We can fetch a blog; demonstrating a GET request. We can also edit a blog; demonstrating a POST request.

login.html

Note that the need to press the Facebook login button can be eliminated by uncommenting //facebookLogin();  in the window.fbAsyncInit  function.

 

fb.js

Here’s the JS for the facebook authentication. It’s adapted from the sample code supplied by Facebook. The only notable thing about it is the authenticateWithServerApplication  function which is invoked on a successful Facebook login.

 

Downloads

Be sure to change the following two properties to your own Facebook application values.

  1. The appId  property in the window.fbAsyncInit  function in fb.js
  2. The facebook.secret  property in the NinjaFramework application in the application.conf file

CORS Enabled NinjaFramework Facebook Authentication Maven project download: CorsRestServiceFBAuthenticationService

CORS Enabled Facebook Authentication HTML5 project download: CORSRestServiceFBAuthenticationClient

Note: The HTML5 application must be run out of an appliaction server such as the Netbeans HTML5 Chrome plugin/app or Mongoose for example. Running direct from the file system will not work.

 

Conclusion

OK, so that was a lot to take in….. It was also a little difficult to articulate all of that in a coherent fashion due to the fact that the flow sprawls back and forth across three layers so perhaps the best thing to do might be to download the code and try it out.

If coherent the following should have been demonstrated:

  • Logging in to Facebook using the Facebook JavaScript API.
  • Retrieving the current users profile using the Facebook JavaScript API.
  • Authentication with our Rest Service using a stateless token approach using the Facebook authentication token and email address.
  • Handling of unauthenticated/unauthorized requests by redirecting to the login page.

What has not been demonstrated:

  • Adhering to standards and best practices by having our Rest service issue a JWT (JSON Web Token) rather than just issuing a string (email address) as the token.

This JWT approach is described here in this subsequent blog http://outbottle.com/json-web-token-jwt-with-cors-stateless-rest-service-with-facebook-authentication/

Questions, comments and critique are always welcome.

 

Hat Tip: