Core Platform Team/Initiative/OAuth2/Status-Call-2019-11-20

Concerns

edit
  • "Non-expiring access tokens"
    • Why are we setting non-expiring access tokens?
    • Isn't it better to not ask for user approval each time, but allow full authorization to pass on each request?
      • Brad: Isn't not asking for re-approval what refresh tokens are for? Also, phab:T71232 may be relevant, as silent re-auth was specifically not implemented previously.
  • "Misuse of OAuth2 scopes"
    • Standard OAuth2 behaviour is, that if the client application asks for certain scopes, the user will be presented with an authorization dialog for those requested scopes only (even if the app is registered in a way that it can request more scopes).
    • For example, there can be an app that is registered with "editpages" grant.
      • The user is ok with the client being able to authenticate her/him on a different website.
      • The user is not ok with the client being able to make edits in her/his name.
    • With OAuth2 scopes, the app can just ask for authentication approval, so the user can use that feature without allowing edits by the client.
      • If the app, in the future wants to actually do edits, it can request that scope as well, where user will be able to see the approval dialog again, and deny and approve the request.
      • Even if editing is denied, user can still use the client for basic authentication.
      • It does not make sense to ask the user to approve full set of grants (=OAuth2 scopes) that application is registered with, regardless of what client actually requested, or even if it did not request anything ("empty scopes"). That way we are just disregarding "scope" param and going around it.
    • Brad: I'm not clear on where the problem is here, everything stated above seems completely correct to me. The only issue I raised in code review is when the client doesn't include the scope parameter. The implementation was (in PS14) interpreting that as the same as specifying scope with an empty value, while I'd find it more expected to treat that as a request to authorize the full set of registered scopes.
  • "REST versus Specialpage":
    • The REST API is the future of MediaWiki Web APIs
      • Brad: It's one of multiple APIs intended for the future, as far as I know. (Evan: me too.) But that's beside the point.
    • With moving to REST, all the logic should be contained within its handlers, and it should be dispatching requests to appropriate specialpages as needed. For login and client approval.
    • Spliting some of that logic to "Special:MWOAuth" would only help with redirecting from "Special:UserLogin", since its a valid "Title" object. But by this REST would lose its integrity as a separate unit.
      • Brad: The point is that end-user interaction via a browser typically happens via special pages, not via API endpoints which are intended for programmatic interaction instead. The current implementation does "REST → Special:UserLogin → hacky hook to redirect back to REST → Special:OAuth/approve → REST → client". I'd like to avoid the hacky hook by redirecting to Special:OAuth.
      • Decision: We're going to do like "REST → Special:UserLogin → Special:OAuth/returnFromLogin → REST → Special:OAuth/approve → REST → client". That keeps the OAuth 2 logic inside the REST handler and avoids using the hook that would have to be run on every login trying to catch this special case.
  • "Recurring approvals"
    • Why should it be necessary to ask user for application approval each time an application makes a request?
      • Brad: It's not, as long as the client still has a valid access token or refresh token. If the client does not have the token anymore (perhaps it was uninstalled then reinstalled?), why shouldn't the user re-approve it?
    • In OAuth2, approval would be presented to user only if client app is making the request for the first time and user had not approved it yet. Or if it requests scopes that were not present in original approval (= asking for additional permissions).
    • It was probably set up that way, because the access tokens do not expire, so a user would be asked to re-approve only if client explicitly asks for new token or user "renounces" the access. But this feels like we are forcing (at least OAuth2) to provide a workflow that it was not designed for.

Issues

edit
  • Binding access tokens to user approvals ("acceptances")
    • How do we deal with grants that do not require user approval (like client_credentials)?
    • Do we mock the approval? If yes, that approval would be valid also for "authentication_code" grant, since there is no grant designation in the database table.
      • Dejan: I have given this some tought. Technically we could make "acceptance_id" optional, so that only if acceptance is present we add it to the "access_token". Presence of "acceptance_id" does not affect access token validity or security. It is used only to get the acceptance from the access token identifier and to remove access tokens when user revokes the client approval.
    • Brad: For an owner-only consumer (oarc_owner_only != 0), it should use the existing approval for the owner (typically created at registration time). For a non-owner-only consumer, I see two possible options: (1) Return an error, or (2) return an "approval" that maps to a User with ID 0 (at the database level, what Dejan said sounds ok to me). If we're going to continue with Evan's plan to (ab)use OAuth 2 client IDs as API keys, we'll probably need option 2.
  • Providing available scope names to the consumer
    • In OAuth(1), clients (= consumers) do not explicitly request specific grants in the request. Therefore there is no need for consumers to know what are the grants actually called.
    • In OAuth2, clients should be able to request a set of scopes. But there is no way for them to know the names of the available scopes.
    • Figuring out those names was difficult even with access to and knowledge of the code
      • Brad: At the code level, ScopeRepository has the list. Exposing that list via a REST endpoint like /oauth2/resource/scopes would seem valid. We might also adjust the dialogs like Special:OAuthConsumerRegistration/propose to include the scope name in addition to the human-readable description, and the management pages under Special:OAuthConsumerRegistration/list to list the registered scopes.
  • Purpose of "owner-only"
    • What should it be used for?
      • Brad: It's used to register a consumer that will only ever be used by one user account, typically a bot where there's no human to actually visit the authorization endpoint. Rather than using the normal authorization endpoint, the (never-expiring) access token is created and returned at registration time. For OAuth 2, we might instead or in addition allow the client_credentials flow to be used.