The previous blogs led up to situation where the user is able to authenticate with Facebook thus receiving a Facebook authentication token. Authentication with Facebook results in a request being sent to our REST service. The intent of that request is to authenticate with our Rest service. The request contains the Facebook authentication token and the users Facebook email address (from their Facebook profile). The Rest Service will receive the Facebook authentication token from the client, it then invokes Facebook itself using RestFB to retrieve the users profile. The email address received from the client is now compared with the email address taken from the Facebook profile just retrieved via RestFB.

If the email addresses 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 email addresses 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.

If the email addresses match, the user is authentic. At this point in the previous blog, the server just responds to the client with an email address, i.e. the matched email address. The client stores this and passes it to the service in a request-header on each request. Our REST service will use this each time to extract the user from persistence.

There are a couple of problems with this approach.

The email address in transit is exposed unless HTTPS is used. HTTPS should be used so this is not such a big issue.

The email address alone may not be sufficient information. Date/Time issued or Date/Time expires may be of use so that the token can be expired after a defined idle period.

Data other than the email address may be required, i.e. a bunch of key-value pairs.

A Maven project and HTML5 client are available for download at the bottom of this blog.

Application Flow

The general flow of the application looks like this. Follow these steps if having downloaded the MAven project and HTML5 client.

index.html is accessed by the user

The user clicks the Get Blog button

A preflight request and actual get request are sent to the Service

The services sees the absence of an “Authentication-Token” value in the request header and therefore issues a HTTP status 401 – unauthorised

The client acts on the HTTP 401 by redirecting to login.html

login.html uses the Facebook JavaScript API to log the user into facebook (For demonstration purposes, the user has to click the Facebook login button but this is not necessary as illustrated later)

On successful login to Facebook, the client retrieves the users Facebook profile using the Facebook JavaScript API. The client now has a Facebook authorisation token.

The client subsequently sends a request to the our service to authenticate. The request contains the Facebook authorisation token and the profile’s email address as parameters.

The service then via RestFB fetches the users Facebook profile using the supplied Facebook authorisation token.

The service compares the two email addresses. Matching email addresses means the request is legitimate, the user is authentic and therefore authenticated.

To achieve this authentication, the service uses JJWT to generate a JSON Web Token (JWT) which it includes in the response to the client.

The client stores this token locally in HTML5’s localStorage

The client includes this token in a HTTP header of each subsequent request to the service. The service reads the token to verify authentication each time. Having read the token, the email address of the user is revealed thus the user can be retrieved from persistence.

AuthenticationFilter

AuthenticationFilter.java now tests for the existence of the token. If it exists it parses the token to extract an expiry date, then tests for expiration before extracting the email address from the token. Any issues here results in a HTTP 401 unauthorized response. This filter is executed on every request (except ApplicationController.authenticate). The client JavaScript is equipped to handle the 401 response by redirecting the user to a login page.

Client Highlights

tokenManager.js

This object is responsible for persisting, fetching and removing the Service authentication-token. It consists of a getter and setter for the token along with a “delete” function.

tokenManager.js

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

vartokenManager=(function(){

vartokenHeader="Authentication-Token";

functionsetToken(token){

localStorage.setItem(tokenHeader,token);

}

functiongetToken(){

//HTTP headers don't understand null

returnlocalStorage.getItem(tokenHeader)!=null?

localStorage.getItem(tokenHeader):"";

}

functiondeleteToken(){

localStorage.removeItem(tokenHeader);

}

return{

setToken:setToken,

getToken:getToken,

deleteToken:deleteToken,

tokenHeader:tokenHeader

};

})();

axaxUtils.js

This has the obvious purpose of making AJAX requests but notably, it is responsible for always including the “Authentication-Token” header in every request. Before authorization the value of this token is an empty string. Following authentication, its value is the JWT token. The error handler of the AJAX requests handles HTTP 401 unauthorized responses by redirecting to login.html.

ajaxUtils.js

JavaScript

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

varajaxUtils=(function(){

functiongetHeaders(){

varheaders={};

headers[tokenManager.tokenHeader]=tokenManager.getToken()

returnheaders;

}

functionperformAjaxPostRequest(url,data,successFunc){

$.ajax({

type:'POST',

contentType:"application/json",

headers:getHeaders(),

url:url,

data:JSON.stringify(data),

dataType:"json",

success:successFunc,

error:function(jqXHR,textStatus,errorThrown){

if(jqXHR.status==401){

//not authenticated

window.location='login.html';

}else{

alert('Woops an error has occurred, please try again');

}

}

});

}

functionperformAjaxGetRequest(url,successFunc){

$.ajax({

type:'GET',

headers:getHeaders(),

url:url,

dataType:"json",

success:successFunc,

error:function(jqXHR,textStatus,errorThrown){

if(jqXHR.status==401){

//not authenticated

window.location='login.html';

}else{

alert('Woops an error has occurred, please try again');

}

}

});

}

return{

performAjaxPostRequest:performAjaxPostRequest

,performAjaxGetRequest:performAjaxGetRequest

};

})();

fb.js

Authentication with Facebook is handled in this file. The code is just slightly altered from the example code on the Facebook JavaScript API site. Immediately after the user is authenticated, a request containing the Facebook authorization token (just received) and the users Facebook profile email address is made to our REST Service (specifically, ApplicationController.authenticate()). The response form here is a JWT token. This token is as mentioned previously included in the header of each request to our rest Service (via ajaxUtils.js)

Download

Conclusion

This blog has demonstrated how to create and use a JSON Web Token (JWT) as a means to authenticate a REST Service via Facebook. The client demonstrated is a simple HTM5 application. Both the client and service are configured to communicate cross-origin (CORS). The client could easily be a Cordova/Phonegap application.

The application uses two pages index.html and login.html independently in a non-single-page-application since. In a single page application, the exact same philosophies apply. The physical traditional navigation between index.html and login.html is mainly to illustrate the point more clearly.