I am attempting to build a Spring application that uses JWT tokens and the OAuth2 protocol. I have the Authentication Server running thanks to this tutorial. However, I am struggling with getting the Resource Server to function properly. From following the article, and thanks to a response to a prior question, this is my current attempt:
Security config for Resource Server:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.signing-key}")
private String signingKey;
@Value("${security.encoding-strength}")
private Integer clientID;
@Value("${security.security-realm}")
private String securityRealm;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setVerifierKey(signingKey);
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean ResourceServerTokenServices tokenService() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Override
public AuthenticationManager authenticationManager() throws Exception {
OAuth2AuthenticationManager authManager = new OAuth2AuthenticationManager();
authManager.setTokenServices(tokenService());
return authManager;
}
}
Resource Server config:
@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private ResourceServerTokenServices tokenServices;
@Value("${security.jwt.resource-ids}")
private String resourceIds;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(resourceIds).tokenServices(tokenServices);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().and().authorizeRequests().antMatchers("/actuator/**", "/api-docs/**").permitAll()
.antMatchers("/**").authenticated();
}
}
Security config for Authorization Server (from noted tutorial):
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${security.signing-key}")
private String signingKey;
@Value("${security.encoding-strength}")
private Integer encodingStrength;
@Value("${security.security-realm}")
private String securityRealm;
@Autowired
private UserDetailsService userDetailsService;
@Bean
@Override
protected AuthenticationManager authenticationManager() throws Exception {
return super.authenticationManager();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new ShaPasswordEncoder(encodingStrength));
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.httpBasic()
.realmName(securityRealm)
.and()
.csrf()
.disable();
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(signingKey);
return converter;
}
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
@Primary //Making this primary to avoid any accidental duplication with another token service instance of the same name
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
}
Now, when I attempt to make a request to the Resource server, I receive an error such as follows:
{"error":"invalid_token","error_description":"Invalid access token: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdWQiOlsidGVzdGp3dHJlc291cmNlaWQiXSwidXNlcl9uYW1lIjoiam9obi5kb2UiLCJzY29wZSI6WyJyZWFkIiwid3JpdGUiXSwiZXh
wIjoxNTE1MTE3NTU4LCJhdXRob3JpdGllcyI6WyJTVEFOREFSRF"}
I have a couple questions:
security.oauth2.resource.token-info-uri=http://localhost:8080/oauth/check_token
. However, if I attempt to not rely on a key with my Resource Server, then I run into difficulties setting my ResourceServerTokenService. The service expects a token store, the JWTTokenStore uses a JwtAccessTokenConverter, and the converter uses a key (removing the key resulted in the same invalid token
error I experienced earlier).I am really struggling to find articles that show how to separate the Auth and Resource server. Any advice would be appreciated.
EDIT: Actually, the code for the Resource Server is now failing to compile with the following message:
Caused by: java.lang.IllegalStateException: For MAC signing you do not need to specify the verifier key separately, and if you do it must match the signing key
I tried spring oauth and I came across the same error :
Caused by: java.lang.IllegalStateException: For MAC signing you do not need to specify the verifier key separately, and if you do it must match the signing key
My mistake was that my public certificate was :
-----BEGIN PUBLIC KEY-----
tadadada
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
tadadada
-----END CERTIFICATE-----
And this is not allowed. REMOVE the certificate, just let the public key in this file :
-----BEGIN PUBLIC KEY-----
tadadada
-----END PUBLIC KEY-----
And the startup error will disapear.
For your second question, that's what I understand :
The authentication server give you an encrypted token (encrypted with the private key), that contains ALL the permissions of your user.
The resource server decrypts the token with the public key, and assumes that the permissions contained in the token are TRUE.
Hopes this help.
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