Doorkeeper: Using doorkeeper with rails-api

Created on 23 Mar 2018  Â·  22Comments  Â·  Source: doorkeeper-gem/doorkeeper

Hi.
I'm trying to setup doorkeeper to work with rails-api only application and getting when trying to authenticate

NameError: uninitialized constant AccessToken
doorkeeper-4.3.1/lib/doorkeeper/oauth/token.rb:15:in `authenticate'

```
doorkeeper (4.3.1)
rails (5.1.5)

I want to use doorkeeper in this application only for the purpose of request authentication and it is connected to the same database which is the other application (which is OAuth provider) is using.
So basically there are 2 rails applications: one is regular rails app (OAuth provider) and the other one is just API consuming same database.
```ruby
module Api
  module V1
    class ApiController < ActionController::API #:nodoc:
      before_action :doorkeeper_authorize!

      def current_resource_owner
        User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
      end
    end
  end
end

Maybe there is some additional setup needed in order to make it work with rails-api or some middlewares are missing. Thanks for the help in advance!

bug?

Most helpful comment

Try to touch ActiveRecord::Base in the end of Doorkeeper initilizer like this: puts ActiveRecord::Base.inspect

I'm wondering if it is connected with lazy models loading..

All 22 comments

We have some support for Rails 5 API mode in master (it is not released yet). Maybe you can check it (just enable api_only option in configuration)? Also, can you please provide your Doorkeeper initializer and full error backtrace?

Thanks for jumping in, @nbulaj.
No luck with master branch as well.
Since I'm not using this app as OAuth provider, doorkeeper configuration is pretty slim:

Doorkeeper.configure do
  orm :active_record
  api_only
end

Setting base_controller 'ActionController::API' also didn't helped.


Error backtrace

Started GET "/api/v1/contacts" for 127.0.0.1 at 2018-03-23 18:38:56 +0100
Processing by Api::V1::ContactsController#index as JSON
Completed 500 Internal Server Error in 438ms



NameError (uninitialized constant AccessToken):

/home/denis/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/bundler/gems/doorkeeper-e8474c48bc35/lib/doorkeeper/oauth/token.rb:15:in `authenticate'
/home/denis/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/bundler/gems/doorkeeper-e8474c48bc35/lib/doorkeeper/rails/helpers.rb:71:in `doorkeeper_token'
/home/denis/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/bundler/gems/doorkeeper-e8474c48bc35/lib/doorkeeper/rails/helpers.rb:17:in `valid_doorkeeper_token?'
/home/denis/.rbenv/versions/2.5.0/lib/ruby/gems/2.5.0/bundler/gems/doorkeeper-e8474c48bc35/lib/doorkeeper/rails/helpers.rb:7:in `doorkeeper_authorize!'
activesupport (5.1.5) lib/active_support/callbacks.rb:413:in `block in make_lambda'
activesupport (5.1.5) lib/active_support/callbacks.rb:197:in `block (2 levels) in halting'
actionpack (5.1.5) lib/abstract_controller/callbacks.rb:12:in `block (2 levels) in <module:Callbacks>'
activesupport (5.1.5) lib/active_support/callbacks.rb:198:in `block in halting'
activesupport (5.1.5) lib/active_support/callbacks.rb:507:in `block in invoke_before'
activesupport (5.1.5) lib/active_support/callbacks.rb:507:in `each'
activesupport (5.1.5) lib/active_support/callbacks.rb:507:in `invoke_before'
activesupport (5.1.5) lib/active_support/callbacks.rb:130:in `run_callbacks'
actionpack (5.1.5) lib/abstract_controller/callbacks.rb:19:in `process_action'
actionpack (5.1.5) lib/action_controller/metal/rescue.rb:20:in `process_action'
actionpack (5.1.5) lib/action_controller/metal/instrumentation.rb:32:in `block in process_action'
activesupport (5.1.5) lib/active_support/notifications.rb:166:in `block in instrument'
activesupport (5.1.5) lib/active_support/notifications/instrumenter.rb:21:in `instrument'
activesupport (5.1.5) lib/active_support/notifications.rb:166:in `instrument'
actionpack (5.1.5) lib/action_controller/metal/instrumentation.rb:30:in `process_action'
actionpack (5.1.5) lib/action_controller/metal/params_wrapper.rb:252:in `process_action'
activerecord (5.1.5) lib/active_record/railties/controller_runtime.rb:22:in `process_action'
actionpack (5.1.5) lib/abstract_controller/base.rb:124:in `process'
actionview (5.1.5) lib/action_view/rendering.rb:30:in `process'
actionpack (5.1.5) lib/action_controller/metal.rb:189:in `dispatch'
actionpack (5.1.5) lib/action_controller/metal.rb:253:in `dispatch'
actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:31:in `serve'
actionpack (5.1.5) lib/action_dispatch/journey/router.rb:50:in `block in serve'
actionpack (5.1.5) lib/action_dispatch/journey/router.rb:33:in `each'
actionpack (5.1.5) lib/action_dispatch/journey/router.rb:33:in `serve'
actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:844:in `call'
rack (2.0.4) lib/rack/etag.rb:25:in `call'
rack (2.0.4) lib/rack/conditional_get.rb:25:in `call'
rack (2.0.4) lib/rack/head.rb:12:in `call'
activerecord (5.1.5) lib/active_record/migration.rb:556:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/callbacks.rb:26:in `block in call'
activesupport (5.1.5) lib/active_support/callbacks.rb:97:in `run_callbacks'
actionpack (5.1.5) lib/action_dispatch/middleware/callbacks.rb:24:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/debug_exceptions.rb:59:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
railties (5.1.5) lib/rails/rack/logger.rb:36:in `call_app'
railties (5.1.5) lib/rails/rack/logger.rb:24:in `block in call'
activesupport (5.1.5) lib/active_support/tagged_logging.rb:69:in `block in tagged'
activesupport (5.1.5) lib/active_support/tagged_logging.rb:26:in `tagged'
activesupport (5.1.5) lib/active_support/tagged_logging.rb:69:in `tagged'
railties (5.1.5) lib/rails/rack/logger.rb:24:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/remote_ip.rb:79:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/request_id.rb:25:in `call'
rack (2.0.4) lib/rack/runtime.rb:22:in `call'
activesupport (5.1.5) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/executor.rb:12:in `call'
actionpack (5.1.5) lib/action_dispatch/middleware/static.rb:125:in `call'
rack (2.0.4) lib/rack/sendfile.rb:111:in `call'
railties (5.1.5) lib/rails/engine.rb:522:in `call'
puma (3.11.3) lib/puma/configuration.rb:225:in `call'
puma (3.11.3) lib/puma/server.rb:624:in `handle_request'
puma (3.11.3) lib/puma/server.rb:438:in `process_client'
puma (3.11.3) lib/puma/server.rb:302:in `block in run'
puma (3.11.3) lib/puma/thread_pool.rb:120:in `block in spawn_thread'

