In Spring Security Oauth2 based authentication when the client sends an access token which needs to be refreshed, the DefaultTokenServices class throws an InvalidTokenException (see at line 235):
https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/main/java/org/springframework/security/oauth2/provider/token/DefaultTokenServices.java
the output when this happens is something like:
{"error":"invalid_token","error_description":"Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9"
}
I'd like to change this output but I got lost. Some other answer suggested setting up a custom exceptionRenderer but this didn't work either, my custom exception renderer never gets called in these cases.
Also there's something called an exception translator but they werent called either in any case.
Part of my spring config:
<bean id="clientAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="typeName" value="Basic"/>
<property name="exceptionRenderer" ref="myExceptionRenderer" />
</bean>
<bean id="oauthAuthenticationEntryPoint"
class="org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint">
<property name="exceptionRenderer" ref="myExceptionRenderer" />
<property name="exceptionTranslator" ref="listyOauthExceptionTranslator" />
</bean>
<bean id="oauthAccessDeniedHandler" class="org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler" >
<property name="exceptionRenderer" ref="myExceptionRenderer" />
<property name="exceptionTranslator" ref="myExceptionTranslator" />
</bean>
<bean id="myExceptionRenderer" class="com.example.exceptions.MyOauth2ExceptionRenderer" />
<bean id="myExceptionTranslator" class="com.example.exceptions.MyOauth2ExceptionTranslator" />
The exception renderer:
public class MyExceptionRenderer implements OAuth2ExceptionRenderer {
@Override
public void handleHttpEntityResponse(HttpEntity<?> responseEntity, ServletWebRequest webRequest) throws Exception {
System.out.println("Thrown exception");
}
}
I also added a custom Exception Mapper which should get ALL the exceptions, but since I assume its another servlet this doesnt really work in this case?
@Provider
public class GenericExceptionMapper implements ExceptionMapper<Throwable> {
@Override
public Response toResponse(Throwable ex) {
System.out.println("MAPPING EXCEPTION");
return Response.status(200).entity().build();
}
}
I could catch cases of AuthenticationException, but not any of the InvalidTokenExceptions.
Any help regarding this? Where does Spring actually catch this InvalidTokenException and how can I set it up so I can provide a custom output?
InvalidTokenException extends ClientAuthenticationException
. So you can create your own exception by extending ClientAuthenticationException
and throw this instead of InvalidTokenException
public class CustomException extends ClientAuthenticationException {
public CustomException(String msg, Throwable t) {
super(msg, t);
}
public CustomException(String msg) {
super(msg);
}
@Override
public String getOAuth2ErrorCode() {
return "my_custom_exception";
}
}
like
throw new CustomException("Invalid access token: " + accessTokenValue);
In the error that is thrown by InvalidTokenException
{"error":"invalid_token","error_description":"Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9"}
invalid_token
is returned by getOAuth2ErrorCode()
method of InvalidTokenException and Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9
is the message that you give when you throw the exception.
If you throw
throw new CustomException("This is my custom exception");
the error would be shown as
{"error":"my_custom_exception","error_description":"This is my custom exception"}
my_custom_exception
is coming from getOAuth2ErrorCode()
of CustomException
.
for overriding
{"error":"invalid_token","error_description":"Invalid access token: a0cb5ab9-7281-46bd-a9a2-796a04a906c9"
}
you need to inherit ResourceServerConfigurerAdapter and override public void configure(final ResourceServerSecurityConfigurer config)
sample code
package com.org.security;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.common.exceptions.OAuth2Exception;
import org.springframework.security.oauth2.provider.error.DefaultWebResponseExceptionTranslator;
import org.springframework.stereotype.Component;
@Component
public class CustomWebResponseExceptionTranslator extends DefaultWebResponseExceptionTranslator {
/**
* Modify OAuth2.0 Error Response
* @param e
* @return ResponseEntity<OAuth2Exception>
* @throws Exception
*/
@Override
public ResponseEntity<OAuth2Exception> translate(Exception e) throws Exception {
ResponseEntity responseEntity = super.translate(e);
OAuth2Exception auth2Exception = (OAuth2Exception)responseEntity.getBody();
if (auth2Exception != null) {
auth2Exception.addAdditionalInformation("data", null);
auth2Exception.addAdditionalInformation("message", auth2Exception.getMessage());
auth2Exception.addAdditionalInformation("statusCode", String.valueOf(auth2Exception.getHttpErrorCode()));
}
return new ResponseEntity<OAuth2Exception>(auth2Exception, responseEntity.getHeaders(), responseEntity.getStatusCode());
}
}
package com.org.security;
import com.org.exception.CustomAuthExceptionEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.error.OAuth2AccessDeniedHandler;
import org.springframework.security.oauth2.provider.error.OAuth2AuthenticationEntryPoint;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;
@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Autowired
private ResourceServerTokenServices tokenServices;
@Autowired
private WebResponseExceptionTranslator oauth2ResponseExceptionTranslator;
@Override
public void configure(final ResourceServerSecurityConfigurer config) {
OAuth2AccessDeniedHandler auth2AccessDeniedHandler = new OAuth2AccessDeniedHandler();
auth2AccessDeniedHandler.setExceptionTranslator(oauth2ResponseExceptionTranslator);
OAuth2AuthenticationEntryPoint authenticationEntryPoint = new OAuth2AuthenticationEntryPoint();
authenticationEntryPoint.setExceptionTranslator(oauth2ResponseExceptionTranslator);
config.tokenServices(tokenServices).accessDeniedHandler(auth2AccessDeniedHandler).authenticationEntryPoint(authenticationEntryPoint);
}
}
The answer does not really deliver custom implementation, a custom response will be a point in code where I can access the default response and I can send a POJO instead of it, for example if you want to change error_description
to error_info
or anything else, or you may want to add more variables to the response. The solution does exist, but I think it is painful to implement to say the least, as I copy it from here:
This problem has been solved. Follow the workaround below:
- Extend
OAuth2Exception
to a new class, such as CustomOAuth2Exception. In the custom class, add some specific properties.- custom
DefaultWebResponseExceptionTranslator
and register the custom translator inAuthorizationServerConfiguration
.- custom two jackson serializers annotated in
OAuth2Exception
and annotated yourCustomOAuth2Exception
with the two custom serializers.- use
ObjectMapper
to override initial serializers with custom serializers.
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