I have a fairly basic setup in my Spring Boot project. I'm trying to set up OAuth2 to protect my API but I'm running into issues with my /oauth/token
end point. Making either a POST or GET request to my /oauth/token
end point results in the following response (With a 401 Unauthorized
status code):
{
"timestamp": "2018-09-17T16:46:59.961+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/oauth/token"
}
This is my Authorization server configuration.
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.token.TokenStore;
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("client_id")
.secret("secret")
.authorizedGrantTypes("password", "authorization_code", "refresh_token")
.scopes("read", "write")
.accessTokenValiditySeconds(600)
.refreshTokenValiditySeconds(3600);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(this.tokenStore)
.userApprovalHandler(this.userApprovalHandler)
.authenticationManager(this.authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) {
security.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()")
.passwordEncoder(this.passwordEncoder);
}
}
This is my resource server configuration. Nothing significant yet:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(this.tokenStore);
}
}
And finally my standard web security configuration:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenApprovalStore;
import org.springframework.security.oauth2.provider.approval.TokenStoreUserApprovalHandler;
import org.springframework.security.oauth2.provider.approval.UserApprovalHandler;
import org.springframework.security.oauth2.provider.request.DefaultOAuth2RequestFactory;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder builder) throws Exception {
builder.inMemoryAuthentication()
.withUser("user").password("password").roles("ADMIN")
.and()
.withUser("admin").password("password").roles("USER");
}
@Override
protected void configure(HttpSecurity security) throws Exception {
security.csrf().disable()
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(8);
}
@Bean
@Autowired
public UserApprovalHandler userApprovalHandler(TokenStore tokenStore) {
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(this.clientDetailsService));
handler.setClientDetailsService(this.clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}
I've messed around quite a bit with different matcher patterns to see if I can get it working but I haven't had any luck. I'm running this in a root context and servlet path on http://localhost:8080
.
I can confirm that the end point is mapped in the output when Spring Boot fires up and trying to hit a slightly different end point results in an expected 404.
Turns out I wasn't hitting the end point correctly. I was sending all of my data, client credentials included, via HTTP POST.
POST http://localhost:8080/oauth/token
...
client_id=client_id&secret=secret&scope=read&grant_type=password&username=user&password=password
I needed to use HTTP Basic Auth to send my client credentials rather than POSTing them:
POST http://localhost:8080/oauth/token
Authorization: Basic Y2xpZW50X2lkOnNlY3JldA==
...
scope=read&grant_type=password&username=user&password=password
try changing your password encoder from your AuthorizationServerConfig
class with this simple encoder(it doesn't encrypt passwords).because you don't save your client secret in InMemory storage with encryption.
private PasswordEncoder getPasswordEncoder() {
return new PasswordEncoder() {
public String encode (CharSequence charSequence) {
return charSequence.toString();
}
public boolean matches(CharSequence charSequence, String s) {
return true;
}
};
}
hope it will work.
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