Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authenticating with an API key in JAX-RS

We'd like to secure our rest api using an api key. Here are the requirements:

  1. Public-facing services require an api key.
  2. "Private" services can only accept a call from within the cluster, not the outside world.
  3. Each api identifies a user, and the User object must be available to the rest service.

Is there some standard way to do this in a JAX-RS app? (We're using Resteasy.)

I've read all about filters, interceptors and basic auth, but it isn't clear to me what's the best approach.

In an earlier version of the app we had a roll-your-own solution in which public services ran on a public port and private ones on a private port. There was a custom api key lookup that set the User object as a variable into the rest service object.

I can't figure out how to do either of these things using standard JAX-RS.

like image 359
ccleve Avatar asked Nov 25 '14 22:11

ccleve


People also ask

How do I authenticate API using API key?

You can pass the API key via Basic Auth as either the username or password. Most implementations pair the API key with a blank value for the unused field (username or password). You will need to base64-encode the 'username:password' content, but most request libraries do this for you.

Is API key used for authentication?

API keys are for projects, authentication is for users The main distinction between these two is: API keys identify the calling project — the application or site — making the call to an API. Authentication tokens identify a user — the person — that is using the app or site.


1 Answers

Using a filter to intercept the request

This kind of authentication could be achieved with a ContainerRequestFilter, intercepting the requests to your resource methods.

The filter will be used to extract the API key from the request and validate it. If the API key is not valid, the request will be refused. Otherwise, the request will proceed to the resource methods.

Have a look at the following piece of code. The ContainerRequestContext API can be used to extract information from the HTTP request:

@Provider
@Priority(Priorities.AUTHENTICATION)
public class AuthenticationFilter implements ContainerRequestFilter {

    @Override
    public void filter(ContainerRequestContext requestContext) throws IOException {

        // Extract and validate the API key from the request
        String apiKey = requestContext.getHeaderString("API-Key");
        ...
    }
}

Also have a look at this answer I wrote a while ago about authentication with tokens in JAX-RS. There you will find plenty of details that can be useful to address the situation you described in your question.

Identifying the user

During the authentication process, you must be able to identify the user who is performing the request. To propagate this information to your resource classes/methods you could:

  1. Override the SecurityContext and inject it into your resource classes/methods.
  2. Use a CDI Event and a producer method to create an object that contains the user identifier that can be injected in your resource classes/methods.

For more details on the these approaches, refer to the answer I mentioned above.

Binding the filter to some resource classes/methods

By default, the filters are global (it means they are executed for all the resource methods of your application). To bind the filter to a subset of resource methods or classes, you could use name binding annotations.

like image 191
cassiomolin Avatar answered Sep 21 '22 11:09

cassiomolin