Try to touch ActiveRecord::Base in the end of Doorkeeper initilizer like this: puts ActiveRecord::Base.inspect

I'm wondering if it is connected with lazy models loading..

You da man! Worked like charm. Is it ok to just leave the line above in doorkeeper initializer or it is better to touch ActiveRecord::Base somewhere else?

Hmm, it is really strange why AR wasn't loaded at the moment :/ Can you show you gemfile? (not .lock) Maybe you made some AR customizations?

No, touched nothing. It's fresh rails app.


Gemfile

# frozen_string_literal: true

source 'https://rubygems.org'

git_source(:github) do |repo_name|
  repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?('/')
  "https://github.com/#{repo_name}.git"
end

ruby File.read('.ruby-version').match(/\d\.\d.\d/)[0]

gem 'doorkeeper', git: 'https://github.com/doorkeeper-gem/doorkeeper.git', branch: 'master'
gem 'dotenv-rails'
gem 'iso_country_codes'
gem 'pg', '~> 0.18.4'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
gem 'rails', '~> 5.1.5'
# Use sqlite3 as the database for Active Record
gem 'sqlite3'
# Use Puma as the app server
gem 'puma', '~> 3.7'
# Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder
gem 'jbuilder', '~> 2.5'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin AJAX possible
# gem 'rack-cors'

group :development, :test do
  # Call 'byebug' anywhere in the code to stop execution and get a debugger console
  gem 'byebug', platforms: %i[mri mingw x64_mingw]
  gem 'factory_bot_rails', '~> 4.0'
  gem 'pry'
  gem 'rspec-rails'
end

group :development do
  gem 'listen', '>= 3.0.5', '< 3.2'
  gem 'overcommit', require: false
  gem 'rubocop', require: false
  # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
  gem 'spring'
  gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
  gem 'dox', require: false
end

# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]

It is silly, but can you try to set 'rails' as the first gem in the list? Before doorkeeper. And try without touching AR. Bundler loads gems as they defined, so maybe it is the problem..

Nope, that didn't help :/

Any plans on when the next release (with api_only included) will be? :heart: for this gem! :tada:

@milgner I think in early April we will release an RC version so you can try it

@mojobiri could you please provide some instruction on how to setup the app to get error problem? (maybe there are something special that I must know)

ok, I will.
Btw, it is only happening on the first request and only if Content-type is not set.
Means this fails the first time and works after.

curl \
--header "Authorization: Bearer token" \
--request GET \
http://localhost:3000/contacts

And this works from the beginning:

curl \
--header "Content-type: application/json" \
--header "Authorization: Bearer token" \
--request GET \
http://localhost:3000/contacts


Sample app to reproduce the issue

Rails 5.1.5

rails new doorkeeper-test --api
cd doorkeeper-test
echo -e "\ngem 'doorkeeper', git: 'https://github.com/doorkeeper-gem/doorkeeper.git', branch: 'master'" >> Gemfile
echo "gem 'dotenv-rails'" >> Gemfile
echo "gem 'pg', '~> 0.18.4'" >> Gemfile
bundle install

