Silhouette not using Custom Error handler when authentication fails


#1

Hi

My client was sending incorrect JWT token and Silhouette correctly responded with 401. I have created a custom error handler (extends HttpErrorHandler) so that I can send my application specific error response (JSON). But I notice that it wasn’t called when the authentication failed? Why?

I enabled debugging to see whats going on.

<logger name="com.mohiva" level="INFO" />
    <logger name="com.mohiva.play.silhouette.api.Silhouette" level="INFO" />

I found that Silhouette throws an error but I think the error is thrown before my Controller could handle it. The error is thrown at the entry point of the controller’s definition

def newQuestion = silhouette.SecuredAction.async(parse.json) {

The error was

com.mohiva.play.silhouette.api.exceptions.AuthenticatorException: [Silhouette][jwt-authenticator] Error on parsing JWT token: eyJ...
	at com.mohiva.play.silhouette.impl.authenticators.JWTAuthenticator$$anonfun$unserialize$5.applyOrElse(JWTAuthenticator.scala:154)111```

How can I handle this error and how can I use my custom error handler to send custom response?

thanks

#2

Hi Akkie

Could you please let me know how I could use my custom HTTPErrorHandler if Silhoutte’ throws an exception in silhouette.SecuredAction.async action?


#3

Hi,

have you read https://www.silhouette.rocks/docs/endpoints#section-local-error-handlers ?

Best regards,
Christian


#4

Thanks. The process to create local error handler part seems to be OK but the process to create a global error handler isn’t clear from the documentation.

I suppose for local error handler, I create an instance of SecuredErrorHandler and pass it to silhouette.SecuredAction.async(newSecuredActionHandler). As I don’t want to pass them individually to each action, the global handler is more suitable for me. However I am unable to understand what I need to do to create one. I suppose the documentation says that Silhouette provides modules default error handlers.

  1. Am I correct that the behaviour I am seeing the behaviour of default error handlers?

  2. I need to disable default error handler module in application.conf like play.modules.disabled += "com.mohiva.play.silhouette.api.actions.SecuredErrorHandlerModule"

  3. Once I have disabled the default error handler modules of Silhouette, I suppose I can provide my own implementation. This is where I am lost. I am using compile time injection to reference to play documentation (as it is been done in the documentation) isn’t helpful for me.

  4. I suppose I need to create new class which extends SecuredErrorHandler and override the methods of SecuredErrorHandler but once I do that, how do I tell Silhouette to use my implementation??


#5

got it. As I am using Compile time injection, I had to add my custom handler when I created the SecuredAction.

Earlier, I created SecuredAction as follows

val securedAction = new DefaultSecuredAction(new DefaultSecuredRequestHandler(new DefaultSecuredErrorHandler(messagesApi)), defaultParser )

I had to change it to

Where CustomSilhouetteSecuredErrorHandler
is defined as following (from silhouette’s documentation)

class CustomSilhouetteSecuredErrorHandler extends SecuredErrorHandler{

    override def onNotAuthenticated(implicit request: RequestHeader) = {
      Future.successful(Unauthorized(Json.toJson(JsonResultError("You need to sign in first"))))

    }

  override def onNotAuthorized(implicit request: RequestHeader) = {
    Future.successful(Forbidden(Json.toJson(JsonResultError("You do not have permission for the operation"))))
  }
}

for completeness sake, if I was using local error handling, I would have done

  val  errorHandler = new SecuredErrorHandler {
    override def onNotAuthenticated(implicit request: RequestHeader) = {
      Future.successful(Unauthorized(Json.toJson(JsonResultError("local.not.authenticated"))))

    }
    override def onNotAuthorized(implicit request: RequestHeader) = {
      Future.successful(Forbidden(Json.toJson(JsonResultError("local.not.authorized"))))
    }
  }

  def newQuestion = silhouette.SecuredAction(errorHandler ).async(parse.json) {...}