w3c-fedid / FedCM

A privacy preserving identity exchange Web API
https://w3c-fedid.github.io/FedCM/
Other
382 stars 73 forks source link

Returning users have to unnecessarily re-approve #429

Closed yi-gu closed 1 year ago

yi-gu commented 1 year ago

Currently, after a user has created a federated account on an RP with an IDP via the FedCM API, the next time they revisit the website they need to go through the same steps with the same UI affordances. i.e. they will need to explicitly and manually re-confirm to re-authenticate and proceed with the sign-in flow. This UX makes more sense before the user has created the federated account to prevent tracking, which is one of the main goals of FedCM API, but less so after the user has gone through it once: after the user grants permission to allow an RP-IDP communication, there’s no privacy or security benefit for enforcing another explicit user confirmation for something that they have already previously acknowledged.

We have heard from both RPs and IDPs that they would like the authentication experience to be more streamlined for users who have already created a federated account with them. In fact, there are already use cases on the web that are implemented with third-party cookies. From UA’s perspective, supporting re-authentication without explicit user confirmation can:

  1. reduce user friction without reducing privacy or security
  2. preserve existing deployments in a backwards compatible manner
  3. help RPs prevent cookie theft by keeping short lived cookies and relying on (highly sophisticated) IDPs to help them refresh the cookies
yi-gu commented 1 year ago

Updated on April 25: Proposal with Mediation Requirements

Credential Management API supports handing over credentials to API caller automatically when certain conditions are met. It's achieved by using the mediation requirements field. We believe that it fits well with the FedCM use case. i.e. the browser can help to reduce user friction at the re-authentication moment for RPs/IDPs without paying such security cost. In addition, since the new streamlined re-authn experience only applies to returning users who have granted permission for the RP-IDP communication in the past, we believe that this can be done without reducing privacy.

A quick overview of how the proposed “auto re-authn” works:

  1. Prerequisite: a user has already created an account on rp.example with idp.example in the browser, and has not cleared site data for either site
  2. When the user returns to rp.example, they may no longer have an active session with the RP. e.g. 1P session cookie expired
  3. If “auto re-authn” is available (see details below), instead of showing the explicit sign-in UI with the “Continue as” call-to-action button, the browser can automatically fetch the token from idp.example and return it to rp.example
  4. If successful, the user will be automatically re-authenticated into the RP. The browser can display some UI in the “auto re-authn” flow to give users some context of this feature.

Proposals

Auto re-authn is for “returning users” only. In addition, it’s gated by several other conditions. We define “Auto re-authn is available” if all the following are true

  1. An RP has opted in to auto re-authn AND
  2. Only one account is eligible for auto re-authn AND
  3. User has not explicitly signed out from RP AND
  4. User has not disabled auto re-authn in browser settings (if provided)

Auto re-authn flow overview

Mediation Requirements

In the initial launch of FedCM API, we did not include the mediation requirements field which is part of the upstream Credential Management API. One of the goals of “mediation requirements” is to automatically share credentials with the API caller when certain conditions are met. Given that it meets the product requirements of FedCM auto re-authn and it has been used by Password Credentials, we believe that implementing mediation requirements for auto re-authn could not only complete FedCM API but also ensure consistency across similar products.

An RP can specify that they’d like to use auto re-authn by using proper mediation requirements in the existing API:

const cred = await navigator.credentials.get({
    identity: {
        providers: [{
            configURL: "https://idp.example//fedcm.json",
            clientId: "1234",
        }],
    },
    mediation: 'required|optional|silent'
});

In particular:

Note: since the mediation requirements field is not supported in the current FedCM specification and the spec treats it as required, implementing the mediation requirement changes the default behavior of FedCM from required to optional.

preventSilentAccess

As mentioned in the Credential Management API specification,

The intent here is a signal from the origin that the user has signed out. That is, after a click on a "Sign out" button, the site updates the user’s session info, and calls navigator.credentials.preventSilentAccess(). This sets the prevent silent access flag, meaning that credentials will not be automagically handed back to the page next time the user visits.

By supporting preventSilentAccess, the browser can better respect the user's intent of “signing out of the website” by not re-authenticating them automatically.

Note that preventSilentAccess is an API that the browser exposes such that websites can provide the best UX with it. That said, it's up to the website to use it properly upon user signing out and the browser cannot enforce it.

Summary

