-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Using Resource Owner Password Credentials flow
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):
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, make sure password
is part of your grant_flows
so you have at least (you can have others):
grant_flows %w[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[:username])
if user&.valid_for_authentication? { user.valid_password?(params[:password]) } && user&.active_for_authentication?
request.env['warden'].set_user(user, scope: :user, store: false)
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
# Set `store: false` to stop Warden from storing user in session
# https://github.com/doorkeeper-gem/doorkeeper/issues/475#issuecomment-305517549
request.env["warden"].authenticate!(scope: :user, store: false)
end
end
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('[email protected]', 'sekret')
puts access_token.token
That will make a POST request to the OAuth providers /oauth/token
endpoint, with the params:
{
"client_id": "the_client_id",
"client_secret": "the_client_secret",
"grant_type": "password",
"username": "[email protected]",
"password": "sekret"
}
Then, you'll receive the access token back in the response:
{
"access_token": "1f0af717251950dbd4d73154fdf0a474a5c5119adad999683f5b450c460726aa",
"token_type": "bearer",
"expires_in": 7200
}
Links: