Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v0.10.0.rc5 interferes with devise_token_auth #1667

Closed
JamesChevalier opened this issue Apr 6, 2016 · 36 comments
Closed

v0.10.0.rc5 interferes with devise_token_auth #1667

JamesChevalier opened this issue Apr 6, 2016 · 36 comments

Comments

@JamesChevalier
Copy link

Expected behavior vs actual behavior

With version 0.10.0.rc4 ASM is not serializing the response from devise_token_auth, so sign_in succeeds:

Started POST "/api/v1/auth/sign_in" for 127.0.0.1 at 2016-04-06 11:55:32 -0400
  ActiveRecord::SchemaMigration Load (0.9ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by DeviseTokenAuth::SessionsController#create as JSON
  Parameters: {"email"=>"EMAIL", "password"=>"[FILTERED]"}
Can't verify CSRF token authenticity
  User Load (3.4ms)  SELECT  "users".* FROM "users" WHERE (email = 'EMAIL' AND provider='email')  ORDER BY "users"."id" ASC LIMIT 1
   (1.0ms)  BEGIN
  SQL (2.2ms)  UPDATE "users" SET "tokens" = $1, "updated_at" = $2 WHERE "users"."id" = $3  [
  ["tokens", "{\"KEY\":{\"token\":\"VALUE\",\"expiry\":1460489763}}"], ["updated_at", "2016-04-06 15:55:32.864239"], ["id", 1]]
   (1.2ms)  COMMIT
   (0.8ms)  BEGIN
  SQL (1.4ms)  UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5  [["last_sign_in_at", "2016-04-06 15:53:07.210140"], ["current_sign_in_at", "2016-04-06 15:55:32.887707"], ["sign_in_count", 33], ["updated_at", "2016-04-06 15:55:32.889785"], ["id", 1]]
   (1.2ms)  COMMIT
Completed 200 OK in 212ms (Views: 5.4ms | ActiveRecord: 13.1ms)

With version 0.10.0.rc5 ASM is attempting to serialize the response from devise_token_auth, so sign_in fails:

Started POST "/api/v1/auth/sign_in" for 127.0.0.1 at 2016-04-06 11:57:45 -0400
  ActiveRecord::SchemaMigration Load (1.0ms)  SELECT "schema_migrations".* FROM "schema_migrations"
Processing by DeviseTokenAuth::SessionsController#create as JSON
  Parameters: {"email"=>"EMAIL", "password"=>"[FILTERED]"}
Can't verify CSRF token authenticity
  User Load (2.3ms)  SELECT  "users".* FROM "users" WHERE (email = 'EMAIL' AND provider='email')  ORDER BY "users"."id" ASC LIMIT 1
   (1.1ms)  BEGIN
  SQL (1.8ms)  UPDATE "users" SET "tokens" = $1, "updated_at" = $2 WHERE "users"."id" = $3  [["tokens", "{\"KEY\":{\"token\":\"VALUE\",\"expiry\":1460489763}}"], ["updated_at", "2016-04-06 15:57:45.253067"], ["id", 1]]
   (1.2ms)  COMMIT
   (0.9ms)  BEGIN
  SQL (1.3ms)  UPDATE "users" SET "last_sign_in_at" = $1, "current_sign_in_at" = $2, "sign_in_count" = $3, "updated_at" = $4 WHERE "users"."id" = $5  [["last_sign_in_at", "2016-04-06 15:55:32.887707"], ["current_sign_in_at", "2016-04-06 15:57:45.271287"], ["sign_in_count", 34], ["updated_at", "2016-04-06 15:57:45.273380"], ["id", 1]]
   (1.1ms)  COMMIT
[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.14ms)
Completed 500 Internal Server Error in 207ms (Views: 7.5ms | ActiveRecord: 10.9ms)

Steps to reproduce

(e.g., detailed walkthrough, runnable script, example application)

The environment is a Rails app that uses devise_token_auth for authentication, and active_model_serializers to serialize responses. The error occurs when the rc5 version of active_model_serializers is in place, and it does not appear when the rc4 version is in place.

I'm not sure if the fix will ultimately reside in devise_token_auth or here.

I've included more information at the bottom.

Environment

ActiveModelSerializers Version (commit ref if not on tag):
0.10.0.rc5

Output of ruby -e "puts RUBY_DESCRIPTION":
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin14]

