We are using Doorkeeper gem to authenticate our users through an API. Everything is working fine since we've implemented it few years ago, we are using the password
grant flow as in the example:
resource_owner_from_credentials do |_routes|
user = User.active.find_for_database_authentication(email: params[:username])
if user&.valid_password?(params[:password])
sign_in(user, force: true)
user
end
end
Doorkeeper is coupled with Devise, which enable reconfirmable
strategy. As you can see in the code above, we are only allowing active
users (a.k.a users with a confirmed email) to connect:
User.active.find_.....
Our specifications changed and now we want to return a different error on login (against /oauth/token
) depending if the user has confirmed its email or not.
Right now, if login fails, Doorkeeper is returning the following JSON:
{
"error": "invalid_grant",
"error_description": "The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client."
}
Ideally, we want to be able to return a custom description if and only if the current email trying to login is unconfirmed
We've checked the documentation on Doorkeeper but it does not seems to have an easy way (if any at all) to do this. The fact that resource_owner_from_credentials
method is located in the config adds too much magic and not enough flexibility.
Any ideas ?
Ok so after digging a little bit, we found an easy way to work around this issue by overriding Doorkeeper::TokensController
.
# frozen_string_literal: true
class TokensController < Doorkeeper::TokensController
before_action :check_if_account_is_pending, only: :create
private
def check_if_account_is_pending
user = User.find_by(email: params['username'])
render json: unconfirmed_account_error if user && !user.confirmed?
end
def unconfirmed_account_error
{ error: 'invalid', error_description: 'You must validate your email address before login' }
end
end
We also needed to make sure the routes were pointing to the custom controller:
use_doorkeeper do
controllers tokens: 'tokens'
end
Hope it can helps someone in the future