When preventSilentAccess is not set for the RP mediation / selected credentials single match zero or multiple match
required Requires user mediation Requires user mediation
silent Skip user mediation Resolve promise with null / no prompt
optional Skip user mediation Requires user mediation
When preventSilentAccess is set for the RP mediation / selected credentials single match zero or multiple match
required Requires user mediation Requires user mediation
silent Requires use mediation Resolve promise with null / no prompt
optional Requires user mediation Requires user mediation

Privacy Consideration

The major difference between the existing authentication flow and the auto re-authn flow is that the latter does not require explicit user permission for authentication. However, an explicit user permission to allow the RP-IDP communication MUST have been granted in the browser in the past (e.g. the browser stores such permission locally after a previous FedCM grant). i.e. the new feature only works “post permission”.

From privacy’s perspective, this “post permission” feature does not introduce new privacy risks because an explicit user permission to allow RP-IDP communication has been granted in the browser in the past. Thus, bad actors can track user visits on an RP already. e.g. during the last time the user logged in with FedCM, RP and IDP could have already exchanged an identifier such that the RP could just make a fetch to the IDP and reveal relevant information to IDP anyway.

To align user expectations of whether they are logged into an RP, we propose UA revoking the previously granted permission when users clear cookies etc. for either IDP or RP. e.g. In Chrome, the permission gets cleared when a user clears Browsing history or cookies or SiteData in chrome://settings/clearBrowserData or chrome://settings/content/all (SiteData for either RP or IDP). i.e. auto re-authn won't work after such user actions.

mediation: silent

Per specification of the mediation: ‘silent’:

The intended usage is to support "Keep me signed-into this site" scenarios, where a developer may wish to silently obtain credentials if a user should be automatically signed in, but to delay bothering the user with a sign-in prompt until they actively choose to sign-in.

On the one hand, the key difference between silent and optional is that “RP prefers not to show any UI to users” if auto re-authn is unavailable when silent is used.

On the other hand, UAs may have requirements to show UIs in a FedCM API call to mitigate IdP tracking problem. e.g. Firefox shows an IdP selector before sending the request to fetch accounts from IdP; Chrome shows the account selector (and will show sign in to IdP UI or some error UI) after the accounts fetch.

We believe that it’s possible to respect both with the following proposal: when mediation: ‘silent’ is used, before fetching accounts, the browser can run several checks to make sure that we don’t fetch accounts if auto re-authn is guaranteed to fail. In this case, no UI needs to be displayed and no leak would occur:

Security Consideration

Technically speaking, the concept “auto re-authn” is achievable on the RP land. e.g. when a user is signing in to an RP with an IDP, the RP can set a long-lived cookie (e.g. 400 days) such that the user is always signed in to the RP as long as they revisit the RP within 400 days. However, while being able to automatically sign returning users back in is a promising feature for RPs, having to extend 1P cookies may be suboptimal or even impractical for some RPs. The proposed API on the other hand:

  1. provides all RPs the opportunity of “auto re-authn” without jeopardizing their cookie policy
    • Having long-lived session cookies are hard because an RP has to deal with cookie theft etc. which gets proportionally harder the longer it lives
    • It’s cheaper to operate by delegating it to the IDP (auto re–authn works when the user is signed in to the IDP, i.e. IDP needs to manage long-lived session cookies but RPs don’t)
  2. does not introduce any security risk similar to privacy since it’s “post permission”

Alternative proposal

Initially we proposed adding a new boolean autoReauthn: true|false to FedCM API to achieve the same goal but that requires reinventing the wheel which is suboptimal.

FedCM extensions consideration

IdpSigninStatus API integration

As part of the IdpSigninStatus API, the browser can be notified by the IdP that whether a user has an active session with them. If no user is signing in to the IdP when FedCM API is called, the browser will terminate the flow early before sending out an account fetch request. The same strategy will apply to auto re-authn. i.e. auto re-authn will be treated as “unavailable” if the IdpSigninStatus is signed-out.

Multiple IDP support

FedCM is adding multiple IDP support (explainer) which may have an intersection with auto re-authn. e.g. if both IDP1 and IDP2 are eligible for FedCM, how does FedCM handle auto re-authn?

Similar to the “single IDP with multiple accounts” use case, we can choose to trigger auto re-authn only if the user has one returning account across the IDPs. e.g.

Account with IDP 1 is new Account with IDP 1 is returning
Account with IDP 2 is new No auto re-authn Auto re-authn with IDP 1
Account with IDP 2 is returning Auto re-authn with IDP 2 No auto re-authn
yi-gu commented 1 year ago

