0

My System: A Security Provider generates JWT Tokens based on a Private Key. The Private Key belongs to a Certificate which will expire.

  1. Is it possible to set multiple Public Keys in Resource Server?

I would like to do a rolling Update, so for a short time it has to Support the old Public Key and a new Public Key. Thats a default use case because the certificates expires.?

  1. Can oauth/token_key deliver multiple Keys or just one?

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        Resource resource = new ClassPathResource("public.txt");
        String publicKey = null;
        try {
            publicKey = IOUtils.toString(resource.getInputStream());
        } 
        catch (final IOException e) { throw new RuntimeException(e);
    }
        **converter.setVerifierKey(publicKey);**
        **converter.setVerifierKeys(publicKey1, publicKey2);?**
        return converter;
    }
    

http://www.baeldung.com/spring-security-oauth-jwt

Thanks

farhan
  • 458
  • 2
  • 8
  • 24
kirill1722
  • 21
  • 1
  • Were you able to have multiple keys? – yyunikov Oct 27 '17 at 11:01
  • We have a similar problem and wondering if there is a more straightforward way to achieve this in Spring Security 5.3. Other threads indicate this is a newer feature of SS 5.3. https://stackoverflow.com/questions/60031919/how-do-i-use-multiple-jwk-set-uri-values-in-the-same-spring-boot-app Also multi-tenancy appears to be part of SS 5.3 - but not sure how this would work for multiple keys. https://docs.spring.io/spring-security/site/docs/current/reference/html5/#webflux-oauth2resourceserver-multitenancy – Rhett Jul 23 '20 at 15:11

1 Answers1

2

This is not standard practice and Spring's jwt framework does not support multiple security providers (or multiple active verifier keys) out-of-the-box. Having said that, what you wish to do is theoretically possible. You would have wire-up a new implementation for the AccessTokenConverter similar to the JwtAccessTokenConverter, but implement the decode method like this:

protected Map<String, Object> decode(String token) {
    try {
        Jwt jwt = JwtHelper.decodeAndVerify(token, verifier1);
        String content = jwt.getClaims();
        Map<String, Object> map = objectMapper.parseMap(content);
        if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
            Integer intValue = (Integer) map.get(EXP);
            map.put(EXP, new Long(intValue));
        }
        return map;
    }
    catch (Exception e) {
      //try the other verifier
      try {
        Jwt jwt = JwtHelper.decodeAndVerify(token, verifier2);
        String content = jwt.getClaims();
        Map<String, Object> map = objectMapper.parseMap(content);
        if (map.containsKey(EXP) && map.get(EXP) instanceof Integer) {
            Integer intValue = (Integer) map.get(EXP);
            map.put(EXP, new Long(intValue));
        }
        return map;
    }
    catch(InvalidTokenException te){
       throw te;
    }catch (Exception e) {

        throw new InvalidTokenException("Cannot convert access token to JSON", e);
    }
    }
}

Essentially, the code above trys to verify the first key but if any exception is thrown it will try to validate the second one.

I would also suggest you override to tokenConverter to split the provided token by some delimiter like a "." or something that is not in the encoding char set of your hash algo that generates the verifier key. Then when calling the you could do: setVerifierKey("verifierKey1" + delimiter + "verifierKey2")

  • Note: I have not tested this code, just some thoughts :)
cosbor11
  • 14,709
  • 10
  • 54
  • 69