In my Spring Bott application I have configured own OAuth2 with Authorization/Resource servers.
I have implemented following JwtAccessTokenConverter:
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter() {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
DBUserDetails user = (DBUserDetails) authentication.getUserAuthentication().getPrincipal();
final Map<String, Object> additionalInfo = new HashMap<>();
additionalInfo.put("user_id", user.getUser().getId());
((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
OAuth2AccessToken enhancedToken = super.enhance(accessToken, authentication);
return enhancedToken;
}
};
converter.setSigningKey("123");
DefaultAccessTokenConverter accessTokenConverter = new DefaultAccessTokenConverter();
DefaultUserAuthenticationConverter userTokenConverter = new DefaultUserAuthenticationConverter();
userTokenConverter.setUserDetailsService(userDetailsService);
accessTokenConverter.setUserTokenConverter(userTokenConverter);
converter.setAccessTokenConverter(accessTokenConverter);
return converter;
}
Right now my application produces following tokens, for example:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxNzgzNTEsInVzZXJfbmFtZSI6ImFkbWluIiwic2NvcGUiOlsicmVhZCIsIndyaXRlIl0sImV4cCI6MTQ3NTA5NDA4NSwiYXV0aG9yaXRpZXMiOlsiUEVSTUlTU0lPTl9ERUxFVEVfT1dOX0NSSVRFUklPTiIsIlBFUk1JU1NJT05fREVMRVRFX09XTl9DT01NRU5UIiwiUEVSTUlTU0lPTl9VUERBVEVfT1dOX0NSSVRFUklPTiIsIlBFUk1JU1NJT05fVVBEQVRFX0FOWV9DUklURVJJT04iLCJQRVJNSVNTSU9OX0RFTEVURV9PV05fQ1JJVEVSSU9OX0dST1VQIiwiUEVSTUlTU0lPTl9ERUxFVEVfQU5ZX0RFQ0lTSU9OIiwiUEVSTUlTU0lPTl9DUkVBVEVfVk9URSIsIlBFUk1JU1NJT05fREVMRVRFX0FOWV9DUklURVJJT04iLCJQRVJNSVNTSU9OX0NSRUFURV9DUklURVJJT05fR1JPVVAiLCJQRVJNSVNTSU9OX0RFTEVURV9PV05fREVDSVNJT04iLCJQRVJNSVNTSU9OX0NSRUFURV9ERUNJU0lPTiIsIlBFUk1JU1NJT05fREVMRVRFX0FOWV9DUklURVJJT05fR1JPVVAiLCJQRVJNSVNTSU9OX0RFTEVURV9BTllfVk9URSIsIlBFUk1JU1NJT05fREVMRVRFX09XTl9WT1RFIiwiUEVSTUlTU0lPTl9VUERBVEVfT1dOX0NSSVRFUklPTl9HUk9VUCIsIlBFUk1JU1NJT05fVVBEQVRFX0FOWV9DUklURVJJT05fR1JPVVAiLCJQRVJNSVNTSU9OX1VQREFURV9BTllfQ09NTUVOVCIsIlBFUk1JU1NJT05fVVBEQVRFX09XTl9DT01NRU5UIiwiUEVSTUlTU0lPTl9VUERBVEVfQU5ZX0RFQ0lTSU9OIiwiUEVSTUlTU0lPTl9BUFBFTkRfREVDSVNJT04iLCJQRVJNSVNTSU9OX1VQREFURV9PV05fVk9URSIsIlBFUk1JU1NJT05fVVBEQVRFX0FOWV9WT1RFIiwiUEVSTUlTU0lPTl9ERUxFVEVfQU5ZX0NPTU1FTlQiLCJQRVJNSVNTSU9OX1VQREFURV9PV05fREVDSVNJT04iLCJQRVJNSVNTSU9OX0NSRUFURV9DT01NRU5UIiwiUEVSTUlTU0lPTl9DUkVBVEVfQ1JJVEVSSU9OIiwiUEVSTUlTU0lPTl9SRUFEX0FDVFVBVE9SX0RBVEEiXSwianRpIjoiMWU3OGMzMGYtNTY0ZS00NjliLWE1MmMtODlhOGM4YzFiZmY2IiwiY2xpZW50X2lkIjoiZGVjaXNpb253YW50ZWRfY2xpZW50X2lkIn0.Cnj_7b3FAanmL0Y-_kxcH2f4yjLFHOw-4NOVr67WZ88
This token can be decoded with JWT debugger here https://jwt.io/
I don't want to expose the internals of this token to external world and would like to encode this token in a some way.
How it can be implemented with Spring Boot, OAuth2, JWT ?
JWT and OAuth2 are entirely different and serve different purposes, but they are compatible and can be used together. The OAuth2 protocol does not specify the format of the tokens, therefore JWTs can be incorporated into the usage of OAuth2.
You need to guide OAuth2 to issue two tokens. The first token should be access_token and the second token should be a JWT token featuring additional identity details.
i try this and it is working for me:https://gist.github.com/salgmachine/352799a6052b02901982dcbf85d30346
Create Custom JwtAccessTokenConverter
public class JwtJweAccessTokenConverter extends JwtAccessTokenConverter {
RSAKey recipientJWK, recipientPublicJWK;
public JwtJweAccessTokenConverter() {
try {
recipientJWK = new RSAKeyGenerator(2048).keyID("456").keyUse(KeyUse.ENCRYPTION).generate();
recipientPublicJWK = recipientJWK.toPublicJWK();
} catch (JOSEException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected String encode(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
String jwt = super.encode(accessToken, authentication);
try {
// jwt is already signed at this point (by JwtAccessTokenConverter)
SignedJWT parsed = SignedJWT.parse(jwt);
// Create JWE object with signed JWT as payload
JWEObject jweObject = new JWEObject(
new JWEHeader.Builder(JWEAlgorithm.RSA_OAEP_256, EncryptionMethod.A256GCM).contentType("JWT") // required
// to
// indicate
// nested
// JWT
.build(),
new Payload(parsed));
// Encrypt with the recipient's public key
jweObject.encrypt(new RSAEncrypter(recipientPublicJWK));
// Serialise to JWE compact form
String jweString = jweObject.serialize();
return jweString;
} catch (Exception e) {
e.printStackTrace();
}
return jwt;
}
@Override
protected Map<String, Object> decode(String token) {
try {
// basically treat the incoming token as an encrypted JWT
EncryptedJWT parse = EncryptedJWT.parse(token);
// decrypt it
RSADecrypter dec = new RSADecrypter(recipientJWK);
parse.decrypt(dec);
// content of the encrypted token is a signed JWT (signed by
// JwtAccessTokenConverter)
SignedJWT signedJWT = parse.getPayload().toSignedJWT();
// pass on the serialized, signed JWT to JwtAccessTokenConverter
return super.decode(signedJWT.serialize());
} catch (ParseException e) {
e.printStackTrace();
} catch (JOSEException e) {
e.printStackTrace();
}
return super.decode(token);
}
}
And Config your Oauth2 Auth server and resource to use your Custom JwtAccessTokenConverter
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtJweAccessTokenConverter();
final KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("mytest.jks"),
"mypass".toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
return converter;
}
Check github link for completed code example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With