@bvandersloot-mozilla Hi Ben, We are thinking about running an origin trial of this API and will send out an "Intent to Experiment" to blink-dev. Since this is not shipping, we are wondering whether a PR is needed to get you feedback as discussed the other day. Note that the API shape may change before shipping based on the experiment.

bvandersloot-mozilla commented 1 year ago

@martinthomson : thoughts on if feedback is needed before an Intent to Experiment?

bvandersloot-mozilla commented 1 year ago

To the proposal: I think I prefer using mediation modes- this feels like re-inventing that wheel.

To your concerns in the considered alternatives:

  1. This is exactly the purpose of mediation: optional.
  2. I think it would be good to add this! This was part of my federated3 proposal I was going to spin out into an atomic PR once my large editorial patches were done.
  3. I'm not sure I follow, but I think the core of the argument is "FedCM API cannot guarantee that the user is signed in post authentication which deviates a bit from the intended purpose of mediation: silent." I disagree with this. The intended purpose of the CM API is to get a credential, not guarantee that the user is signed in. I don't see how the semantics here are any different than existing uses of FedCM (or any other Credential). The RP can always require other steps to log in.

Also,

We should probably also add IdentityCredential to the Credential Management API if this option is desirable. This has already happened :) https://w3c.github.io/webappsec-credential-management/#sctn-cred-type-registry

yi-gu commented 1 year ago

Thanks Ben for the quick response!

  1. This is exactly the purpose of mediation: optional.

Agreed. On the other hand, mediation: optional is the default mode for get which means all RPs are opt-in to auto re-authn by default and they have to opt out explicitly with mediation: required if they don't want this feature.

For one, it changes the default behavior for FedCM sign-in flow. We need to think about what it means to future extensions like multiple IDP support and other potential use cases we have discussed about at FedIDCG. In addition, this seems like a backwards incompatible change (from UX's perspective and how developers recognize FedCM in general) so we need to evaluate whether it's reasonable to proceed (unlike IdpSigninStatus API which I have solid reason to make that backwards incompatible change).

  1. I'm not sure I follow, but I think the core of the argument is "FedCM API cannot guarantee that the user is signed in post authentication which deviates a bit from the intended purpose of mediation: silent." I disagree with this. The intended purpose of the CM API is to get a credential, not guarantee that the user is signed in. I don't see how the semantics here are any different than existing uses of FedCM (or any other Credential). The RP can always require other steps to log in.

That's a fair point. I suppose we can ask for some wording changes in CM API to make it more generic if needed.

Also,

We should probably also add IdentityCredential to the Credential Management API if this option is desirable. This has already happened :) https://w3c.github.io/webappsec-credential-management/#sctn-cred-type-registry

TIL :)

As mentioned earlier, origin trial is a way for us to understand whether the current proposal (API, UX etc.) makes sense such that we can course correct before shipping. While we are totally open with the "mediation mode" path and will be actively thinking it through, we'd like to proceed with the "autoReauthn" path for this round of origin trial to get some feedback on other fronts. Does it make sense?

Regardless the API shape, can I assume that there's no "objection" from you for the feature itself? Of course we need to agree on the API before shipping but that could be a separate conversation when we get there. WDYT?

martinthomson commented 1 year ago

@bvandersloot-mozilla:

thoughts on if feedback is needed before an Intent to Experiment?

I think that we'd like to get a little further into this before we can be happy.

I'd say that if this were more clearly the right design, then it might be easier to say "no problem", but I don't see that being the case here.

Let's look at this from a privacy perspective. Once the RP has obtained a user-bound identifier from the IdP, then the two sites are able to link activity from that person. That means that re-login flows can indeed be done without re-prompting, assuming that cookies have not been cleared on either site[^1].

It's not clear to me whether this is just about recovering from lost RP cookies, or whether it is really about complying with IdP policies about token validity and periodic re-authorization (of the RP by the IdP).

The proposed Boolean parameter doesn't really cover cases where there are potentially multiple identities involved though. I would prefer that the RP indicate directly which identity they want to re-authenticate, including the associated IdP. This would allow for multiple linked identities (potentially across different IdPs) without additional friction on this flow. There are ways to make this state more robust than a login cookie, which might expire for good reasons.

If the goal is to offer an option to choose a different identity, the browser is in a position to manage that. It will have better information. Though I will note that we might want to avoid offering new identities in general once one has been established; we might prefer to only show the chooser in the case where the original identity is no longer available for use.

