waiting-for-dev / devise-jwt

JWT token authentication with devise and rails

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

JWT::DecodeError when passing token such as "Bearer test"

DavidAmyot opened this issue · comments

When trying to do a logout and passing an invalid token, it gives me a JWT::DecodeError (Not enough or too many segments) error, but only in specific cases.

Passing values such as bearertest, Bearer, test, nil, Bearertest in the authorization header are intercepted easily in my respond_to_on_destroy, but values such as 'Bearer test' gives me an error 500. Actually, it's kind of strange because in my rails terminal, I can see that the controller returns a 200, but afterwards I see the 500 error JWT::DecodeError and it gives me the 500 on postman instead of the 200 with my rendered json.

Currently using the basic JTI matcher strategy, pretty much everything default. All other scenarios work well.

My destroy is just:

  # GET /api/v1/users/logout
  def destroy
    super
  end

Even if I don't have a respond_to_on_destroy or an empty one, the issue still happens.

To Reproduce

Make a logout request with an valid token such as "Bearer test".

Current behavior

Gives a JWT::DecodeError (Not enough or too many segments): error.

Expected behavior

Screenshots

image
image

Additional context

Stack Trace:

Started GET "/api/v1/users/logout" for 127.0.0.1 at 2022-12-21 12:40:47 -0500
Processing by Api::V1::Users::SessionsController#destroy as JSON
Filter chain halted as :verify_signed_out_user rendered or redirected
Completed 204 No Content in 7ms (ActiveRecord: 0.0ms)


  
JWT::DecodeError (Not enough or too many segments):
  
jwt (2.1.0) lib/jwt/decode.rb:37:in `raw_segments'
jwt (2.1.0) lib/jwt/decode.rb:25:in `decode_segments'
jwt (2.1.0) lib/jwt.rb:31:in `decode'
warden-jwt_auth (0.5.0) lib/warden/jwt_auth/token_decoder.rb:17:in `call'
warden-jwt_auth (0.5.0) lib/warden/jwt_auth/token_revoker.rb:13:in `call'
warden-jwt_auth (0.5.0) lib/warden/jwt_auth/middleware/revocation_manager.rb:34:in `revoke_token'
warden-jwt_auth (0.5.0) lib/warden/jwt_auth/middleware/revocation_manager.rb:22:in `call'
rack (2.2.4) lib/rack/builder.rb:244:in `call'
warden-jwt_auth (0.5.0) lib/warden/jwt_auth/middleware.rb:23:in `call'
remotipart (1.4.2) lib/remotipart/middleware.rb:32:in `call'
warden (1.2.9) lib/warden/manager.rb:36:in `block in call'
warden (1.2.9) lib/warden/manager.rb:34:in `catch'
warden (1.2.9) lib/warden/manager.rb:34:in `call'
rack (2.2.4) lib/rack/etag.rb:27:in `call'
rack (2.2.4) lib/rack/conditional_get.rb:27:in `call'
rack (2.2.4) lib/rack/head.rb:12:in `call'
rack (2.2.4) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.4) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/cookies.rb:613:in `call'
activerecord (5.1.7) lib/active_record/migration.rb:556:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
activesupport (5.1.7) lib/active_support/callbacks.rb:97:in `run_callbacks'
actionpack (5.1.7) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
web-console (3.7.0) lib/web_console/middleware.rb:135:in `call_app'
web-console (3.7.0) lib/web_console/middleware.rb:30:in `block in call'
web-console (3.7.0) lib/web_console/middleware.rb:20:in `catch'
web-console (3.7.0) lib/web_console/middleware.rb:20:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.7) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.7) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.7) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.7) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.7) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.7) lib/rails/rack/logger.rb:24:in `call'
sprockets-rails (3.2.2) lib/sprockets/rails/quiet_assets.rb:13:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
request_store (1.4.1) lib/request_store/middleware.rb:19:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.2.4) lib/rack/method_override.rb:24:in `call'
rack (2.2.4) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.7) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.7) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.2.4) lib/rack/sendfile.rb:110:in `call'
rack-cors (1.0.2) lib/rack/cors.rb:97:in `call'
railties (5.1.7) lib/rails/engine.rb:522:in `call'
puma (3.12.0) lib/puma/configuration.rb:225:in `call'
puma (3.12.0) lib/puma/server.rb:658:in `handle_request'
puma (3.12.0) lib/puma/server.rb:472:in `process_client'
puma (3.12.0) lib/puma/server.rb:332:in `block in run'
puma (3.12.0) lib/puma/thread_pool.rb:133:in `block in spawn_thread'

Not sure to understand the issue here, but getting the exception is what's expected for an invalid token. Am I missing something?

@waiting-for-dev If I pass values such as bearertest, Bearer, test, nil, Bearertest, it goes into the respond_to_on_destroy, but if I pass something like Bearer test, no matter what I tried, I can't get it to go into the respond_to_on_destroy and it gives me a 500 error (like the screenshot).

Is that the intentional behaviour? I believe that's because it thinks Bearer test is a valid token since there is the separate Bearer keyword first.

I'm new to the library so I'm not sure at all if I'm doing something wrong though. Tokens always start with eyJ... and have a minimum amount of characters, maybe validating this?

Thanks for taking the time to read through this!

Where is that respond_to_on_destroy coming from?

From class Api::V1::Users::SessionsController < Devise::SessionsController.

Not sure how to help here. The error comes from jwt-ruby library and, yes, probably providing a malformed token can produce that kind of error. I don't think we need to do anything special in this library for that. It makes sense that the request doesn't go forward and it doesn't reach the respond_to_on_destroy hook.

Closing as it looks like the normal behaviour for jwt-ruby. Thanks again for reporting.

how do you address the part where it doesn't throw off an exception? @waiting-for-dev i'm trying to prevent the exception from happening by validating if token is a valid token.

    return render json: { error: 'Invalid token' }, status: :unauthorized unless current_user

my understanding is that the middleware continues despite having to respond with an error, the middleware continues with jwt_auth and this throws an exception cause the token is invalid, which is fine, I'd like to know how i can stop the request from getting there, like just return this response to my API.

any leads? @waiting-for-dev`

disregard this request I dug up old resource that is helpful.
#234