OS Type & Version:
Mac OS X 10.10.5

Integrated application and version (e.g., Rails, Grape, etc):
Rails 4.2.6
devise 3.5.6
devise_token_auth 0.1.37 (code)

Backtrace

(e.g., provide any applicable backtraces from your application)

> undefined method `[]' for nil:NilClass

devise_token_auth (0.1.37) app/models/devise_token_auth/concerns/user.rb, line 202
----------------------------------------------------------------------------------

  197     def build_auth_header(token, client_id='default')
  198       client_id ||= 'default'
  199   
  200       # client may use expiry to prevent validation request if expired
  201       # must be cast as string or headers will break
> 202       expiry = self.tokens[client_id]['expiry'] || self.tokens[client_id][:expiry]
  203   
  204       return {
  205         "access-token" => token,
  206         "token-type"   => "Bearer",
  207         "client"       => client_id,
NoMethodError - undefined method `[]' for nil:NilClass:
  devise_token_auth (0.1.37) app/models/devise_token_auth/concerns/user.rb:202:in `build_auth_header'
  devise_token_auth (0.1.37) app/controllers/devise_token_auth/concerns/set_user_by_token.rb:77:in `update_auth_header'
  activesupport (4.2.6) lib/active_support/callbacks.rb:432:in `block in make_lambda'
  activesupport (4.2.6) lib/active_support/callbacks.rb:239:in `block in halting'
  activesupport (4.2.6) lib/active_support/callbacks.rb:506:in `block in call'
  activesupport (4.2.6) lib/active_support/callbacks.rb:506:in `call'
  activesupport (4.2.6) lib/active_support/callbacks.rb:498:in `block (2 levels) in around'
  activesupport (4.2.6) lib/active_support/callbacks.rb:313:in `block (2 levels) in halting'
  rails-observers (0.1.2) lib/rails/observers/action_controller/caching/sweeping.rb:73:in `around'
  activesupport (4.2.6) lib/active_support/callbacks.rb:455:in `block in make_lambda'
  activesupport (4.2.6) lib/active_support/callbacks.rb:312:in `block in halting'
  activesupport (4.2.6) lib/active_support/callbacks.rb:497:in `block in around'
  activesupport (4.2.6) lib/active_support/callbacks.rb:505:in `call'
  activesupport (4.2.6) lib/active_support/callbacks.rb:92:in `__run_callbacks__'
  activesupport (4.2.6) lib/active_support/callbacks.rb:778:in `_run_process_action_callbacks'
  activesupport (4.2.6) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.6) lib/abstract_controller/callbacks.rb:19:in `process_action'
  actionpack (4.2.6) lib/action_controller/metal/rescue.rb:29:in `process_action'
  actionpack (4.2.6) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
  activesupport (4.2.6) lib/active_support/notifications.rb:164:in `block in instrument'
  activesupport (4.2.6) lib/active_support/notifications/instrumenter.rb:20:in `instrument'
  activesupport (4.2.6) lib/active_support/notifications.rb:164:in `instrument'
  actionpack (4.2.6) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
  actionpack (4.2.6) lib/action_controller/metal/params_wrapper.rb:250:in `process_action'
  activerecord (4.2.6) lib/active_record/railties/controller_runtime.rb:18:in `process_action'
  actionpack (4.2.6) lib/abstract_controller/base.rb:137:in `process'
  actionview (4.2.6) lib/action_view/rendering.rb:30:in `process'
  rack-mini-profiler (0.9.9.2) lib/mini_profiler/profiling_methods.rb:102:in `block in profile_method'
  actionpack (4.2.6) lib/action_controller/metal.rb:196:in `dispatch'
  actionpack (4.2.6) lib/action_controller/metal/rack_delegation.rb:13:in `dispatch'
  actionpack (4.2.6) lib/action_controller/metal.rb:237:in `block in action'
  actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:74:in `dispatch'
  actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:43:in `serve'
  actionpack (4.2.6) lib/action_dispatch/routing/mapper.rb:49:in `serve'
  actionpack (4.2.6) lib/action_dispatch/journey/router.rb:43:in `block in serve'
  actionpack (4.2.6) lib/action_dispatch/journey/router.rb:30:in `serve'
  actionpack (4.2.6) lib/action_dispatch/routing/route_set.rb:817:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  bullet (5.0.0) lib/bullet/rack.rb:12:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/rack/agent_hooks.rb:30:in `traced_call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/rack/browser_monitoring.rb:32:in `traced_call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/rack/developer_mode.rb:48:in `traced_call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  warden (1.2.6) lib/warden/manager.rb:35:in `block in call'
  warden (1.2.6) lib/warden/manager.rb:34:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/etag.rb:24:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/conditionalget.rb:38:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/head.rb:13:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/params_parser.rb:27:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/flash.rb:260:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/session/abstract/id.rb:225:in `context'
  rack (1.6.4) lib/rack/session/abstract/id.rb:220:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/cookies.rb:560:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  activerecord (4.2.6) lib/active_record/query_cache.rb:36:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  activerecord (4.2.6) lib/active_record/connection_adapters/abstract/connection_pool.rb:653:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  activerecord (4.2.6) lib/active_record/migration.rb:377:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
  activesupport (4.2.6) lib/active_support/callbacks.rb:88:in `__run_callbacks__'
  activesupport (4.2.6) lib/active_support/callbacks.rb:778:in `_run_call_callbacks'
  activesupport (4.2.6) lib/active_support/callbacks.rb:81:in `run_callbacks'
  actionpack (4.2.6) lib/action_dispatch/middleware/callbacks.rb:27:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/reloader.rb:73:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/remote_ip.rb:78:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rollbar (2.8.3) lib/rollbar/middleware/rails/rollbar.rb:24:in `block in call'
  rollbar (2.8.3) lib/rollbar.rb:948:in `scoped'
  rollbar (2.8.3) lib/rollbar/middleware/rails/rollbar.rb:22:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:84:in `protected_app_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:79:in `better_errors_call'
  better_errors (2.1.1) lib/better_errors/middleware.rb:57:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/debug_exceptions.rb:17:in `call'
  rollbar (2.8.3) lib/rollbar/middleware/rails/show_exceptions.rb:22:in `call_with_rollbar'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  web-console (2.3.0) lib/web_console/middleware.rb:28:in `block in call'
  web-console (2.3.0) lib/web_console/middleware.rb:18:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/show_exceptions.rb:30:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  railties (4.2.6) lib/rails/rack/logger.rb:38:in `call_app'
  railties (4.2.6) lib/rails/rack/logger.rb:20:in `block in call'
  activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in `block in tagged'
  activesupport (4.2.6) lib/active_support/tagged_logging.rb:26:in `tagged'
  activesupport (4.2.6) lib/active_support/tagged_logging.rb:68:in `tagged'
  railties (4.2.6) lib/rails/rack/logger.rb:20:in `call'
  quiet_assets (1.1.0) lib/quiet_assets.rb:27:in `call_with_quiet_assets'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/request_id.rb:21:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/methodoverride.rb:22:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/runtime.rb:18:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  activesupport (4.2.6) lib/active_support/cache/strategy/local_cache_middleware.rb:28:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/lock.rb:17:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  actionpack (4.2.6) lib/action_dispatch/middleware/static.rb:120:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/sendfile.rb:113:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack-cors (0.4.0) lib/rack/cors.rb:80:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack-mini-profiler (0.9.9.2) lib/mini_profiler/profiler.rb:281:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  railties (4.2.6) lib/rails/engine.rb:518:in `call'
  railties (4.2.6) lib/rails/application.rb:165:in `call'
  newrelic_rpm (3.15.1.316) lib/new_relic/agent/instrumentation/middleware_tracing.rb:96:in `call'
  rack (1.6.4) lib/rack/content_length.rb:15:in `call'
  thin (1.6.4) lib/thin/connection.rb:86:in `block in pre_process'
  thin (1.6.4) lib/thin/connection.rb:84:in `pre_process'
  thin (1.6.4) lib/thin/connection.rb:53:in `process'
  thin (1.6.4) lib/thin/connection.rb:39:in `receive_data'
  eventmachine (1.2.0.1) lib/eventmachine.rb:194:in `run'
  thin (1.6.4) lib/thin/backends/base.rb:73:in `start'
  thin (1.6.4) lib/thin/server.rb:162:in `start'
  rack (1.6.4) lib/rack/handler/thin.rb:19:in `run'
  rack (1.6.4) lib/rack/server.rb:286:in `start'
  railties (4.2.6) lib/rails/commands/server.rb:80:in `start'
  railties (4.2.6) lib/rails/commands/commands_tasks.rb:80:in `block in server'
  railties (4.2.6) lib/rails/commands/commands_tasks.rb:75:in `server'
  railties (4.2.6) lib/rails/commands/commands_tasks.rb:39:in `run_command!'
  railties (4.2.6) lib/rails/commands.rb:17:in `<top (required)>'
  bin/rails:4:in `<main>'

