1

I am trying to implement OAuth2 authentication in a Dropwizard web-application. I have created the required Authenticator and Authorizer classes and added the code supplied in the Dropwizard manual in my Application's run-method as follows:

environment.jersey().register(new AuthDynamicFeature(
                new OAuthCredentialAuthFilter.Builder<User>()
                .setAuthenticator(new TokenAuthenticator(service))
                .setAuthorizer(new TokenAuthorizer())
                .setPrefix("Bearer")
                .buildAuthFilter()));
        environment.jersey().register(RolesAllowedDynamicFeature.class);
        //If you want to use @Auth to inject a custom Principal type into your resource
        environment.jersey().register(new AuthValueFactoryProvider.Binder<>(User.class));

My required behavior is that after my client has logged in by providing his/her credentials on my login page, I want to redirect the client to a greeting page I have created using Dropwizard Views and is under the path: "/me" as follows:

//After succesfull login and token generation
return Response.seeOther(new URI("/me")).build(); // redirect to greeting page

And my greeting resource looks as follows:

@Path("/me")
@Produces(MediaType.TEXT_HTML)
public class UserResource {

    @GET
    public UserView getView(@Auth User user) {
            return new UserView(user);
    }

}

Currently I am getting a "Credentials are required to access this resource." response after logging in. After some reading on token authentication (nice explanation here) I picked up that the token must be sent from the client in the header of each request. So my question is how do I tell the user's browser (client) to include the token in the header of future requests?

TM00
  • 1,330
  • 1
  • 14
  • 26

1 Answers1

0

I managed to solve this by doing the following:

In order to verify the user, a token must be sent in the header of the request in the form of Authorization: Bearer <token-value>. This token is sent by the server upon authentication and must be stored by the client / user to be sent in future requests. I managed to store the token by using an ajax request when my login form is submitted as follows:

<#-- Handle form submission response to save the token on the client side-->
<script>
    $('#loginForm').submit(function(event){
        event.preventDefault();
        $.ajax({
          url: $(this).attr('action'),
          type: 'POST',
          data : $(this).serialize(),
          dataType: 'json',
          success: function(data){
            //alert("The server says success!!: " +data);
            console.log(data);
            window.sessionStorage.accessToken = data.token;
            window.location = data.url;

          },
          error: function(data){
            alert("The server says error! : ");
            console.log(data);
          }
        });
});
</script>

The login resource then produces JSON which is received in the data-variable in the code above. The required token resides in data.token - which is then stored. I added a second entry in the JSON named "url" to indicate the path to redirect to after successful authentication.

Now the token is stored on the client side when needed. In order to send this token in the request header, I needed to alter my approach to using the Views provided by Dropwizard. Instead of directly requiring authentication, I split the View's resource and the authenticated data resources. To clarify consider the following example. A user logs in, gets the token and then goes to a page that displays his/her username. For the page, a View resource is created with a .ftl file to serve as a template. Something like:

@Path("/me")
@Produces(MediaType.TEXT_HTML)
public class UserResource {


    @GET
    public UserView getView() {
       return new UserView();

    }
}

and...

public class UserView extends View {

    public UserView() {
        super("user.ftl");

    }
}

And user.ftl:

<#include "include/head.html">
<#include "include/header.html">

<!-- Header --> 
<div id ="headerWrapper">
</div>

<div class="container-fluid">

<div id="name">
    <p>Hello user</p>
</div>

</div>

<#include "include/footer.html">

Now to retrieve the username I create a new resource which produces JSON on a new path. For example:

@Path("/getdetails")
@Produces(MediaType.APPLICATION_JSON)
public class UserDetailsResource {

    @GET
    @Timed
    @UnitOfWork
    public User getDetails(@Auth User user) {

        return user;
    }

}

This resource requires authentication and provides JSON from which the username can be retrieved. Now to get the username and place it inside the view, simply add a script to the users.ftl with an ajax request to the getdetails resource, providing the token in the header and using the result to place the username in the view. See script below.

<script>

  $.ajax({
          url: '/getdetails',
          type: 'GET',
          headers: {"Authorization": window.sessionStorage.accessToken},
          dataType: 'json',
          success: function(data){
            //alert("The server says success!!: " +data);
            console.log(data);
            $("#name").text('Hello '+data.username);
          },
          error: function(data){
            alert("The server says error! : ");
            console.log(data);
          }
        });

</script>
TM00
  • 1,330
  • 1
  • 14
  • 26