We have a rest API that uses Spring OAuth2
. After the user is authenticated, all the JSON responses are in the following format:
{"code" : 12345, "data" : "..." }
But the JSON response for authentication failures is not inline with the above format, as that is handled by Spring.
For example in case of incorrect credentials, the clients get HTTP status code 400 with JSON response as follows:
{"error": "invalid_grant", "error_description": "Bad credentials" }
In case the user account is locked, the clients get HTTP status code 400 with JSON response as follows
{"error":"invalid_grant","error_description":"User account is locked"}
All of this is because Spring TokenEndpoint.handleException() is handling the exceptions associated with /oauth/token
I would like to change the JSON response for OAuth2 failures to follow the first format.
This is what I have tried so far with no success:
Any help in any of the above approaches or a new one would be highly appreciated.
I haven't tried this approach as I cannot change the contextpath for the existing clients.
If you want to handle the authentication process, you can setup your own custom authentication manager
<oauth:authorization-server
client-details-service-ref="clientDetails" token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler">
<oauth:authorization-code />
<oauth:implicit />
<oauth:refresh-token />
<oauth:client-credentials />
<oauth:password authentication-manager-ref="customAuthenticationManager" />
</oauth:authorization-server>
<authentication-manager id="customAuthenticationManager"
xmlns="http://www.springframework.org/schema/security">
<authentication-provider ref="customAuthenticationProvider" />
</authentication-manager>
<bean id="customAuthenticationProvider"
class="com.any.CustomAuthenticationProvider">
</bean>
create custom authentication provider that implements AuthenticationProvider
public class UserAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePasswordAuthenticationToken auth = (UsernamePasswordAuthenticationToken) authentication;
String username = auth.getName();
String password = token.getCredentials().toString();
User user = userService.loadByUsername(username);
if(user.isLocked){
throw new UserLockedException("User is locked");
}
if(another.something.bad.happened){
throw new AnotherSomethingBadHappenedException("Error");
}
// setup authorities
//...
return new UsernamePasswordAuthenticationToken(user, password, authorities);
}
}
Now you have your own exception, and by using ExceptionMapper you can translate the exception thrown on authentication process into your custom response message.
Another customization you can create is on Authorization process by creating a custom class that extends ApprovalStoreUserApprovalHandler
public class CustomUserApprovalHandler extends ApprovalStoreUserApprovalHandler {
// stripped
@Override
public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest,
Authentication userAuthentication) {
ClientDetails client = clientDetailsService
.loadClientByClientId(authorizationRequest.getClientId());
// here, you have the client and the user
// you can do any checking here and throw any exception
authorizationRequest.setApproved(approved);
return authorizationRequest;
}
}
create bean definition for that class
<bean id="userApprovalHandler"
class="com.any.CustomUserApprovalHandler">
<property name="approvalStore" ref="approvalStore" />
<property name="requestFactory" ref="oAuth2RequestFactory" />
<property name="clientDetailsService" ref="clientDetails" />
<property name="useApprovalStore" value="true" />
</bean>
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