3

I have a AuthorizationServer which uses password grant_type using Spring Security. I am using this for a mobile application. When a user enters their username and password to log in, the app calls the token endpoint and generates a token, if they are an authenticated user. This is all handled by password grant_type itself. For an unsuccessful login, it returns below general error with 400 HTTP status code.

{
  "error": "invalid_grant",
  "error_description": "Bad credentials"
}

For my scenario I need to customize this error message. Is their a way to change this error message?

I tried the suggested duplicate question: Customize authentication failure response in Spring Security using AuthenticationFailureHandler, but it uses the formLogin and it's not working with my implementation.

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
Rajith K
  • 399
  • 4
  • 18
  • Does this answer your question? [Customize authentication failure response in Spring Security using AuthenticationFailureHandler](https://stackoverflow.com/questions/42839910/customize-authentication-failure-response-in-spring-security-using-authenticatio) – Adisesha Jan 28 '20 at 06:47
  • Sorry @Adi I meant I am not using SSO and http.formLogin() my case, I am using grant_type password to log in users when username and password is provided via a mobile application. – Rajith K Jan 29 '20 at 03:54
  • check if this https://stackoverflow.com/questions/62368896/custom-error-objects-for-spring-rest-api-and-swagger-ui/62370012#62370012 works for you – Suraj Jun 14 '20 at 10:36

3 Answers3

3

I couldn't find an answer to this problem for many days. Finally, I got help from one of my colleagues. He asked me to follow this tutorial and it worked for me. Now I could transform the default spring framework response to my response template as follows.

{
    "status": 400,
    "message": "Invalid username or password",
    "timestamp": "2020-06-19T10:58:29.973+00:00",
    "payload": null
 }

But still, we don't know, why authenticationFailure handler is not working. Hope this helps.

sebin vincent
  • 330
  • 3
  • 12
0

Sabin answer is works, but i need to throw the exception using BadCredentialsException,

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    private final static Logger LOGGER = LogManager.getLogger(CustomAuthenticationProvider.class);

    @Autowired
    private UserService userService;

    @Override
    public Authentication authenticate(final Authentication authentication) throws AuthenticationException{

        final String username = authentication.getName();
        final String password = authentication.getCredentials().toString();

        try {

            /* CHECKING USER CREDENTIAL */
            /* check account */
            User userDetail = userService.findByUsername(username);
            if (userDetail == null){
                throw new Exception("User not found!");
            }

            /* check password */
            String origPass = Utilities.getEncrypted(new String(Base64.decodeBase64(password)), username);
            if(!userDetail.getPassword().equals(origPass)){
                throw new Exception("Wrong username or password!");
            }
            
            /* check is active */
            if(!userDetail.getIsActive()){
                throw new Exception("User is not active!");
            }

            /* check allowance in web type */
            if(Access.isWeb()){
                if(!userDetail.getIsWeb())
                    throw new Exception("Web access prohibited!");
            }

            /* check allowance in mobile type */
            if(Access.isMobile()){
                if(!userDetail.getIsMobile())
                    throw new Exception("Mobile access prohibited!");
            }
            
            /* do some logs */
            userService.login(userDetail);

            return new UsernamePasswordAuthenticationToken(userDetail, "{noop}".concat(origPass), userDetail.getAuthorities());

        } catch (Exception e) {
            LOGGER.error("[OAUTH] Error : " + e.getLocalizedMessage());
            throw new BadCredentialsException(e.getLocalizedMessage(), e);
        }
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return authentication.equals(UsernamePasswordAuthenticationToken.class);
    }

}
aswzen
  • 1,512
  • 29
  • 46
0

If you want to change only the message text in the response, than it will be enough to add the messages.properties file to the classpath of your application with the following content:

AbstractUserDetailsAuthenticationProvider.badCredentials=Invalid username or password

This will lead to the response below:

{
    "error": "invalid_grant",
    "error_description": "Invalid username or password"
}
Denis
  • 19
  • 2