Search code examples
ruby-on-railspostgresqlforeign-keysdoorkeeper

Doorkeeper Foreign Key Violation on Access Grants


I'm attempting to set up Doorkeeper to make my table Company own the Access and Grant tokens. I was following this guide, with the exception that I was using companies and not users as resource owners.

This is the error I'm getting after I accept the pre-authorization prompt and get sent to /oauth/authorize:

ERROR:  insert or update on table "oauth_access_grants" violates foreign key constraint "fk_rails_330c32d8d9"
DETAIL:  Key (resource_owner_id)=(2) is not present in table "companies".

My schema:

add_foreign_key "oauth_access_grants", "companies", column: "resource_owner_id"
add_foreign_key "oauth_access_tokens", "companies", column: "resource_owner_id"

And the association in my Company model:

has_many :access_grants, class_name: 'Doorkeeper::AccessGrant', foreign_key: :resource_owner_id, dependent: :destroy
has_many :access_tokens, class_name: 'Doorkeeper::AccessToken', foreign_key: :resource_owner_id, dependent: :destroy

I've also made sure to nuke the database (db:reset) and rerun migrations (db:migrate:reset). I'm pretty confused at this point. Any thoughts as to what I could be missing?

If it helps, I'm using Rails 5.2.3, Doorkeeper 5.1.0, and PostgreSQL 9.6.5.


Solution

  • Aha, looks like I just needed to rubber duck it. The foreign key constraint was violated because I was attempting to assign my User's ID to it, when it was looking for a Company ID (and it just so happened that a Company with that ID didn't exist). The answer was to update the resource_owner_authenticator block in my Doorkeeper configuration.

    It would typically look something like this:

    resource_owner_authenticator do
      User.find_by_id(session[:user_id]) || redirect_to(new_session_url)
    end
    

    But because I am not assigning a User as the resource owner I needed to modify that. In my case I know a user belongs to one Company, so the updated block looks like:

    resource_owner_authenticator do
      unless user = User.find_by_id(session[:user_id])
        redirect_to(new_session_url)
      end
    
      user.company
    end
    

    Hope this helps any future folks!