I have a Rails 6.1 app using devise 4.7.1, doorkeeper 5.5.1, and devise-doorkeeper 1.2.0.
I'm trying to run through a (PKCE) OAuth flow, but the final step -- a POST request to /oauth/token
-- returns a 401 Unauthorized error with the JSON content {"error": "You need to sign in or sign up before continuing."}
.
I'm confused about this, since the /oauth/token
endpoint should be accessible to unauthenticated users as far as I understand. What's also weird (but perhaps a red herring) is that if I attempt to run the same POST request with curl, but remove the User-Agent header, it succeeds.
My current suspect is this block of code in initializers/doorkeeper.rb
:
resource_owner_authenticator do
current_user || warden.authenticate!(scope: :user)
end
This comes from the Doorkeeper docs. By stepping through the code, I can see that it's the call to warden.authenticate!
that returns a 401 error. Doorkeeper's TokensController#create
is never called.
Is there any important step I'm missing that allows unauthenticated access to this TokensController#create
endpoint?
This problem was caused by our use of the Ahoy analytics library.
By default, this library tracks all page visits in your Rails app. It tries to get the current user using current_user || current_resource_owner
. Because current_user
was still nil when POSTing to /oauth/token
, getting current_resource_owner
ended up calling our Doorkeeper resource_owner_authenticator
, which returned the 401 error. The source code for this is here.
This also explains why things worked as expected when unsetting the User-Agent
header: with no user agent (or the user agent of e.g. curl), Ahoy treats the request as coming from a bot, and doesn't attempt to track it (source code here).
Our solution to this is to tell Ahoy to stop tracking all page views automatically by setting Ahoy.api_only = true
in its configuration.