Securing a Java API with JWTs

Securing a Java API with JWTs

Code Examples / api-integration

Overview

Curity provides a Java Servlet Filter Library to authenticate and authorize requests using OAuth access tokens of various kinds. It contains two OAuthFilter implementations: OAuthJwtFilter and OAuthOpaqueFilter. Both implement javax.servlet.Filter, and can be used to protect APIs built using Java. This tutorial explains an example API that integrates the library.

Create a Java API

The example code can be downloaded from this page’s GitHub link and uses the Spark Framework in order to implement a minimal Java API. An OAuth JWT filter is integrated and configured to run before the API’s own logic:

public class SparkServerExample implements SparkApplication
{
    private void initStandalone() throws ServletException
    {
        port(9090);
        OAuthFilter filter = getJwtFilter();
        before(((request, response) -> {
            filter.doFilter(request.raw(), response.raw(), null);
            if(response.raw().isCommitted())
            {
                halt();
            }
        }));
    }
}

Configuration

The code example uses the following properties to point to the Curity Identity Server’s JWKS endpoint. This returns details of public keys that can be used by the API to verify the digital signature of received JWT access tokens:

private OAuthFilter getJwtFilter() throws ServletException
{
    EmbeddedSparkJwtFilterConfig filterParams = new EmbeddedSparkJwtFilterConfig(
            "localhost",
            "8443",
            "/oauth/v2/oauth-anonymous/jwks",
            "read",
            "3600");

    OAuthFilter filter = new OAuthJwtFilter();
    filter.init(filterParams);
    return filter;
}

Run and Test the API

Ensure that Java 8 is installed and then run the API with Maven according to the GitHub repository’s README file. The API will then listen for requests on port 9090, and we can call the simple secured REST API endpoint via a curl request. In the below example we are not sending a real JWT, so the filter will reject the request, returning an HTTP response with the standard 401 unauthorized status code.

curl -H "Authorization: Bearer XXX" http://localhost:9090/hello_world

To get a real JWT access token for the CURL request you can use OAuth Tools. See the below video for details on how to use OAuth tools to run the Code Flow and then introspect its token to receive a JWT:

JWKS Processing

The API will receive JWT access tokens and will then read the kid value from the JWT header. The corresponding token signing public key will then be downloaded from the Curity Identity Server at the below URL, as a JSON Web Key. This public key will then be cached for future API requests, to ensure efficiency.

  • https://localhost:8443/oauth/v2/oauth-anonymous/jwks

JWT Processing

Once the OAuth filter has the token signing public key it will use it to verify the JWT signature when HTTP requests are received, as explained in JWT Security Best Practices. The filter will ensure that the token is not expired and can also check additional claims including issuer and audience.

Securing Access to API Data

Once the above OAuth processing completes successfully, the filter allows processing to move on to the API’s logic. The filter also makes the scopes and claims available in an AuthenticatedUser object:

get("/hello_world", (req, res) -> {
    AuthenticatedUser user = (AuthenticatedUser)req.attribute(OAuthFilter.PRINCIPAL);
    return "Hello "+ user.getSubject() + " from an OAuth protected world!";
});

A real API would then use the data in the AuthenticatedUser to enforce access to secured resources, as explained in the below articles:

Conclusion

The Curity Java OAuth Filter enables you to secure your Java or Kotlin APIs with only a small amount of code. The Java OAuth Filter library also has many other features, such as the ability to introspect opaque tokens. See the library’s README file for details.

Keep up with our latest articles and how-tos RSS feeds.