Arian
Arian

Reputation: 7739

Spring Boot: error="invalid_grant", error_description="Bad credentials"

I wrote a very Spring boot simple app.

To get the authentication token, I used the following curl command. But instead I see the following error in the server log (eclipse console): error="invalid_grant", error_description="Bad credentials"

curl -v -u greetings:123456 -X POST http://localhost:8080/oauth/token -H "Accept: application/json" -d "username=username&password=password&grant_type=password&scope=write&client_secret=12345&client_id=greetings"

I wonder:

What have I done wrong that it doesn't let me get the auth code?

OAuth2ServerConfiguration.java

import org.springframework.beans.factory.annotation.Autowired;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
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.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;


@Configuration
@EnableResourceServer
@EnableAuthorizationServer
class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {

    String applicationName = "greetings";

    // This is required for password grants, which we specify below as one of the
    // {@literal authorizedGrantTypes()}.
    @Autowired
    AuthenticationManagerBuilder authenticationManager;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
            throws Exception {
        // Workaround for https://github.com/spring-projects/spring-boot/issues/1801
        endpoints.authenticationManager(new AuthenticationManager() {
            @Override
            public Authentication authenticate(Authentication authentication)
                    throws AuthenticationException {
                // TODO Auto-generated method stub
                return authenticationManager.getOrBuild().authenticate(authentication);
            }
        });
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        clients.inMemory()
            .withClient(applicationName)
            .authorizedGrantTypes("password", "authorization_code", "refresh_token")
            .authorities("ROLE_USER")
            .scopes("write")
            .resourceIds(applicationName)
            .secret("123456");
    }
}

WebSecurityConfiguration.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.User;

import com.boot.myproj.repository.AccountRepository;

class WebSecurityConfiguration extends GlobalAuthenticationConfigurerAdapter {

    @Autowired
    AccountRepository userRepository;

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService());
    }

    @Bean
    UserDetailsService userDetailsService() {
        return (username) -> userRepository
                .findByUsername(username)
                .map(a -> new User(a.username, a.password, true, true, true, true,
                        AuthorityUtils.createAuthorityList("USER", "write")))
                .orElseThrow(
                        () -> new UsernameNotFoundException("could not find the user '"
                                + username + "'"));
    }
}

Account.java

import javax.persistence.*;


import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
public class Account {

    @Id
    @GeneratedValue
    private Long id;

    public Long getId() {
        return id;
    }

    public String getPassword() {
        return password;
    }

    public String getUsername() {
        return username;
    }

    @JsonIgnore
    public String password;
    public String username;

    public Account(String name, String password) {
        this.username = name;
        this.password = password;
    }

    Account() { // jpa only
    }
}

AccountRepository.java

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;

import com.boot.myproj.config.security.Account;

public interface AccountRepository extends JpaRepository<Account, String>{
    public Optional<Account> findByUsername(String username);
}

App.java

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import com.boot.cut_costs.config.security.Account;
import com.boot.cut_costs.repository.AccountRepository;

@SpringBootApplication
public class App {
    public static void main(String[] args) {
        SpringApplication.run(App.class, args);
    }

    @Bean
    CommandLineRunner init(AccountRepository accountRepository) {
        return (arg) -> {
            accountRepository.save(new Account("username", "password"));
        };
    }
}

Upvotes: 2

Views: 15831

Answers (1)

Pratik Shah
Pratik Shah

Reputation: 1852

Add @Configuration to WebSecurityConfiguration class. So that your bean will get injected in spring context.

p.s. What you are trying to do here with OAuth2 password grant will not return an auth code , instead it'll directly return you a accessToken.

Upvotes: 8

Related Questions