There are lots of things in this proposal that I don't think are necessary (rate limiting re-authorization and showing browser UX being the ones that spring to mind).

[^1]: On this point, I would like to see the spec be clearer about what cookie clearing on either site does to login state, but let's set that aside for now.

yi-gu commented 1 year ago

Thanks Martin for the feedback! Some comments inline:

That means that re-login flows can indeed be done without re-prompting, assuming that cookies have not been cleared on either site1.

Great to hear that we are aligned on the privacy side! Yes if a user has cleared cookies/site data on either RP or IDP, the previous permission should be revoked. I listed it as the Prerequisite of the proposal but will make it clear going forward.

It's not clear to me whether this is just about recovering from lost RP cookies, or whether it is really about complying with IdP policies about token validity and periodic re-authorization (of the RP by the IdP).

The mail goal of this API is not about solving the RP cookie problem (if any). Rather, it's to reduce unnecessary user friction "post permission". As mentioned in the "Problem" section, any explicit confirmation after user returning to an RP does not provide privacy/security benefit like it does during the sign-up moment.

The proposed Boolean parameter doesn't really cover cases where there are potentially multiple identities involved though. I would prefer that the RP indicate directly which identity they want to re-authenticate, including the associated IdP. This would allow for multiple linked identities (potentially across different IdPs) without additional friction on this flow. There are ways to make this state more robust than a login cookie, which might expire for good reasons.

That makes sense. Rps should have the opportunity to specify which identity (or account) they'd like to re-authenticate. We have proposed another API (login_hint) which I believe can help with this situation. i.e. for Rps who want to re-authenticate a specific account, they could add login_hint to the get call. For those who are OK with any account, they could skip the login_hint bit and the browser could select the only returning account based on its own knowledge. Actually, with login_hint, we could potentially support multiple returning accounts if only one of them is "hinted" by the RP. WDYT?

If the goal is to offer an option to choose a different identity, the browser is in a position to manage that. It will have better information. Though I will note that we might want to avoid offering new identities in general once one has been established; we might prefer to only show the chooser in the case where the original identity is no longer available for use.

Understood! There are a couple of ways to reduce the chance for duplicated accounts. Skipping the chooser when there's one that's available is definitely a compelling solution. Another possible path is to show which account is new or returning on the chooser such that the user could be better informed about the situation. Will report back. That said, do you think this could be UA specific UX that's orthogonal to the re-authn API?

There are lots of things in this proposal that I don't think are necessary (rate limiting re-authorization and showing browser UX being the ones that spring to mind).

For "showing browser UX", IIUC, do you prefer skipping browser UI during re-authentication? For "rate limiting re-authorization", could you elaborate a bit? Did you mean re-authentication?

martinthomson commented 1 year ago

with login_hint, we could potentially support multiple returning accounts if only one of them is "hinted" by the RP. WDYT?

This is a little ambiguous to me. The form of login_hint is such that you can't always rely on it being an identity. That is, in OIDC, login_hint is poorly defined to the extent that it could just be a message that the RP sends to the IdP. That is clearly unacceptable in this context, so we might need to tighten this up more and define it as an identity.

At that point, the notion of automatic login is something the browser can look after. The Boolean parameter is not needed. If the identity is correct, then you are in one of two states:

  1. the site has not been authorized, so you need to talk to the user before acquiring a token; you might promote that identifier somehow, but that is down to browser choice
  2. the site was previously authorized, so you should avoid annoying the user and just get a token

If the identity is not correct, then you proceed with the full flow. Note that if the user has previously authorized a different identifier, this might be a way to force the browser into getting a different identifier. I'm not sure if this is something I like or not. I would prefer if RPs had only had one identity from one IdP, but I'd need to hear more about use cases to be confident in that position.

do you think this could be UA specific UX that's orthogonal to the re-authn API?

Yeah, we might offer guidance, but, as above, my preference is to avoid prompting where possible. If a prompt is shown, we might nudge people toward a previous choice rather than expand RP-IdP communication options, but mostly this is to avoid inadvertent account explosions.

For "showing browser UX", IIUC, do you prefer skipping browser UI during re-authentication?

I refer to your little popup that has no user interaction, other than maybe a cancellation. The mock shows this as fully inside the content area, with suggests that sites can render their own UX if they like. Also, the idea that a user might cancel a login is a bit pessimistic about IdP performance. Yes, IdPs can be quite slow, but they don't have to be. The cancellation only works well if they are very slow, but even then it has poor accessibility properties. I'd say you'd need excellent reflexes and fine motor control to hit that small button in time.