Additonal helpful information

(e.g., Gemfile.lock, configurations, PR containing a failing test, git bisect results)

I do have a serializer for User, but it looks like devise_token_auth isn't using it. The rc5 output at the top of this issue included this line: [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.14ms) ... The Null in there seems odd.

With rc4, the client_id is making it into the build_auth_header method. With rc5, it is not (it exists as default).

I've been trying to trace back that client_id value, but I haven't been successful in finding where it gets unset. I'm going to file an issue with devise_token_auth to see if they can explain it.

If the fix ends up being that devise_token_auth has to avoid running its response through active_model_serializers, is there a way to do that?

@NullVoxPopuli
Copy link
Contributor

hello, I also use devise (with ember! (ember-simple-auth))

this is how I handle sign ins:

class Api::Users::SessionsController < Devise::SessionsController
  clear_respond_to
  respond_to :json

  prepend_before_filter :require_no_authentication, only: [:create]

  # We have to write our own login, cause devise isn't
  # designed for API Authentication
  #
  # instead of returning the current user,
  # we want to return the auth token.
  # the auth token and email will be passed on every request,
  # and the user will be authorized based on the validitity
  # of the token and email pair.
  #
  # HTTPS required :-)
  def create
    resource = User.find_by_email(params[:email])
    return invalid_login_attempt unless resource

    success = resource.valid_password?(params[:password])

    if success
      sign_in("user", resource)
      return render_success(resource)
    end

    invalid_login_attempt
  end

  protected

  def invalid_login_attempt
    # have to declare custom failure,
    # cause warden likes to redirect
    warden.custom_failure!

    render json: {
      error: I18n.t('devise.failure.not_found_in_database')
    }, status: 401
  end

  def render_success(user)
    data = {
       token: user.authentication_token,
       email: user.email,
       id: user.id
     }
     render json: data, status: 201
  end
