0

I'm developing a REST API and I decided to use JWT for authentication/security. There is a service to handle the login validation, and a filter to bound to every service that will need authentication.

LoginService.java:

@Path("login")
public class LoginService {

    private final static long EXPIRATION_TIME = 60000;

@POST
@Produces("application/json")
@Consumes("application/json")
public Response authenticateUser(Credentials c) {
    Users login;
    UsersDAO u = new UsersDAO();
    try {
        login = u.getAuthentication(c);

        String token = generateToken(login.getIdUser(), login.getLogin(), login.getRole());

        // Return the token on the response
        return Response.ok().header(AUTHORIZATION, "Bearer " + token).build();
    } catch (Exception e){
        System.out.println("Exception: " + e.toString());
        return Response.status(Response.Status.UNAUTHORIZED).build();
    }      
}

private String generateToken(int id, String login, int role) {
    long nowMillis = System.currentTimeMillis();
    Date now = new Date(nowMillis);

    //TODO generate key (or retrieve it from file/database?)
    Key key;

    String jwtToken = Jwts.builder()
            .setSubject(login)
            .setIssuer("my_company")
            .setIssuedAt(now)
            .setExpiration(new Date(nowMillis + EXPIRATION_TIME))
            .claim("role", role)
            .signWith(SignatureAlgorithm.HS512, key)
            .compact();
    return jwtToken;
    }

JWTTokenFilter.java:

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

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

    String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);

    String token = authorizationHeader.substring("Bearer".length()).trim();

    try {    
        // TODO generate key (or retrieve it from file/database?)
        Key key;
        Jwts.parser().setSigningKey(key).parseClaimsJws(token);

    } catch (Exception e) {
        requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
    }
    }
}  

I've been doing some research, but I'm still not sure how to manage the key generation/validation. My doubts:

  • If I create the key when authenticating, how could I pass this same key to the filter? I've seen some code examples where key is generated both when authenticating and validating using random numbers, which have no sense to me as the key generated wouldn't be the same. What am I missing there?
  • Other option would be to store the key in filesystem, so both authenticating and validating processes would be able to access to the same key. What downsides (if any) would this bring to the implementation? Is there any good library or framework to manage the key generation and access in filesystem(or even database)?

Notice that I don't want to pass the key to the clients, so they had to authenticate once in a while in order to refresh the token as they won't have access to the expiration date. This topic doesn't fit to my case, and this is quite complete but doesn't bring any example

Community
  • 1
  • 1
Juan
  • 1,949
  • 1
  • 15
  • 22

1 Answers1

5

If you generate the symmetric key at runtime you could share it between the filter and the login class using spring injection or with a static variable

But consider that restarting server will invalidate all issued JWT. If this is not the desired behaviour you need to persist the key in a properties file or in the database

Using Jjwt, you can do:

//generate a random HMAC
Key key = MacProvider.generateKey(SignatureAlgorithm.HS256);

//Get the key data
byte keyData[]= key.getEncoded();
//Store data in a file...

//Build key
Key key = new SecretKeySpec(keyData, SignatureAlgorithm.HS256.getJcaName());
pedrofb
  • 37,271
  • 5
  • 94
  • 142