For "rate limiting re-authorization", could you elaborate a bit? Did you mean re-authentication?

By this, I refer to your proposed 10 minute timer. Let the IdP manage that. Note that I said re-authorization because the authentication happens at the IdP; the RP is authorized by the IdP (or by the user).

yi-gu commented 1 year ago

This is a little ambiguous to me. The form of login_hint is such that you can't always rely on it being an identity. That is, in OIDC, login_hint is poorly defined to the extent that it could just be a message that the RP sends to the IdP. That is clearly unacceptable in this context, so we might need to tighten this up more and define it as an identity.

Sorry for not being clear. In case you haven't seen our login_hint proposal, the hint we are defining is slightly different from OIDC. i.e. it currently only accepts "account id" or "email" which are clear identifiers. We are also considering using other fields in IdentityProviderAccount. Please see the "Extensibility" section in issue #426. If we tight the hint to reliable identifiers, does it mitigate your concern? It's possible that we should consider a rename for login_hint given the potential confusion.

  1. the site has not been authorized, so you need to talk to the user before acquiring a token; you might promote that identifier somehow, but that is down to browser choice

Agreed.

  1. the site was previously authorized, so you should avoid annoying the user and just get a token

As discussed earlier, this is definitely an option for Chrome that we want to iterate on.

If the identity is not correct, then you proceed with the full flow. Note that if the user has previously authorized a different identifier, this might be a way to force the browser into getting a different identifier.

Agree that this is a bit tricky. Basically it means that the browser has observed a single returing account that it can auto re-authenticate with but the RP has hinted a different account. We haven't really thought about this use case through but my intuition is that we should respect the RP's choice and NOT proceed with auto re-authn. We are also proposing isRequired for login_hint that allows the RP to specify whether they accept other accounts that are different from the one hinted (there are use cases that only specific account is accepted by the RP, e.g. accounts in enterprise and edu). Perhaps we could trigger different flows based on the isRequired bit?

the idea that a user might cancel a login is a bit pessimistic about IdP performance.

As you mentioned (also listed in the proposal) we won't proceed with a cancelable auto re-authn. (just to be clear, the thinking was about only sending the token request if a user doesn't cancel in N seconds so it should be orthogonal to IdP performance? Anyway it sounds like that this UX should be off the table)

By this, I refer to your proposed 10 minute timer. Let the IdP manage that.

We are introducing the cooldown to make sure that a user can logout and switch accounts if needed. Totally understand that you prefer "one identity per RP" and we share the same principle such that we'd suggest users to reuse their existing account other than creating new ones. That said, according to some user study we ran, there are users who have multiple identities on an RP for a variety of reasons so they may need to switch accounts every now and then.

Ideally, once a user is signed out of the RP explicitly (e.g. via a "Sign me out" button), the RP should not call FedCM with auto re-authn such that the user can switch accounts. However that's not guaranteed and the user will be signed in with the wrong account again when the RP fails to call FedCM properly. While it's indeed a programming error on the RP/IDP side, maybe the browser can take a position in this case to help with that? e.g. disabling auto re-authn for some time so they can switch accounts.

Again, for the origin trial, we'd like to gather feedback from all parties and evaluate the decisions we made before shipping. WDYT?

bvandersloot-mozilla commented 1 year ago

I've made a draft of what I was talking about RE the mediation parameter in #439. It is a draft because I don't think it is ready, however it is worth having something concrete to argue against.

Bojhan commented 1 year ago

How would this work in the use case where the user has two IDP's (my university and my research institute). They try both with the scientific publishers site, and find out that only one works. In the sense, only one actually has a contract so content access is granted.

How do we make it clear to the user, either one has to be removed (but only for this publishers site) or the user can choose which to tie initial re-auth with?

yi-gu commented 1 year ago

Before the user has completed a FedCM flow with either account, we always show both accounts without auto re-authn.

If the user has created an account with one of them (either university or research institute), next time the user is visiting the same publishers site, the publisher site can choose to trigger auto re-authn with that selected account.

if the user has created two accounts with both of them on the publisher site, auto re-authn will not be triggered and instead the user will need to manually select which one they want to proceed this time.

Note that the decisions are made based on the browser's knowledge of whether the user has created an account or not. i.e. if the user clears cookies or browsing history etc., the browser can choose to reset that knowledge.