end

here is how I handle getting the current user with each request:

  def authenticate_user_from_token!
    http_authorization = request.env['HTTP_AUTHORIZATION']
    return false unless http_authorization
    matches = http_authorization.match(/Bearer (.+)\z/)
    return false unless matches
    token = matches[1]

    user = User.find_by_authentication_token(token)

    if user
      if !user.confirmed?
        user.errors.add(:base, I18n.t('devise.failure.unconfirmed'))
      else
        sign_in user, store: false
      end
    end

    user
  end

feel free to poke around here if you want to know more about my setup: https://github.com/NullVoxPopuli/aeonvera/

@bf4
Copy link
Member

bf4 commented Apr 6, 2016

@JamesChevalier What's ActiveModel::Serializer::Null?

Also, devise isn't very friendly to APIs. :(

@bf4
Copy link
Member

bf4 commented Apr 6, 2016

Ok, apparently I introduced that serializer in ec5dc49

But that's a logging concern.. weird

@JamesChevalier
Copy link
Author

In the second block of code within the 'Expected behavior vs actual behavior' section, this is in the log output:

[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.14ms)

I can agree with you on the devise/API note. This devise_token_auth gem that I'm using is supposed to help with that, but - obviously - things aren't going very well. :-P

What's odd is that everything works great while using active_model_serializers v0.10.0.rc4

