1

I'm experimenting with the JJWT library (and Spring) to try generate/verify JWS tokens.

The following generate method works and generate a valid JWS. However during parse, I get this exception:

io.jsonwebtoken.RequiredTypeException: Cannot convert existing claim value of type 'class java.util.LinkedHashMap' to desired type 'class it.vincenzocorso.webapp.user.dto.UserResponse'. JJWT only converts simple String, Date, Long, Integer, Short and Byte types automatically. Anything more complex is expected to be already converted to your desired type by the JSON Deserializer implementation. You may specify a custom Deserializer for a JwtParser with the desired conversion configuration via the JwtParserBuilder.deserializeJsonWith() method. See https://github.com/jwtk/jjwt#custom-json-processor for more information. If using Jackson, you can specify custom claim POJO types as described in https://github.com/jwtk/jjwt#json-jackson-custom-types
    at io.jsonwebtoken.impl.DefaultClaims.castClaimValue(DefaultClaims.java:169)

This is a utility class I created to wrap JWT generation

@Component
@Scope("singleton")
public class JwsGenerator {
    private final ObjectMapper objectMapper;
    private final Key signKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);

    @Autowired
    public JwsGenerator(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    public <E> String generate(String field, E payload) {
        return Jwts.builder()
                .serializeToJsonWith(new JacksonSerializer(this.objectMapper))
                .claim(field, payload)
                .signWith(this.signKey)
                .compact();
    }

    public <E> E getPayload(String field, String token, Class<E> aClass) {
        try {
            return Jwts.parserBuilder()
                    .deserializeJsonWith(new JacksonDeserializer(this.objectMapper))
                    .setSigningKey(signKey)
                    .build()
                    .parseClaimsJws(token)
                    .getBody()
                    .get(field, aClass);
        } catch(Exception ex) {
            ex.printStackTrace();
            throw new InvalidTokenException();
        }
    }
}

These are my dependencies inside the pom.xml file:

<dependencies>
    [... other dependencies ...]

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-api</artifactId>
        <version>0.11.2</version>
    </dependency>

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-impl</artifactId>
        <version>0.11.2</version>
        <scope>runtime</scope>
    </dependency>

    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt-jackson</artifactId>
        <version>0.11.2</version>
        <scope>compile</scope>
    </dependency>
</dependencies>
Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Vincenzo
  • 45
  • 3
  • 11

1 Answers1

0

I think you need to remove serializeToJsonWith and deserializeJsonWith. Like this

private String generateToken(String principal, String authorities, Integer expirationMinutes) {
    Date expirationTime = Date.from(Instant.now().plus(expirationMinutes, ChronoUnit.MINUTES));
    return Jwts.builder()
      .setSubject(principal)
      .setIssuer(tokenIssuer)
      .setExpiration(expirationTime)
      .setIssuedAt(new Date())
      .claim(authoritiesClaim, authorities)
      .signWith(secretKey)
      .compact();
}

private Jws<Claims> getJwsClaims(String jwt) throws AuthenticationException {
    return Jwts.parserBuilder()
      .requireIssuer(tokenIssuer)
      .setSigningKey(secretKey)
      .build()
      .parseClaimsJws(jwt);
}
Alex Po
  • 1,837
  • 1
  • 24
  • 28