echo "Doorkeeper.configure do
  orm :active_record
  api_only
end" > config/initializers/doorkeeper.rb

echo "class ContactsController < ApiController
  def index
    render json: {}
  end
end" > app/controllers/contacts_controller.rb

echo "class ApiController < ActionController::API
  before_action :doorkeeper_authorize!
end" > app/controllers/api_controller.rb

echo "Rails.application.routes.draw do
  resources :contacts
end" > config/routes.rb

echo "2.5.0" >> .ruby-version
echo "DATABASE_URL=postgresql://postgres:postgres@localhost/DB_NAME" > .env.local

rails s


curl \
--header "Authorization: Bearer token" \
--request GET \
http://localhost:3000/contacts

I've made the sample app and done some extra steps (rails db:create , rails g doorkeeper:migration , rails db:migrate). And I've got:

Completed 401 Unauthorized in 25ms (ActiveRecord: 3.4ms)

And no problem:

Processing by ContactsController#index as /
Doorkeeper::AccessToken Load (0.5ms) SELECT "oauth_access_tokens".* FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = $1 LIMIT $2 [["token", "token"], ["LIMIT", 1]]

:thinking:

yeah, it is ok. I just have not standard setup because I'm connecting to an existing DB and the other app is OAuth provider. So I already have doorkeeper tables in the database and don't want to run any migrations in the second app.

Hm.. I don't know how to reproduce it... Maybe you can upload your project somewhere (without all the models / controllers / etc except Doorkeeper) ?

You should get an error with the setup I wrote above if you follow it without any additional setup you did (like rails g doorkeeper:migration and rails db:migrate)

You should get an error with the setup I wrote above if you follow it without any additional setup you did (like rails g doorkeeper:migration and rails db:migrate)

But it have no sense because I would not have valid DB tables. Ok, I will try tomorrow once again

the error occurs before it reaches DB-related errors )

the error occurs before it reaches DB-related errors )

Yep, I understand it, but in my case there are was database error, not NameError exception.

@mojobiri as I mentioned above:

Use Ctrl-C to stop
Started GET "/contacts" for 127.0.0.1 at 2018-04-02 11:41:52 +0300
Processing by ContactsController#index as /
Doorkeeper::AccessToken Load (2.7ms) SELECT "oauth_access_tokens".* FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = $1 LIMIT $2 [["token", "token"], ["LIMIT", 1]]
↳ /home/bulaj/.rvm/gems/ruby-2.4.1/bundler/gems/doorkeeper-ed95d941e584/lib/doorkeeper/models/access_token_mixin.rb:23
Doorkeeper::AccessToken Load (0.5ms) SELECT "oauth_access_tokens".* FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = $1 LIMIT $2 [["token", "token"], ["LIMIT", 1]]
↳ /home/bulaj/.rvm/gems/ruby-2.4.1/bundler/gems/doorkeeper-ed95d941e584/lib/doorkeeper/models/access_token_mixin.rb:23
Doorkeeper::AccessToken Load (0.6ms) SELECT "oauth_access_tokens".* FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = $1 LIMIT $2 [["token", "token"], ["LIMIT", 1]]
↳ /home/bulaj/.rvm/gems/ruby-2.4.1/bundler/gems/doorkeeper-ed95d941e584/lib/doorkeeper/models/access_token_mixin.rb:23
Doorkeeper::AccessToken Load (0.6ms) SELECT "oauth_access_tokens".* FROM "oauth_access_tokens" WHERE "oauth_access_tokens"."token" = $1 LIMIT $2 [["token", "token"], ["LIMIT", 1]]
↳ /home/bulaj/.rvm/gems/ruby-2.4.1/bundler/gems/doorkeeper-ed95d941e584/lib/doorkeeper/models/access_token_mixin.rb:23
Filter chain halted as :doorkeeper_authorize! rendered or redirected
Completed 401 Unauthorized in 165ms (ActiveRecord: 60.3ms)

So I just have 401 Unauthorized

I dropped database and got:

Started GET "/contacts" for 127.0.0.1 at 2018-04-02 11:45:16 +0300

ActiveRecord::NoDatabaseError (FATAL: database "DB_NAME" does not exist
):

activerecord (5.2.0.rc2) lib/active_record/connection_adapters/postgresql_adapter.rb:688:in rescue in connect' activerecord (5.2.0.rc2) lib/active_record/connection_adapters/postgresql_adapter.rb:684:inconnect'
activerecord (5.2.0.rc2) lib/active_record/connection_adapters/postgresql_adapter.rb:215:in initialize' activerecord (5.2.0.rc2) lib/active_record/connection_adapters/postgresql_adapter.rb:40:innew'

Any news here?

I have a non-standard setup and no one have issues with it. The workaround works for me. Let's close it.

Was this page helpful?
0 / 5 - 0 ratings