@NullVoxPopuli
Copy link
Contributor

@JamesChevalier for what it's worth, I'm using master, if you want to borrow my code. :-)

@groyoh
Copy link
Member

groyoh commented Apr 8, 2016

@JamesChevalier What's ActiveModel::Serializer::Null?
Ok, apparently I introduced that serializer in ec5dc49

@bf4 you're the best 😂

@NullVoxPopuli
Copy link
Contributor

@JamesChevalier what's the status on this?

@JamesChevalier
Copy link
Author

@NullVoxPopuli Nothing has changed on my end & I haven't received a response to the Issue that I filed with devise_token_auth.

I appreciate you sharing your code with me, but (and hopefully I'm not misunderstanding this) I'm pretty tied in to using devise_token_auth at this point & can't take the time to rewrite my authentication strategy.

@bf4
Copy link
Member

bf4 commented Apr 11, 2016

@JamesChevalier My guess is that it's a change in how the serialization_context or serialization_scope are being used. I see in the source code some instance variable stuff which boils down to:

 client_name = DeviseTokenAuth.headers_names[:'client']
 @client_id = request.headers[client_name] || params[client_name]

Maybe you can paste that somewhere or use that to debug?

refs:

Or maybe it's this insane line:

https://github.com/lynndylanhurley/devise_token_auth/blob/15bf7857eca2d33602c7a9cb9d08db8a160f8ab8/app/controllers/devise_token_auth/application_controller.rb#L36-L38

    def is_json_api
      return false unless defined?(ActiveModel::Serializer)
      return ActiveModel::Serializer.config.adapter == :json_api
    end

@JamesChevalier
Copy link
Author

Thanks for the detective work, @bf4 ! Their code on master isn't what's in their latest gem, though. :-/

This is their released version. The released version of your first reference doesn't use DeviseTokenAuth.headers_names[:'client']. I'm not sure that this matters, though, because this isn't how sign_in works - the email and password are sent & client, uid, and access-token are returned - so I would not expect these params to exist yet in this scenario.

The problem is that the @client_id is un-set at a point in the sign in process.

It looks like @client_id is being set here. I was able to walk through that action & find that the @client_id is correctly set until after the render_create_success line (after which it is set to 'default').

After a bit of research, I've found that the sign_up flow goes like this:

  1. create in sessions_controller
  2. render_create_success in sessions_controller
  3. token_validation_response in user model
  4. update_auth_header in set_user_by_token

When using ASM v0.10.0.rc4, the @client_id is correctly set the entire way through. I verified this by putting logger lines as first/last lines of methods in that list above.

When using ASM v0.10.0.rc5, the @client_id is correctly set until after this render line gets called. I verified this by putting a logger as the last line in the render_create_success method, and seeing it display 'default' instead of the actual value.

The only thing that I have to point to is that self.as_json line in the token_validation_response method. Based on my research & tests so far, it looks like the two versions of ASM behave differently when that line is called. Now I'm about to dive in to see if I can find out what that is...

@bf4
Copy link
Member

bf4 commented Apr 12, 2016

If you clone ams into a local dir and set that as the path in the gemfile, you can run a git bisect on ams and check for the failure at each commit... Might help

@beauby
Copy link
Contributor

beauby commented Apr 20, 2016

The failing line in devise_token_auth is expiry = self.tokens because the self.tokens is nil. Can you confirm the bug arises for AMS 0.10.0rc5, not for AMS 0.10.0rc4, and for the same version of devise_token_auth?
Edit: disregard above comment, hadn't read the whole thread.

@JamesChevalier
Copy link
Author

The released version of 0.10.0 does not resolve this issue.

@NullVoxPopuli
Copy link
Contributor

@JamesChevalier, please take a look at this repo: https://github.com/NullVoxPopuli/aeonvera
specifically: https://github.com/NullVoxPopuli/aeonvera/tree/master/app/controllers/api/users

I have AMS + super basic token auth working with devise.

@JamesChevalier
Copy link
Author

Thanks, @NullVoxPopuli but the issue is between active_model_serializers & devise_token_auth.

@NullVoxPopuli
Copy link
Contributor

Do you need devise_token_auth? Devise token auth doesn't provide much and it seems like it's just preventing you from upgrading AMS

@bf4
Copy link
Member

bf4 commented May 18, 2016

I'm not sure what else we can do-- we've all put time into it-- without prioritizing this over features or performance or bugs with failing testa

B mobile phone

On May 18, 2016, at 8:43 AM, L. Preston Sego III notifications@github.com wrote:

Do you need devise_token_auth? Devise token auth doesn't provide much and it seems like it's just preventing you from upgrading AMS


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub

@JamesChevalier
Copy link
Author

I have another update... The short version is that this actually is working as expected with the latest 0.10.0 version.

The longer version is:

I read back through the issue, and I was reminded that there's unreleased devise_token_auth code. I decided to try out the latest AMS against different DTA git refs to see if I could get a functional environment that way...

I tried the latest commit first, and that succeeded. Since that worked so quickly, I decided I could spend a few minutes trying to pin down which commit fixed things. I tried a number of versions by specifying different refs in the Gemfile, and I couldn't get it to fail again - going all the way back to the released commit.

So, I'm guessing that there was something wrong with my initial test of active_model_serializers v0.10.0 which was cleared up in subsequent tests along the way. As of now, this is working. Here are the versions in use for this functional environment:

  • active_model_serializers (0.10.0)
  • devise (4.0.3)
  • devise_token_auth (0.1.37)

Sorry for the trouble this morning & thanks for all your help along the way!

@NullVoxPopuli
Copy link
Contributor

glad it works now!!! yay!!! 💯

@bf4
Copy link
Member

bf4 commented May 18, 2016

So much awesome that you shared this back!

B mobile phone

On May 18, 2016, at 9:24 AM, James Chevalier notifications@github.com wrote:

I have another update... The short version is that this actually is working as expected with the latest 0.10.0 version.

The longer version is:

I read back through the issue, and I was reminded that there's unreleased devise_token_auth code. I decided to try out the latest AMS against different DTA git refs to see if I could get a functional environment that way...

I tried the latest commit first, and that succeeded. Since that worked so quickly, I decided I could spend a few minutes trying to pin down which commit fixed things. I tried a number of versions by specifying different refs in the Gemfile, and I couldn't get it to fail again - going all the way back to the released commit.

So, I'm guessing that there was something wrong with my initial test of active_model_serializers v0.10.0 which was cleared up in subsequent tests along the way. As of now, this is working. Here are the versions in use for this functional environment:

active_model_serializers (0.10.0)
devise (4.0.3)
devise_token_auth (0.1.37)
Sorry for the trouble this morning & thanks for all your help along the way!


You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub

@JamesChevalier
Copy link
Author

I spoke too soon. With active_model_serializers version 0.10.0, the API response body is correct but the headers lack the access-token and have an incorrect client value.

The only other difference that I've spotted so far is that v0.10.0 includes [active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.29ms) in the Rails log, and 0.10.0.rc4 does not. This does not seem to be of any consequence to the response body, though.

The headers are allowed:

Access-Control-Expose-Headers: access-token, expiry, token-type, uid, client

headers for a successful signin request

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
access-token: Ge5GECWjOJ2yPMbtyVCwWj
token-type: Bearer
client: -s_IOgzIlrBEHXQaLi6bip
expiry: 1464796126
uid: person@domain.com
Content-Type: application/json; charset=utf-8
Cache-Control: no-store, must-revalidate, private, max-age=0
X-Request-Id: 2b726u1d-1105-4g59-840g-9ej03e123769
X-Runtime: 0.344088
Access-Control-Allow-Origin: http://127.0.0.1:8080
Access-Control-Allow-Methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
Access-Control-Expose-Headers: access-token, expiry, token-type, uid, client
Access-Control-Max-Age: 1728000
Access-Control-Allow-Credentials: true
Vary: Origin
X-MiniProfiler-Ids: ["l0omufwcolearmecaf1d","yv3ryhiy10013kcot2hq","kqwhy2kn4ukr5th70708","y2ldl9u8ol0srzbrr3m5","ymw9d8fhq7jrb4xz63ni","4qopmbn0c8invivqrs6l","mhec2hye8m8zbqlcdrq5","fzxwko8ufjwxeusf69gu","nbuswnusuu801jtklhy6","9q9lengeyugwz63pvnh7","5pmibt5jzy5uubr3gmfx","wz78cgygat50qfselhsi","a80v42x7ivf0wc8yj1fg","bi9y9xo1e7qz318a9eab","vpe4qp2vax5hm6gtvsjt","193k3dyh2dvq0oefj0kq","mu0bl4b87djnutg0nymm","era8cbby2yv8zscbe0so","ttqkw0osxcb1v39nl053","4xha7g9im9bdun98vtx8"]
Set-Cookie: __profilin=p%3Dt; path=/
Connection: close
Server: thin

headers for a failed signin request

HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
token-type: Bearer
client: default
expiry: 1464789869
uid: person@domain.com
Content-Type: application/json; charset=utf-8
Cache-Control: no-store, must-revalidate, private, max-age=0
X-Request-Id: 0cce6213-e4b3-43h0-81w9-c066301b29d4
X-Runtime: 0.342584
Access-Control-Allow-Origin: http://127.0.0.1:8080
Access-Control-Allow-Methods: DELETE, GET, OPTIONS, PATCH, POST, PUT
Access-Control-Expose-Headers: access-token, expiry, token-type, uid, client
Access-Control-Max-Age: 1728000
Access-Control-Allow-Credentials: true
Vary: Origin
X-MiniProfiler-Ids: ["yv3ryhiy10013kcot2hq","kqwhy2kn4ukr5th70708","y2ldl9u8ol0srzbrr3m5","ymw9d8fhq7jrb4xz63ni","4qopmbn0c8invivqrs6l","mhec2hye8m8zbqlcdrq5","fzxwko8ufjwxeusf69gu","nbuswnusuu801jtklhy6","9q9lengeyugwz63pvnh7","5pmibt5jzy5uubr3gmfx","wz78cgygat50qfselhsi","a80v42x7ivf0wc8yj1fg","bi9y9xo1e7qz318a9eab","vpe4qp2vax5hm6gtvsjt","193k3dyh2dvq0oefj0kq","mu0bl4b87djnutg0nymm","era8cbby2yv8zscbe0so","ttqkw0osxcb1v39nl053","4xha7g9im9bdun98vtx8","7pesyrq3surtsdhnghpa"]
Set-Cookie: __profilin=p%3Dt; path=/
Connection: close
Server: thin

I'm not sure that this new discovery warrants reopening the issue, though. The API request into devise_token_auth's space only includes email & password parameters. The rest is up to DTA, and that's where the client and access-token problems are occurring. As far as I'm aware, active_model_serializers doesn't play around in the headers, so it seems out of scope for this project.

I just wanted to pass along the details here, in case anyone has the same problem & comes across this issue in their initial debugging process...

@NullVoxPopuli
Copy link
Contributor

are you wanting the access token to be included in every response? or every request?
for token auth, you don't need to return tokens in the headers (they are only needed in requests)

@JamesChevalier
Copy link
Author

JamesChevalier commented May 18, 2016

Yeah access-token, client, expiry, token-type, and uid are all sent back & forth in each request/response (well, expiry, token-type are only sent in responses).

There are two places in the docs that mention this behavior:

  • The Token Header Format section includes a line, "The authentication headers required for each request will be available in the response from the previous request."
  • The About Token Management section discusses their suggested setup where tokens are constantly invalidated. "During each request, a new token is generated. The access-token header that should be used in the next request is returned in the access-token header of the response to the previous request."

@NullVoxPopuli
Copy link
Contributor

have you thought about using JWT? it sounds like you may want to use that? along with knock? https://github.com/nsarno/knock

@mustela
Copy link

mustela commented Jun 3, 2016

Having exactly the same issue. I had to downgrade AMS to 0.10.0.rc4

@bf4
Copy link
Member

bf4 commented Jun 3, 2016

@mustela I believe this is resolved #1667 (comment)

@bf4
Copy link
Member

bf4 commented Jun 3, 2016

It may also be worth keeping in mind that https://github.com/lynndylanhurley/devise_token_auth is regularly having issues with AMS due the gem's design... might be worth considering improving the code there or using different gem

@NullVoxPopuli
Copy link
Contributor

it's much easier to write your own token auth (As I have pasted in an earlier comment). It's easier to understand, customize, and upgrade.

@JamesChevalier
Copy link
Author

FYI, for anyone who ends up here on this issue:
I just updated devise_token_auth to version 0.1.38 and active_model_serializers to 0.10.2 and it looks like things are working out OK!

@alfmatos
Copy link

@JamesChevalier Any configuration options required? I've got a ng-token-auth authenticating with devise_token_auth, and it always gives:

Unpermitted parameter: session
Unpermitted parameter: session
[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (1.29ms)
   (0.1ms)  begin transaction
  User Load (0.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = ? LIMIT ?   [["id", 1], ["LIMIT", 1]]
   (0.9ms)  commit transaction
Completed 401 Unauthorized in 166ms (Views: 2.4ms | ActiveRecord: 1.6ms)

@bf4
Copy link
Member

bf4 commented Aug 10, 2016

@alfmatos Rendered ActiveModel::Serializer::Null with Hash makes it look like your trying to serialize a hash, which usually is from trying to use a serializer directly

@alfmatos
Copy link

@bf4 It seems I was getting a hash whenever the credentials failed (invalid). It created an empty session object and tried to serialise that. Not sure if that's an expected behaviour.

This was related wit ng_token_auth requests from angular not coming though as json (not sure why) and processed as HTML. I managed to track this down with curl. The response (for a request with proper Content-Type set to application/json, gave me the proper error message.

My problem was having confirmable active. When I added the confirmed_at, it started working. Since then I've added a namespace defaulting to json to make sure it processes the requests correctly:

namespace :api, defaults: {format: 'json'} do
      mount_devise_token_auth_for 'User', at: 'auth'
  end

@HOllarves
Copy link

I was having a similar issue and after many tweaks I found the problem that was affecting my project.

Just like many of you have said, my response headers didn't have the access-token and client

The server was rolling back the transaction because a required attribute was missing. After I sort that out, everything worked as expected. I felt kind of stupid after realizing it was such a minor thing.

Currently using:
Using active_model_serializers 0.10.2
Using devise 4.2.0
Using devise_token_auth 0.1.39

@betoharres
Copy link

betoharres commented Aug 12, 2017

Did anyone experienced that the API completely hangs util the request timeout after adding AMS in a project with devise_token_auth?
My api was working just fine before adding the gem.
Not sure what happened yet, but I'm using the latest versions from rubygem.

devise (4.3.0)
devise_token_auth (0.1.42)
active_model_serializers (0.10.6)

@bf4
Copy link
Member

bf4 commented Aug 13, 2017 via email

@betoharres
Copy link

@bf4 yeah I downgraded AMS to 0.10.0.rc4 and looks like it's working now, but in a near future I'm going to make my own auth library.

I realized that after started using redux-auth( the React frontend library that deals with authentication for devise_token_auth from the same author ). I had to rewrite the entire library, it felt like it was wrote in a rush with a lot of holes in the code. Also, few weeks ago this library started crashing at startup after updating dependencies( if you remove redux-auth the app comes back ).

I'm not saying the author is a bad coder, I'm just warning future adopters to consider this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

9 participants