I'm trying to get a new access token using a refresh token in Spring Boot with OAuth2. It should be done as following: POST: url/oauth/token?grant_type=refresh_token&refresh_token=...
.
It works fine if I'm using InMemoryTokenStore because the token is tiny and contains only digits/letters but right now I'm using a JWT token and as you probably know it has 3 different parts which probably are breaking the code.
I'm using the official migration guide to 2.4.
When I try to access the URL above, I'm getting the following message:
{
"error": "invalid_token",
"error_description": "Cannot convert access token to JSON"
}
How do I pass a JWT token in the params? I tried to set a breakpoint on that message, so I could see what the actual argument was, but it didn't get to it for some reason.
/**
* The Authorization Server is responsible for generating tokens specific to a client.
* Additional information can be found here: https://www.devglan.com/spring-security/spring-boot-security-oauth2-example.
*/
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Value("${user.oauth2.client-id}")
private String clientId;
@Value("${user.oauth2.client-secret}")
private String clientSecret;
@Value("${user.oauth2.accessTokenValidity}")
private int accessTokenValidity;
@Value("${user.oauth2.refreshTokenValidity}")
private int refreshTokenValidity;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient(clientId)
.secret(bCryptPasswordEncoder.encode(clientSecret))
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.scopes("read", "write", "trust")
.resourceIds("api")
.accessTokenValiditySeconds(accessTokenValidity)
.refreshTokenValiditySeconds(refreshTokenValidity);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.tokenStore(tokenStore())
.userApprovalHandler(userApprovalHandler())
.accessTokenConverter(accessTokenConverter());
}
@Bean
public UserApprovalHandler userApprovalHandler() {
ApprovalStoreUserApprovalHandler userApprovalHandler = new ApprovalStoreUserApprovalHandler();
userApprovalHandler.setApprovalStore(approvalStore());
userApprovalHandler.setClientDetailsService(clientDetailsService);
userApprovalHandler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
return userApprovalHandler;
}
@Bean
public TokenStore tokenStore() {
JwtTokenStore tokenStore = new JwtTokenStore(accessTokenConverter());
tokenStore.setApprovalStore(approvalStore());
return tokenStore;
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final RsaSigner signer = new RsaSigner(KeyConfig.getSignerKey());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter() {
private JsonParser objectMapper = JsonParserFactory.create();
@Override
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String content;
try {
content = this.objectMapper.formatMap(getAccessTokenConverter().convertAccessToken(accessToken, authentication));
} catch (Exception ex) {
throw new IllegalStateException("Cannot convert access token to JSON", ex);
}
Map<String, String> headers = new HashMap<>();
headers.put("kid", KeyConfig.VERIFIER_KEY_ID);
return JwtHelper.encode(content, signer, headers).getEncoded();
}
};
converter.setSigner(signer);
converter.setVerifier(new RsaVerifier(KeyConfig.getVerifierKey()));
return converter;
}
@Bean
public ApprovalStore approvalStore() {
return new InMemoryApprovalStore();
}
@Bean
public JWKSet jwkSet() {
RSAKey.Builder builder = new RSAKey.Builder(KeyConfig.getVerifierKey())
.keyUse(KeyUse.SIGNATURE)
.algorithm(JWSAlgorithm.RS256)
.keyID(KeyConfig.VERIFIER_KEY_ID);
return new JWKSet(builder.build());
}
}