springboot bearer token authentication giving 401
I am new to Spring boot so please help me. I have got it working to the point where I am able to generate a Bearer Token with an unauthenticated request. Next I want to use this token to use with an endpoint so that my request is authenticated - this is where my trouble is coming in. I am always getting a 401, looks like something is wrong with my config. Here is my code
public class ApplicationUser {
private String username;
private String password;
private String role;
public ApplicationUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getRole() {
return role;
}
}
JwtConfig Class:
@Component("jwtConfig")
public class JwtConfig {
@Value("${security.jwt.uri:/auth/**}")
private String Uri;
@Value("${security.jwt.header:Authorization}")
private String header;
@Value("${security.jwt.prefix:Bearer }")
private String prefix;
@Value("${security.jwt.expiration:#{24*60*60}}")
private int expiration;
@Value("${security.jwt.secret:JwtSecretKey}")
private String secret;
public String getUri() {
return Uri;
}
public String getHeader() {
return header;
}
public String getPrefix() {
return prefix;
}
public int getExpiration() {
return expiration;
}
public String getSecret() {
return secret;
}
}
JwtTokenAuthenticationFilter
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
private final JwtConfig jwtConfig;
public JwtTokenAuthenticationFilter(JwtConfig jwtConfig) {
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
// 1. get the authentication header. Tokens are supposed to be passed in the authentication header
String header = request.getHeader(jwtConfig.getHeader());
// 2. validate the header and check the prefix
if(header == null || !header.startsWith(jwtConfig.getPrefix())) {
chain.doFilter(request, response); // If not valid, go to the next filter.
return;
}
// If there is no token provided and hence the user won't be authenticated.
// It's Ok. Maybe the user accessing a public path or asking for a token.
// All secured paths that needs a token are already defined and secured in config class.
// And If user tried to access without access token, then he won't be authenticated and an exception will be thrown.
// 3. Get the token
String token = header.replace(jwtConfig.getPrefix(), "");
try { // exceptions might be thrown in creating the claims if for example the token is expired
// 4. Validate the token
Claims claims = Jwts.parser()
.setSigningKey(jwtConfig.getSecret().getBytes())
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
if(username != null) {
@SuppressWarnings("unchecked")
List<String> authorities = (List<String>) claims.get("authorities");
// 5. Create auth object
// UsernamePasswordAuthenticationToken: A built-in object, used by spring to represent the current authenticated / being authenticated user.
// It needs a list of authorities, which has type of GrantedAuthority interface, where SimpleGrantedAuthority is an implementation of that interface
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
username, null, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
// 6. Authenticate the user
// Now, user is authenticated
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
// In case of failure. Make sure it's clear; so guarantee user won't be authenticated
SecurityContextHolder.clearContext();
}
// go to the next filter in the filter chain
chain.doFilter(request, response);
}
}
JwtUsernameAndPasswordAuthenticationFilter
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
// We use auth manager to validate the user credentials
private AuthenticationManager authManager;
private final JwtConfig jwtConfig;
public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager, JwtConfig jwtConfig) {
this.authManager = authManager;
this.jwtConfig = jwtConfig;
// By default, UsernamePasswordAuthenticationFilter listens to "/login" path.
// In our case, we use "/auth". So, we need to override the defaults.
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(jwtConfig.getUri(), "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try {
// 1. Get credentials from request
UserCredentials creds = new ObjectMapper().readValue(request.getInputStream(), UserCredentials.class);
// 2. Create auth object (contains credentials) which will be used by auth manager
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
creds.getUsername(), creds.getPassword(), Collections.emptyList());
// 3. Authentication manager authenticate the user, and use UserDetialsServiceImpl::loadUserByUsername() method to load the user.
return authManager.authenticate(authToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// Upon successful authentication, generate a token.
// The 'auth' passed to successfulAuthentication() is the current authenticated user.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication auth) throws IOException, ServletException {
Long now = System.currentTimeMillis();
String token = Jwts.builder()
.setSubject(auth.getName())
// Convert to list of strings.
// This is important because it affects the way we get them back in the Gateway.
.claim("authorities", auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.setIssuedAt(new Date(now))
.setExpiration(new Date(now + jwtConfig.getExpiration() * 1000)) // in milliseconds
.signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
.compact();
// Add token to header
response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token);
}
// A (temporary) class just to represent the user credentials
private static class UserCredentials {
private String username, password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
SecurityCredentialsConfig
@Configuration
@EnableWebSecurity(debug=true)
public class SecurityCredentialsConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate user credentials and add token in the response header
// What's the authenticationManager()?
// An object provided by WebSecurityConfigurerAdapter, used to authenticate the user passing user's credentials
// The filter needs this auth manager to authenticate the user.
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig))
.authorizeRequests()
// allow all POST requests
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// any other requests must be authenticated
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
.anyRequest().authenticated();
}
// Spring has UserDetailsService interface, which can be overriden to provide our implementation for fetching user from database (or any other source).
// The UserDetailsService object is used by the auth manager to load the user from database.
// In addition, we need to define the password encoder also. So, auth manager can compare and verify passwords.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final List<ApplicationUser> users = Arrays.asList(
new ApplicationUser("omar",encoder.encode("12345"), "USER"),
new ApplicationUser("admin", encoder.encode("12345"), "ADMIN")
);
for(ApplicationUser appUser: users) {
if(appUser.getUsername().equals(username)) {
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList( appUser.getRole());
return new User(appUser.getUsername(), appUser.getPassword(), grantedAuthorities);
}
}
// If user not found. Throw this exception.
throw new UsernameNotFoundException("Username: " + username + " not found");
}
}
WebSecurity
@EnableWebSecurity(debug=true)
@Order(1000)
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks").access("hasRole('ADMIN')")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated();
}
}
Controller
@RestController
public class CookController {
@Autowired
private CookService cookService;
// Get All Cooks
@GetMapping("/v1/cooks")
public List<Cook> getAllCooks(){
return cookService.getAllCooks();
}
application.properties
zuul.routes.auth-service.path=/auth/**
zuul.routes.auth-service.service-id=AUTH-SERVICE
zuul.routes.auth-service.strip-prefix=false
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie
spring.application.name=auth-service
server.port=9100
eureka.client.service-url.default-zone=http://localhost:8761/eureka
the call to v1/cooks always returns 401.
What part of the configuration I am missing? I followed the documentation at https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8
but I am completely lost now.
Request url is
GET http://localhost:9100/v1/cooks
Response is
{
"timestamp": "2018-10-13T20:08:13.804+0000",
"status": 401,
"error": "Unauthorized",
"message": "No message available",
"path": "/v1/cooks"
}
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0-b170201.1204</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
EDIT: Added application.properties and dependies from pom
java spring-boot authentication http-status-code-401
add a comment |
I am new to Spring boot so please help me. I have got it working to the point where I am able to generate a Bearer Token with an unauthenticated request. Next I want to use this token to use with an endpoint so that my request is authenticated - this is where my trouble is coming in. I am always getting a 401, looks like something is wrong with my config. Here is my code
public class ApplicationUser {
private String username;
private String password;
private String role;
public ApplicationUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getRole() {
return role;
}
}
JwtConfig Class:
@Component("jwtConfig")
public class JwtConfig {
@Value("${security.jwt.uri:/auth/**}")
private String Uri;
@Value("${security.jwt.header:Authorization}")
private String header;
@Value("${security.jwt.prefix:Bearer }")
private String prefix;
@Value("${security.jwt.expiration:#{24*60*60}}")
private int expiration;
@Value("${security.jwt.secret:JwtSecretKey}")
private String secret;
public String getUri() {
return Uri;
}
public String getHeader() {
return header;
}
public String getPrefix() {
return prefix;
}
public int getExpiration() {
return expiration;
}
public String getSecret() {
return secret;
}
}
JwtTokenAuthenticationFilter
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
private final JwtConfig jwtConfig;
public JwtTokenAuthenticationFilter(JwtConfig jwtConfig) {
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
// 1. get the authentication header. Tokens are supposed to be passed in the authentication header
String header = request.getHeader(jwtConfig.getHeader());
// 2. validate the header and check the prefix
if(header == null || !header.startsWith(jwtConfig.getPrefix())) {
chain.doFilter(request, response); // If not valid, go to the next filter.
return;
}
// If there is no token provided and hence the user won't be authenticated.
// It's Ok. Maybe the user accessing a public path or asking for a token.
// All secured paths that needs a token are already defined and secured in config class.
// And If user tried to access without access token, then he won't be authenticated and an exception will be thrown.
// 3. Get the token
String token = header.replace(jwtConfig.getPrefix(), "");
try { // exceptions might be thrown in creating the claims if for example the token is expired
// 4. Validate the token
Claims claims = Jwts.parser()
.setSigningKey(jwtConfig.getSecret().getBytes())
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
if(username != null) {
@SuppressWarnings("unchecked")
List<String> authorities = (List<String>) claims.get("authorities");
// 5. Create auth object
// UsernamePasswordAuthenticationToken: A built-in object, used by spring to represent the current authenticated / being authenticated user.
// It needs a list of authorities, which has type of GrantedAuthority interface, where SimpleGrantedAuthority is an implementation of that interface
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
username, null, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
// 6. Authenticate the user
// Now, user is authenticated
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
// In case of failure. Make sure it's clear; so guarantee user won't be authenticated
SecurityContextHolder.clearContext();
}
// go to the next filter in the filter chain
chain.doFilter(request, response);
}
}
JwtUsernameAndPasswordAuthenticationFilter
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
// We use auth manager to validate the user credentials
private AuthenticationManager authManager;
private final JwtConfig jwtConfig;
public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager, JwtConfig jwtConfig) {
this.authManager = authManager;
this.jwtConfig = jwtConfig;
// By default, UsernamePasswordAuthenticationFilter listens to "/login" path.
// In our case, we use "/auth". So, we need to override the defaults.
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(jwtConfig.getUri(), "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try {
// 1. Get credentials from request
UserCredentials creds = new ObjectMapper().readValue(request.getInputStream(), UserCredentials.class);
// 2. Create auth object (contains credentials) which will be used by auth manager
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
creds.getUsername(), creds.getPassword(), Collections.emptyList());
// 3. Authentication manager authenticate the user, and use UserDetialsServiceImpl::loadUserByUsername() method to load the user.
return authManager.authenticate(authToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// Upon successful authentication, generate a token.
// The 'auth' passed to successfulAuthentication() is the current authenticated user.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication auth) throws IOException, ServletException {
Long now = System.currentTimeMillis();
String token = Jwts.builder()
.setSubject(auth.getName())
// Convert to list of strings.
// This is important because it affects the way we get them back in the Gateway.
.claim("authorities", auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.setIssuedAt(new Date(now))
.setExpiration(new Date(now + jwtConfig.getExpiration() * 1000)) // in milliseconds
.signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
.compact();
// Add token to header
response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token);
}
// A (temporary) class just to represent the user credentials
private static class UserCredentials {
private String username, password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
SecurityCredentialsConfig
@Configuration
@EnableWebSecurity(debug=true)
public class SecurityCredentialsConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate user credentials and add token in the response header
// What's the authenticationManager()?
// An object provided by WebSecurityConfigurerAdapter, used to authenticate the user passing user's credentials
// The filter needs this auth manager to authenticate the user.
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig))
.authorizeRequests()
// allow all POST requests
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// any other requests must be authenticated
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
.anyRequest().authenticated();
}
// Spring has UserDetailsService interface, which can be overriden to provide our implementation for fetching user from database (or any other source).
// The UserDetailsService object is used by the auth manager to load the user from database.
// In addition, we need to define the password encoder also. So, auth manager can compare and verify passwords.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final List<ApplicationUser> users = Arrays.asList(
new ApplicationUser("omar",encoder.encode("12345"), "USER"),
new ApplicationUser("admin", encoder.encode("12345"), "ADMIN")
);
for(ApplicationUser appUser: users) {
if(appUser.getUsername().equals(username)) {
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList( appUser.getRole());
return new User(appUser.getUsername(), appUser.getPassword(), grantedAuthorities);
}
}
// If user not found. Throw this exception.
throw new UsernameNotFoundException("Username: " + username + " not found");
}
}
WebSecurity
@EnableWebSecurity(debug=true)
@Order(1000)
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks").access("hasRole('ADMIN')")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated();
}
}
Controller
@RestController
public class CookController {
@Autowired
private CookService cookService;
// Get All Cooks
@GetMapping("/v1/cooks")
public List<Cook> getAllCooks(){
return cookService.getAllCooks();
}
application.properties
zuul.routes.auth-service.path=/auth/**
zuul.routes.auth-service.service-id=AUTH-SERVICE
zuul.routes.auth-service.strip-prefix=false
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie
spring.application.name=auth-service
server.port=9100
eureka.client.service-url.default-zone=http://localhost:8761/eureka
the call to v1/cooks always returns 401.
What part of the configuration I am missing? I followed the documentation at https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8
but I am completely lost now.
Request url is
GET http://localhost:9100/v1/cooks
Response is
{
"timestamp": "2018-10-13T20:08:13.804+0000",
"status": 401,
"error": "Unauthorized",
"message": "No message available",
"path": "/v1/cooks"
}
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0-b170201.1204</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
EDIT: Added application.properties and dependies from pom
java spring-boot authentication http-status-code-401
add a comment |
I am new to Spring boot so please help me. I have got it working to the point where I am able to generate a Bearer Token with an unauthenticated request. Next I want to use this token to use with an endpoint so that my request is authenticated - this is where my trouble is coming in. I am always getting a 401, looks like something is wrong with my config. Here is my code
public class ApplicationUser {
private String username;
private String password;
private String role;
public ApplicationUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getRole() {
return role;
}
}
JwtConfig Class:
@Component("jwtConfig")
public class JwtConfig {
@Value("${security.jwt.uri:/auth/**}")
private String Uri;
@Value("${security.jwt.header:Authorization}")
private String header;
@Value("${security.jwt.prefix:Bearer }")
private String prefix;
@Value("${security.jwt.expiration:#{24*60*60}}")
private int expiration;
@Value("${security.jwt.secret:JwtSecretKey}")
private String secret;
public String getUri() {
return Uri;
}
public String getHeader() {
return header;
}
public String getPrefix() {
return prefix;
}
public int getExpiration() {
return expiration;
}
public String getSecret() {
return secret;
}
}
JwtTokenAuthenticationFilter
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
private final JwtConfig jwtConfig;
public JwtTokenAuthenticationFilter(JwtConfig jwtConfig) {
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
// 1. get the authentication header. Tokens are supposed to be passed in the authentication header
String header = request.getHeader(jwtConfig.getHeader());
// 2. validate the header and check the prefix
if(header == null || !header.startsWith(jwtConfig.getPrefix())) {
chain.doFilter(request, response); // If not valid, go to the next filter.
return;
}
// If there is no token provided and hence the user won't be authenticated.
// It's Ok. Maybe the user accessing a public path or asking for a token.
// All secured paths that needs a token are already defined and secured in config class.
// And If user tried to access without access token, then he won't be authenticated and an exception will be thrown.
// 3. Get the token
String token = header.replace(jwtConfig.getPrefix(), "");
try { // exceptions might be thrown in creating the claims if for example the token is expired
// 4. Validate the token
Claims claims = Jwts.parser()
.setSigningKey(jwtConfig.getSecret().getBytes())
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
if(username != null) {
@SuppressWarnings("unchecked")
List<String> authorities = (List<String>) claims.get("authorities");
// 5. Create auth object
// UsernamePasswordAuthenticationToken: A built-in object, used by spring to represent the current authenticated / being authenticated user.
// It needs a list of authorities, which has type of GrantedAuthority interface, where SimpleGrantedAuthority is an implementation of that interface
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
username, null, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
// 6. Authenticate the user
// Now, user is authenticated
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
// In case of failure. Make sure it's clear; so guarantee user won't be authenticated
SecurityContextHolder.clearContext();
}
// go to the next filter in the filter chain
chain.doFilter(request, response);
}
}
JwtUsernameAndPasswordAuthenticationFilter
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
// We use auth manager to validate the user credentials
private AuthenticationManager authManager;
private final JwtConfig jwtConfig;
public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager, JwtConfig jwtConfig) {
this.authManager = authManager;
this.jwtConfig = jwtConfig;
// By default, UsernamePasswordAuthenticationFilter listens to "/login" path.
// In our case, we use "/auth". So, we need to override the defaults.
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(jwtConfig.getUri(), "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try {
// 1. Get credentials from request
UserCredentials creds = new ObjectMapper().readValue(request.getInputStream(), UserCredentials.class);
// 2. Create auth object (contains credentials) which will be used by auth manager
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
creds.getUsername(), creds.getPassword(), Collections.emptyList());
// 3. Authentication manager authenticate the user, and use UserDetialsServiceImpl::loadUserByUsername() method to load the user.
return authManager.authenticate(authToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// Upon successful authentication, generate a token.
// The 'auth' passed to successfulAuthentication() is the current authenticated user.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication auth) throws IOException, ServletException {
Long now = System.currentTimeMillis();
String token = Jwts.builder()
.setSubject(auth.getName())
// Convert to list of strings.
// This is important because it affects the way we get them back in the Gateway.
.claim("authorities", auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.setIssuedAt(new Date(now))
.setExpiration(new Date(now + jwtConfig.getExpiration() * 1000)) // in milliseconds
.signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
.compact();
// Add token to header
response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token);
}
// A (temporary) class just to represent the user credentials
private static class UserCredentials {
private String username, password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
SecurityCredentialsConfig
@Configuration
@EnableWebSecurity(debug=true)
public class SecurityCredentialsConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate user credentials and add token in the response header
// What's the authenticationManager()?
// An object provided by WebSecurityConfigurerAdapter, used to authenticate the user passing user's credentials
// The filter needs this auth manager to authenticate the user.
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig))
.authorizeRequests()
// allow all POST requests
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// any other requests must be authenticated
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
.anyRequest().authenticated();
}
// Spring has UserDetailsService interface, which can be overriden to provide our implementation for fetching user from database (or any other source).
// The UserDetailsService object is used by the auth manager to load the user from database.
// In addition, we need to define the password encoder also. So, auth manager can compare and verify passwords.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final List<ApplicationUser> users = Arrays.asList(
new ApplicationUser("omar",encoder.encode("12345"), "USER"),
new ApplicationUser("admin", encoder.encode("12345"), "ADMIN")
);
for(ApplicationUser appUser: users) {
if(appUser.getUsername().equals(username)) {
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList( appUser.getRole());
return new User(appUser.getUsername(), appUser.getPassword(), grantedAuthorities);
}
}
// If user not found. Throw this exception.
throw new UsernameNotFoundException("Username: " + username + " not found");
}
}
WebSecurity
@EnableWebSecurity(debug=true)
@Order(1000)
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks").access("hasRole('ADMIN')")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated();
}
}
Controller
@RestController
public class CookController {
@Autowired
private CookService cookService;
// Get All Cooks
@GetMapping("/v1/cooks")
public List<Cook> getAllCooks(){
return cookService.getAllCooks();
}
application.properties
zuul.routes.auth-service.path=/auth/**
zuul.routes.auth-service.service-id=AUTH-SERVICE
zuul.routes.auth-service.strip-prefix=false
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie
spring.application.name=auth-service
server.port=9100
eureka.client.service-url.default-zone=http://localhost:8761/eureka
the call to v1/cooks always returns 401.
What part of the configuration I am missing? I followed the documentation at https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8
but I am completely lost now.
Request url is
GET http://localhost:9100/v1/cooks
Response is
{
"timestamp": "2018-10-13T20:08:13.804+0000",
"status": 401,
"error": "Unauthorized",
"message": "No message available",
"path": "/v1/cooks"
}
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0-b170201.1204</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
EDIT: Added application.properties and dependies from pom
java spring-boot authentication http-status-code-401
I am new to Spring boot so please help me. I have got it working to the point where I am able to generate a Bearer Token with an unauthenticated request. Next I want to use this token to use with an endpoint so that my request is authenticated - this is where my trouble is coming in. I am always getting a 401, looks like something is wrong with my config. Here is my code
public class ApplicationUser {
private String username;
private String password;
private String role;
public ApplicationUser(String username, String password, String role) {
this.username = username;
this.password = password;
this.role = role;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public String getRole() {
return role;
}
}
JwtConfig Class:
@Component("jwtConfig")
public class JwtConfig {
@Value("${security.jwt.uri:/auth/**}")
private String Uri;
@Value("${security.jwt.header:Authorization}")
private String header;
@Value("${security.jwt.prefix:Bearer }")
private String prefix;
@Value("${security.jwt.expiration:#{24*60*60}}")
private int expiration;
@Value("${security.jwt.secret:JwtSecretKey}")
private String secret;
public String getUri() {
return Uri;
}
public String getHeader() {
return header;
}
public String getPrefix() {
return prefix;
}
public int getExpiration() {
return expiration;
}
public String getSecret() {
return secret;
}
}
JwtTokenAuthenticationFilter
public class JwtTokenAuthenticationFilter extends OncePerRequestFilter {
private final JwtConfig jwtConfig;
public JwtTokenAuthenticationFilter(JwtConfig jwtConfig) {
this.jwtConfig = jwtConfig;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
// 1. get the authentication header. Tokens are supposed to be passed in the authentication header
String header = request.getHeader(jwtConfig.getHeader());
// 2. validate the header and check the prefix
if(header == null || !header.startsWith(jwtConfig.getPrefix())) {
chain.doFilter(request, response); // If not valid, go to the next filter.
return;
}
// If there is no token provided and hence the user won't be authenticated.
// It's Ok. Maybe the user accessing a public path or asking for a token.
// All secured paths that needs a token are already defined and secured in config class.
// And If user tried to access without access token, then he won't be authenticated and an exception will be thrown.
// 3. Get the token
String token = header.replace(jwtConfig.getPrefix(), "");
try { // exceptions might be thrown in creating the claims if for example the token is expired
// 4. Validate the token
Claims claims = Jwts.parser()
.setSigningKey(jwtConfig.getSecret().getBytes())
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
if(username != null) {
@SuppressWarnings("unchecked")
List<String> authorities = (List<String>) claims.get("authorities");
// 5. Create auth object
// UsernamePasswordAuthenticationToken: A built-in object, used by spring to represent the current authenticated / being authenticated user.
// It needs a list of authorities, which has type of GrantedAuthority interface, where SimpleGrantedAuthority is an implementation of that interface
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
username, null, authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
// 6. Authenticate the user
// Now, user is authenticated
SecurityContextHolder.getContext().setAuthentication(auth);
}
} catch (Exception e) {
// In case of failure. Make sure it's clear; so guarantee user won't be authenticated
SecurityContextHolder.clearContext();
}
// go to the next filter in the filter chain
chain.doFilter(request, response);
}
}
JwtUsernameAndPasswordAuthenticationFilter
public class JwtUsernameAndPasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
// We use auth manager to validate the user credentials
private AuthenticationManager authManager;
private final JwtConfig jwtConfig;
public JwtUsernameAndPasswordAuthenticationFilter(AuthenticationManager authManager, JwtConfig jwtConfig) {
this.authManager = authManager;
this.jwtConfig = jwtConfig;
// By default, UsernamePasswordAuthenticationFilter listens to "/login" path.
// In our case, we use "/auth". So, we need to override the defaults.
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(jwtConfig.getUri(), "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
try {
// 1. Get credentials from request
UserCredentials creds = new ObjectMapper().readValue(request.getInputStream(), UserCredentials.class);
// 2. Create auth object (contains credentials) which will be used by auth manager
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
creds.getUsername(), creds.getPassword(), Collections.emptyList());
// 3. Authentication manager authenticate the user, and use UserDetialsServiceImpl::loadUserByUsername() method to load the user.
return authManager.authenticate(authToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
// Upon successful authentication, generate a token.
// The 'auth' passed to successfulAuthentication() is the current authenticated user.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication auth) throws IOException, ServletException {
Long now = System.currentTimeMillis();
String token = Jwts.builder()
.setSubject(auth.getName())
// Convert to list of strings.
// This is important because it affects the way we get them back in the Gateway.
.claim("authorities", auth.getAuthorities().stream()
.map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
.setIssuedAt(new Date(now))
.setExpiration(new Date(now + jwtConfig.getExpiration() * 1000)) // in milliseconds
.signWith(SignatureAlgorithm.HS512, jwtConfig.getSecret().getBytes())
.compact();
// Add token to header
response.addHeader(jwtConfig.getHeader(), jwtConfig.getPrefix() + token);
}
// A (temporary) class just to represent the user credentials
private static class UserCredentials {
private String username, password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
}
SecurityCredentialsConfig
@Configuration
@EnableWebSecurity(debug=true)
public class SecurityCredentialsConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate user credentials and add token in the response header
// What's the authenticationManager()?
// An object provided by WebSecurityConfigurerAdapter, used to authenticate the user passing user's credentials
// The filter needs this auth manager to authenticate the user.
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig))
.authorizeRequests()
// allow all POST requests
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// any other requests must be authenticated
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
.anyRequest().authenticated();
}
// Spring has UserDetailsService interface, which can be overriden to provide our implementation for fetching user from database (or any other source).
// The UserDetailsService object is used by the auth manager to load the user from database.
// In addition, we need to define the password encoder also. So, auth manager can compare and verify passwords.
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private BCryptPasswordEncoder encoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
final List<ApplicationUser> users = Arrays.asList(
new ApplicationUser("omar",encoder.encode("12345"), "USER"),
new ApplicationUser("admin", encoder.encode("12345"), "ADMIN")
);
for(ApplicationUser appUser: users) {
if(appUser.getUsername().equals(username)) {
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList( appUser.getRole());
return new User(appUser.getUsername(), appUser.getPassword(), grantedAuthorities);
}
}
// If user not found. Throw this exception.
throw new UsernameNotFoundException("Username: " + username + " not found");
}
}
WebSecurity
@EnableWebSecurity(debug=true)
@Order(1000)
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks").access("hasRole('ADMIN')")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated();
}
}
Controller
@RestController
public class CookController {
@Autowired
private CookService cookService;
// Get All Cooks
@GetMapping("/v1/cooks")
public List<Cook> getAllCooks(){
return cookService.getAllCooks();
}
application.properties
zuul.routes.auth-service.path=/auth/**
zuul.routes.auth-service.service-id=AUTH-SERVICE
zuul.routes.auth-service.strip-prefix=false
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie
spring.application.name=auth-service
server.port=9100
eureka.client.service-url.default-zone=http://localhost:8761/eureka
the call to v1/cooks always returns 401.
What part of the configuration I am missing? I followed the documentation at https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8
but I am completely lost now.
Request url is
GET http://localhost:9100/v1/cooks
Response is
{
"timestamp": "2018-10-13T20:08:13.804+0000",
"status": 401,
"error": "Unauthorized",
"message": "No message available",
"path": "/v1/cooks"
}
pom.xml
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.restdocs</groupId>
<artifactId>spring-restdocs-mockmvc</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0-b170201.1204</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
EDIT: Added application.properties and dependies from pom
java spring-boot authentication http-status-code-401
java spring-boot authentication http-status-code-401
edited Nov 20 '18 at 9:58
Teocali
1,5811430
1,5811430
asked Oct 13 '18 at 20:26
kk1957
2,13062346
2,13062346
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
As looking your requirement, you really dont need multiple http security configurations until you are using multiple authentications for multiple paths(like for some path you would like to have jwt and for some you would like to have basic auth or auth2).
so remove SecurityCredentialsConfig and update WebSecurity to below and you will be good.
@Configuration
@EnableWebSecurity(debug = true) // Enable security config. This annotation denotes config for spring security.
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks/**").hasAuthority("ADMIN")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated()
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I did that, however now I am not able to use my first resource which ishttp://localhost:9100/auth/which generates a token. It says, 404.
– kk1957
Oct 14 '18 at 14:51
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
still same problem
– kk1957
Oct 15 '18 at 2:40
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
|
show 5 more comments
Try to add this
/**
on line in WebSecurity class,
.antMatchers("/v1/cooks/**" ).access("hasRole('ADMIN')")
please, if you can provide logs and version on spring boot and security dependencies this could help us much.
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
|
show 4 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52797019%2fspringboot-bearer-token-authentication-giving-401%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
As looking your requirement, you really dont need multiple http security configurations until you are using multiple authentications for multiple paths(like for some path you would like to have jwt and for some you would like to have basic auth or auth2).
so remove SecurityCredentialsConfig and update WebSecurity to below and you will be good.
@Configuration
@EnableWebSecurity(debug = true) // Enable security config. This annotation denotes config for spring security.
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks/**").hasAuthority("ADMIN")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated()
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I did that, however now I am not able to use my first resource which ishttp://localhost:9100/auth/which generates a token. It says, 404.
– kk1957
Oct 14 '18 at 14:51
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
still same problem
– kk1957
Oct 15 '18 at 2:40
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
|
show 5 more comments
As looking your requirement, you really dont need multiple http security configurations until you are using multiple authentications for multiple paths(like for some path you would like to have jwt and for some you would like to have basic auth or auth2).
so remove SecurityCredentialsConfig and update WebSecurity to below and you will be good.
@Configuration
@EnableWebSecurity(debug = true) // Enable security config. This annotation denotes config for spring security.
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks/**").hasAuthority("ADMIN")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated()
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
I did that, however now I am not able to use my first resource which ishttp://localhost:9100/auth/which generates a token. It says, 404.
– kk1957
Oct 14 '18 at 14:51
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
still same problem
– kk1957
Oct 15 '18 at 2:40
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
|
show 5 more comments
As looking your requirement, you really dont need multiple http security configurations until you are using multiple authentications for multiple paths(like for some path you would like to have jwt and for some you would like to have basic auth or auth2).
so remove SecurityCredentialsConfig and update WebSecurity to below and you will be good.
@Configuration
@EnableWebSecurity(debug = true) // Enable security config. This annotation denotes config for spring security.
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks/**").hasAuthority("ADMIN")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated()
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
As looking your requirement, you really dont need multiple http security configurations until you are using multiple authentications for multiple paths(like for some path you would like to have jwt and for some you would like to have basic auth or auth2).
so remove SecurityCredentialsConfig and update WebSecurity to below and you will be good.
@Configuration
@EnableWebSecurity(debug = true) // Enable security config. This annotation denotes config for spring security.
public class WebSecurity extends WebSecurityConfigurerAdapter {
@Autowired
private JwtConfig jwtConfig;
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
// make sure we use stateless session; session won't be used to store user's state.
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
// authorization requests config
.authorizeRequests()
// allow all who are accessing "auth" service
.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()
// must be an admin if trying to access admin area (authentication is also required here)
.antMatchers("/v1/cooks/**").hasAuthority("ADMIN")
//for other uris
// .antMatchers(HttpMethod.GET, "/v1/**").hasRole("USER")
// Any other request must be authenticated
.anyRequest().authenticated()
.and()
// handle an authorized attempts
.exceptionHandling().authenticationEntryPoint((req, rsp, e) -> rsp.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
// Add a filter to validate the tokens with every request
.addFilterAfter(new JwtTokenAuthenticationFilter(jwtConfig), UsernamePasswordAuthenticationFilter.class)
.addFilter(new JwtUsernameAndPasswordAuthenticationFilter(authenticationManager(), jwtConfig));
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
edited Oct 15 '18 at 17:14
answered Oct 14 '18 at 8:37
kj007
2,61931326
2,61931326
I did that, however now I am not able to use my first resource which ishttp://localhost:9100/auth/which generates a token. It says, 404.
– kk1957
Oct 14 '18 at 14:51
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
still same problem
– kk1957
Oct 15 '18 at 2:40
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
|
show 5 more comments
I did that, however now I am not able to use my first resource which ishttp://localhost:9100/auth/which generates a token. It says, 404.
– kk1957
Oct 14 '18 at 14:51
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
still same problem
– kk1957
Oct 15 '18 at 2:40
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
I did that, however now I am not able to use my first resource which is
http://localhost:9100/auth/ which generates a token. It says, 404.– kk1957
Oct 14 '18 at 14:51
I did that, however now I am not able to use my first resource which is
http://localhost:9100/auth/ which generates a token. It says, 404.– kk1957
Oct 14 '18 at 14:51
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
@kk1957 define SecurityCredentialsConfig order 2..check my updated answer.
– kj007
Oct 14 '18 at 17:46
still same problem
– kk1957
Oct 15 '18 at 2:40
still same problem
– kk1957
Oct 15 '18 at 2:40
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
would you mind sharing your sample code at github..I can look at exactly..
– kj007
Oct 15 '18 at 2:51
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
github.com/kashifusmani/foodie
– kk1957
Oct 15 '18 at 3:08
|
show 5 more comments
Try to add this
/**
on line in WebSecurity class,
.antMatchers("/v1/cooks/**" ).access("hasRole('ADMIN')")
please, if you can provide logs and version on spring boot and security dependencies this could help us much.
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
|
show 4 more comments
Try to add this
/**
on line in WebSecurity class,
.antMatchers("/v1/cooks/**" ).access("hasRole('ADMIN')")
please, if you can provide logs and version on spring boot and security dependencies this could help us much.
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
|
show 4 more comments
Try to add this
/**
on line in WebSecurity class,
.antMatchers("/v1/cooks/**" ).access("hasRole('ADMIN')")
please, if you can provide logs and version on spring boot and security dependencies this could help us much.
Try to add this
/**
on line in WebSecurity class,
.antMatchers("/v1/cooks/**" ).access("hasRole('ADMIN')")
please, if you can provide logs and version on spring boot and security dependencies this could help us much.
answered Oct 14 '18 at 5:30
Jonathan Johx
867211
867211
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
|
show 4 more comments
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Still same problem.
– kk1957
Oct 14 '18 at 14:56
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
Logs are accessible at pastebin.com/eaBGW0ZR
– kk1957
Oct 14 '18 at 14:57
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
added pom dependencies in the original question, also added application.properties.
– kk1957
Oct 14 '18 at 14:59
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
Okay, I've taken a look on your logs, you are using last version of spring boot 2.0.5 this version asks that you work on spring security 5, could you remove all dependencies of security and jwt and add dependency below <dependency> <groupId>org.springframework.security.oauth.boot</groupId> <artifactId>spring-security-oauth2-autoconfigure</artifactId> <version>2.0.5.RELEASE</version> </dependency>
– Jonathan Johx
Oct 15 '18 at 2:20
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
If you added it and it shows another error on your logs, you'll need to follow migration to spring security 5..
– Jonathan Johx
Oct 15 '18 at 2:22
|
show 4 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52797019%2fspringboot-bearer-token-authentication-giving-401%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown