w3c / webappsec-credential-management

WebAppSec Credential Management
https://w3c.github.io/webappsec-credential-management/
Other
50 stars 38 forks source link

CREDENTIAL: Credential scope should not be limited to login #8

Open mikewest opened 9 years ago

mikewest commented 9 years ago

From @dlongley on April 15, 2015 13:58

Credentials may be used for more than just login, and a credential may not represent a user's entire identity. This means that browsers can't just take a list of credentials and throw them up in a UI when someone is attempting to log into a website. It also means the API should support more complex queries for the types of credentials desired. This likely means redefining what a credential is -- and making changes to the Credential base class.

There are at least two ways to proceed:

  1. Consider some credentials to be "LoginCredentials" (or username+password legacy credentials) and others to be of a more generalized sort. The browser only bothers displaying "LoginCredentials" in a special way. Browsers can defer to IdPs for displaying non-LoginCredentials.
  2. Consider that all credentials are of a generalized sort, and browsers will have to inspect a variety of properties about them to determine how to best display them to users. Browsers could also simply defer to IdPs to handle specialized display.

In the Credentials CG work, we don't consider "login" to be a special use case. A relying party may ask for whatever credential they want to in order to authorize a user to take some action or to simply collect information about that user for later review, etc. For example, "login" can be implemented by requesting a "Verified Email Credential" from a user. It could be implemented in another way as well.

The current Credential Management API sees the "login use case" as a special first class citizen, which makes perfect sense, considering that it is scope-limited to making incremental improvements to "login" via a new imperative password manager API. I don't see any conflict with the Credentials CG in this respect.

The conflict arises from the fact that the spec aims to do more than just provide an API for password managers, it suggests there is "future work" and attempts to define an extensible API to try and cover it. Again, it makes perfect sense that you'd want such an API to support a broader range of credentials if it can. Fortunately, the Credentials CG has spent years working on designs and technologies in the "future work" space the Credentials Management API refers to. Unfortunately, the current design feels a bit inverted to those of us that have spent that time. I don't have a quick fix for this particular issue -- but it's clear to me that how we want credentials to work in the future doesn't quite mesh with the existing "login" paradigm.

Obviously, it would be nice to make a minimal number of changes to the API now to future proof it -- and then simply list these goals out in the future work section.

Copied from original issue: w3c/webappsec#256

mikewest commented 9 years ago

From @dlongley on April 15, 2015 14:43

One possible minimal change to future proof the API would be to make the Credential base class more generic and create a new LoginCredential class that extends it. That LoginCredential class is then the base class for LocalCredential and FederatedCredential. In the future, there would be something like LinkedDataCredential that extends Credential. Then, in order to select which path (legacy or future) you want to work with, you include that when making a call to navigator.credentials.get():

navigator.credentials.get({
  type: 'LoginCredential'
}).then(function(...) {
  // ...
});

Or:

navigator.credentials.get({
  type: 'LinkedDataCredential',
  query: {
    // linked data query here, format TBD in future work
  },
  callback: // callback to post identity document with credentials to from third party
});

In the first case, you essentially work with the present API as implemented. In the second case, the API doesn't return a promise, rather it posts the result of the credentials query from a third party to a callback. The browser itself may optionally function as that third party, but it also may not. The result will likely be a JSON-LD Linked Data identity document that contains credentials -- but this is to be decided as future work.

In short, it may be that the existing API can be future proofed for the Credentials CG and Web Payments IG use cases by redefining the meaning of Credential, changing the base class to be more generic, extending it with a LoginCredential class for the current password-manager use cases, and adding some notes to the spec in the future work section for how Linked Data credentials might be implemented.

mikewest commented 9 years ago

From @jmajnert on April 15, 2015 16:55

In the second case, the API doesn't return a promise, rather it posts the result of the credentials query from a third party to a callback.

Why not use promises? Is there some specific magic going on that requires callbacks?

In short, it may be that the existing API can be future proofed for the Credentials CG and Web Payments IG use cases by redefining the meaning of Credential, changing the base class to be more generic, extending it with a LoginCredential class for the current password-manager use cases, and adding some notes to the spec in the future work section for how Linked Data credentials might be implemented.

If that's all it takes, LGTM.

mikewest commented 9 years ago

From @dlongley on April 15, 2015 17:36

Why not use promises? Is there some specific magic going on that requires callbacks?

We have no issue with promises, it just seems like it may require complex state management by the browser in order to implement. We also want to ensure that this API is easily polyfillable. To elaborate, the future flow is currently envisioned to work like this (at a high level):

  1. Relying party requests a set of credentials by passing a query to the API.
  2. The browser doesn't have the credentials cached, so it redirects the user to their IdP. Note: the user has left the relying party's website at this point.
  3. With the user's authorization, the IdP uses another API call to pass the credentials that match the query back to the browser. Note: a polyfill would POST them to a temporary trusted centralized website. In either case (browser or polyfill), the identity of the relying party is optionally hidden from the IdP during this step. This provides greater privacy assurances to users.
  4. The browser POSTs the credentials to the callback URL.

I don't see how this is easily implemented using promises, as the original page has been navigated away from and its state has been lost. It seems the page state would need to be saved by the browser -- or another window could be used to visit the IdP -- in order for a promise-based approach to work. Thoughts?