songkick / oauth2-provider

Simple OAuth 2.0 provider toolkit

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Password grant type does not accept scope param when there is no existing authorization

swishstache opened this issue · comments

When the resource owner has no existing authorization record and they attempt to get a token via the password grant (and scopes are specified), the Exchange class creates an authorization with a nil scope value and the following error is returned:

error = invalid_scope
error_description = The request scope was never granted by the user

A review of the code indicates this is likely an issue with the assertion type too.

I began to write a fix but then noticed line 182 in the exchange_spec.rb

https://github.com/songkick/oauth2-provider/blob/master/spec/oauth2/provider/exchange_spec.rb#L182

OAuth2::Provider.handle_passwords do |client, username, password|
  user = TestApp::User[username]
  if password == 'soldier'
    user.grant_access!(client, :scopes => ['foo', 'bar'])
  else
    nil
  end
end

handle_passwords and handle_assertions implementations don't have access to the scope in params. I couldn't find anything in the spec about not allowing one to specify scopes on password and assertion grant types. If they did, they could pass the given scope to grant_access!

Is this a legit bug or am I embarrassingly simple?

Legit bug, I think. I'm taking a look at it -- we should probably expose the requested scopes to the password/assertion handler.

This is partially fixed in fc90daa, by yielding the requested scopes to password and assertion handlers so that the user can grant them. There is an open question with the implementation though which I'd like your feedback.

The way the exchange handler works is that it first validates the client credentials. If valid, it then enters a validation path based on the grant_type. This phase is expected to somehow yield an Authorization (which is why password and assertion handlers must return one). Finally, the requested scopes, if present, are compared to the scopes on the Authorization, and if only a subset are authorized, the request results in an error.

This makes sense if grant_type=authorization_code: the authorized scopes were established by a previous request in which the scopes being requested are displayed to the user. If the client asks for a superset of these scopes in the exchange, it's reasonable to assume it's an error and reject the request.

However, in the password/assertion case, you basically have a 'cold start' where there is no pre-existing authorization. With the current implementation, the password block can authorize the user, but if it only authorizes a subset of the requested scopes, it's considered an error and no access token is released.

So, I'm not sure if I have a concrete question, would just like your thoughts, or close the issue if you're happy.

The issue (as I understand it) is that if we have an existing authorization, we can't extend the scopes of that authorization via a password or assertion grant type, right? It seems like there's a legitimate concern to address there -- I'll brew on some scenarios and how I'd expect them to play-out.

Your commit fixes the initial problem so, I'll close this issue.