rack-jwt icon indicating copy to clipboard operation
rack-jwt copied to clipboard

Customize error messages from Auth

Open eparreno opened this issue 8 years ago • 10 comments

reported by @Morred

https://github.com/eigenbart/rack-jwt/issues/9

Hi there,

First of all, thanks for writing this gem, it's super useful!

I guess this one is more like a feature request, I'm looking for a way to customize the format of the error responses of the Auth class.

Every time something fails, it will automatically return a 401 response with the error body format that is hardcoded into this method, so currently I'm just monkeypatching the return_error method to build the error body into the format I need.

Is a general, more flexible way to format the error responses something you would consider adding to this gem?

eparreno avatar Feb 05 '17 18:02 eparreno

I know, it is obvious, but i think that good way to handle it is add localization files, just like in other gems like device. It is easy to develop, needs one default english-locale file somewhere inside the gem (no need to do generator for that). Also need to have configurable path to user locale file for overlapping and default value for it, or several, if it needs to do for distinct frameworks.

xfynx avatar Feb 07 '17 11:02 xfynx

@xfynx honestly I don't think localization is needed here. Error messages returned by the gem are not meant to be shown to the user, they are useful for logging and debugging but the client should show "Authentication failed" instead of "Invalid JWT token : Signature Verification Error", wdyt?

eparreno avatar Feb 25 '17 19:02 eparreno

@morred what's the point of having custom error messages? do you need a different format than {error: message} to accommodate error messages to your client without changes maybe?

eparreno avatar Feb 25 '17 19:02 eparreno

@eparreno yeah, you are right, there is no need more dependencies for gems like this. and "Authentication failed" is a great variant. In general i think that current variant is okay: no exceptions, that will return something another than 401 with description. From another point of view if it will be used as it is, it needs more common messages for user, but not scary "Invalid JWT ID" or "Incorrect Key Algorithm"

xfynx avatar Feb 25 '17 21:02 xfynx

I'd like to be able to do more than customize the error message string. I'd like to return a JSON error message with the same structure as all my other API errors. I haven't yet settled on exactly what that structure will be (I'm studying this SO answer). I was hoping I could pass a block as one of the options to customize the error generation.

@eparreno do you mind sharing your monkey patch?

mpoisot avatar Mar 23 '17 16:03 mpoisot

@eparreno Yeah I had to work against a spec that expected a very specific error response format.

@mpoisot I patched it like this:

require 'jwt'

module Rack
 module JWT
  class Auth
   def return_error(message)
    body =
     {
      errors: {
       code: '401',
       title: 'Authentication failure',
       details: message
      }
     }.to_json
     headers = { 'Content-Type' => 'application/json', 'Content-Length' => body.bytesize.to_s }
 
     [401, headers, [body]]
    end
   end
  end
end

Now that just hardcodes the exact error message that I needed, but it shouldn't be too hard to change it so it accepts a custom error message template. I can give it a go if that's something you guys would be interested in adding to the gem.

Morred avatar Mar 24 '17 01:03 Morred

I ended up here also looking for a way to customise the HTTP 401 JSON. How about an option, say, called customize_unauthorized_response, which is a proc that accepts the original message?

The default proc would emulate the current behavior:

CUSTOMIZE_UNAUTHORIZED_RESPONSE = Proc.new { |message| { error: message } }

Then, return_error would just call either a provided proc, or, the default if none provided, to format the body:

 def initialize(app, opts = {})
        @app     = app
        @customize_unauthorized_response  = opts.fetch(:customize_unauthorized_response, CUSTOMIZE_UNAUTHORIZED_RESPONSE)
....

def return_error(message)
  body    = @customize_unauthorized_response.call(message).to_json
   ...

Is that too much indirection? Thoughts? I could try a PR if there is interest in this feature.

All this being said, I'm just looking to dupe the HTTP status code in the body because I'm dealing with a client that has no access to the HTTP status (!).

twelve17 avatar Jul 18 '17 00:07 twelve17

Whoops, I just noticed @mpoisot suggested passing in a block as well. Apologies for the dupe.

twelve17 avatar Jul 18 '17 00:07 twelve17

Sorry for the delay guys, gonna check that one today since a few people is interested

eparreno avatar Jul 19 '17 08:07 eparreno

@eparreno any updates? At least 1 day passed :P

RaVbaker avatar Apr 15 '21 12:04 RaVbaker