Using Resource Owner Password Credentials flow

Marvin Marcelo edited this page Dec 14, 2016 · 13 revisions

NOTE: See this issue in case this implementation is buggy: https://github.com/doorkeeper-gem/doorkeeper/issues/475#issuecomment-107501342.

In this flow, a token is requested in exchange for the resource owner credentials (username and password):

Configuration

To use this flow you first have to tell doorkeeper how to authenticate the resource owner with username/password:

Doorkeeper.configure do
  resource_owner_from_credentials do |routes|
    User.authenticate!(params[:username], params[:password])
  end
end

For Doorkeeper 2.1+, you'll need to add password as an acceptable grant type. In your initializer after the Doorkeeper.configure block, add:

Doorkeeper.configuration.token_grant_types << "password"

Newer versions of devise don't provide the authenticate! method anymore, and you can use:

Doorkeeper.configure do
  resource_owner_from_credentials do |routes|
    user = User.find_for_database_authentication(:email => params[:email])
    if user && user.valid_for_authentication? { user.valid_password?(params[:password]) }
      user
    end
  end
end

Alternatively, you can also run the authentication through warden. This requires some trickery though:

Doorkeeper.configure do
  resource_owner_from_credentials do |routes|
    request.params[:user] = {:email => request.params[:username], :password => request.params[:password]}
    request.env["warden"].logout(:user)
    request.env["devise.allow_params_authentication"] = true
    request.env["warden"].authenticate!(:scope => :user)
  end
end

Testing

For testing you can use the oauth2 ruby gem:

client = OAuth2::Client.new('the_client_id', 'the_client_secret', :site => "http://example.com")
access_token = client.password.get_token('user@example.com', 'sekret')
puts access_token.token

NOTE: this syntax might be old, password grant flow doesn't need client credentials. See https://github.com/doorkeeper-gem/doorkeeper/issues/561.

That will make a POST request to the OAuth providers /oauth/token endpoint, with the params:

{
  "grant_type"    : "password",
  "username"      : "user@example.com",
  "password"      : "sekret"
}

Then, you'll receive the access token back in the response:

{
  "access_token": "1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa",
  "token_type": "bearer",
  "expires_in": 7200
}

Links: