Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A proposal for framing the Login Status API that reconciles how FedCM/SAA are planning to use it #54

Closed
wants to merge 7 commits into from

Conversation

samuelgoto
Copy link

@samuelgoto samuelgoto commented Jun 23, 2023

Hey all,

Just following on #53.

I took the time to write down how, concretely, we think FedCM could reconcile with the Login Status API in this PR. You can see a preview of the text here.

@bvandersloot-mozilla, does this make more or less sense to you?

I didn't include a spec, since I wanted to try to gather some convergence at a high level before writing spec language.

I worked with @johannhof who is also interested in exploring how/whether this would help the Storage Access API, and he wrote a section on how that may play out to give you all a sense of how we think this may evolve.

@johnwilander WDYT?

@samuelgoto samuelgoto changed the title A proposal for framing the Login Status API that reconciles how we are planning to be used A proposal for framing the Login Status API that reconciles how we are planning to use it Jun 23, 2023
@bvandersloot-mozilla
Copy link

I think the shape of the API is good and reflects the extensibility required here.

The proposal here doesn't include a key feature of Johann's idea in #53 though. It must be "impossible for a website to read its state directly". I interpreted that to mean that APIs that consume the logged in state must not have web(-developer)-observable behavior based upon that state. This is a big part of the abuse story for this API; we don't want to leak even this one bit per origin to all callers. An explicit statement to this effect would be nice.

@johannhof
Copy link
Member

Yeah, I think that's a fair callout though I don't think any of what's proposed here goes against that idea.

@samuelgoto
Copy link
Author

we don't want to leak even this one bit per origin to all callers. An explicit statement to this effect would be nice.

Ah yes, that makes sense.

Before I do that, I think we have at least chrome and firefox roughly agreeing to the shape of this API, and we can discuss this further in more details in subsequent PRs (e.g. a proper spec).

@annevk @johnwilander where can we go from here as far as Safari is concerned? is this something that you are interested in or not?

If Safari isn't immediately interested in / able to participating in the development of this API, could you please merge this and give @bvandersloot-mozilla and I write access to this repo while we polish this up?

@erik-anderson @hober does that sound reasonable?

@johnwilander
Copy link
Collaborator

Hi! I was not aware of this proposal. I’ve requested that I get a heads up notification from CG chairs when one of my specs is on the agenda since I’ve found myself overbooked the last year or so.

I’m generally in favor of a shared editorship for this proposal. And the name change to Login Status API of course.

However, I want to make sure that the original intent is preserved. That is, to enable browsers to 1) empower sites where the user is logged in, and 2) restrict sites where the user is not logged in. The web has been lacking this signal forever (bar Basic/Digest Auth) and it could serve as a great boundary between allowing powerful but risky features and providing privacy-friendly casual browsing. To connect to an old debate – “it should be safe to click a link.”

Would y’all say we are in agreement there?

@johnwilander
Copy link
Collaborator

There is also another aspect that has grown in our interest regarding Login Status, and that is to formalize the success state of authentication and formalize the logout transition. The former is currently down to heuristics such as HTTP 200 after auth and the latter has never been dealt with, not even with Basic/Digest auth. These are important pieces for the web platform in our mind.

@samuelgoto
Copy link
Author

Hi! I was not aware of this proposal. I’ve requested that I get a heads up notification from CG chairs when one of my specs is on the agenda since I’ve found myself overbooked the last year or so.

Ugh, apologies if this didn't get to you sooner. I kicked this off in April and got word from @annevk in May, but somehow we didn't manage to find you in the process.

However, I want to make sure that the original intent is preserved. That is, to enable browsers to 1) empower sites where the user is logged in, and 2) restrict sites where the user is not logged in.

I believe the original intent in (1) and (2) are preserved.

I think, one of the differences from the original text, is that we turn (1) and (2) into concrete ways that it helps very specific APIs (e.g. the FedCM API and the Storage Access API) in very concrete terms. So, while the intent and intuitions are kept, the concrete first step in applying them is probably less ambitious than the full potential of this API, which is that's by design and deliberate: in one hand, we designed the API to be extensible such that it can be used, incrementally and gradually, to more and more meaningful ways that the Web Platform can take this signal in and on the other hand, we defined a couple of specific ways that it can be useful right now to specific applications.

I think the only way to bootstrap this API is to start with concrete and useful ways in which it provides value to the Web Platform.

Would y’all say we are in agreement there?

I believe we are in agreement, but I think you should be the judge of that. Read/review the explainer text in this PR, and make suggestions to make sure that your intent is captured.

There is also another aspect that has grown in our interest regarding Login Status, and that is to formalize the success state of authentication and formalize the logout transition.

Logout is defined in this PR, and needed by FedCM. Would that be sufficient?


```javascript
Sign-in-Status: type=idp, action=signin

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fwiw, this needs to be ; instead of ,

(https://www.rfc-editor.org/rfc/rfc9110#parameter)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd also prefer Signin-Status over Sign-in-status

@johnwilander
Copy link
Collaborator

Ugh, apologies if this didn't get to you sooner. I kicked this off in April and got word from @annevk in May, but somehow we didn't manage to find you in the process.

I didn't mean to imply that Anne hasn't discussed it with me. I only meant that I assume this has been discussed at PrivacyCG meetings and I haven't been present.

@samuelgoto
Copy link
Author

samuelgoto commented Jul 25, 2023

I didn't mean to imply that Anne hasn't discussed it with me. I only meant that I assume this has been discussed at PrivacyCG meetings and I haven't been present.

This has been discussed in a Privacy CG meeting indeed (and you were, indeed, not present), albeit briefly: meeting notes here. The AI that I took was to kick off this bug and go from there (which is this PR).


interface LoginStatusOptions {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably be a dictionary and should have a boolean idp member?

I am undecided on whether logout should also have the idp member or not, hmm

Here’s how the API for checking the login status could look:
```javascript
partial interface Navigator {
Promise<void> setLoggedIn(optional LoginStatusOptions options);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would recordLogin be a better name?

Also, with the header being named Signin-Status, should this use setSignedIn/recordSignin?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, my preference is to consistent with the header, so setSignedIn() and setSignedOut(). I dislike the record prefix, that feels foreign (is there any other API that has that prefix?), but not a hill I'm wiling to die on.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong opinion; @bvandersloot-mozilla suggested record* in w3c-fedid/FedCM#430 (comment)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The set prefix is also weird because it seems like a setter but this is not. How about just logIn / logout or signIn / signOut? Or maybe report instead of record since it’s the site telling the browser?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also what’s with the Signin-Status header and is that beyond being renamed?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Regarding the header, we got feedback that a JS API is not enough for certain cases, so we also added an HTTP header for that purpose. It works more naturally IMO when a website redirects to the real destination after login; you'll just send the header in response to the form POST + redirect to the real destination without needing an intermediate page that calls the JS API (or adding the JS call to every page that you might get redirected to)

We are totally open to renaming it and/or changing the syntax.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think report makes sense as the word used here.

cbiesinger added a commit to cbiesinger/WebID that referenced this pull request Aug 15, 2023
This removes "IDP" from the HTTP header and JS API names so that they are more
compatible with the is-logged-in API:
https://github.com/privacycg/is-logged-in

See also privacycg/is-logged-in#54

Open question:
Should the JS API use the exact name in the current is-logged-in
explainer (recordLoggedIn) or the more consistent name that this
PR uses (recordSignedIn)?
samuelgoto pushed a commit to w3c-fedid/FedCM that referenced this pull request Aug 17, 2023
* Use generic names for the header and JS API

This removes "IDP" from the HTTP header and JS API names so that they are more
compatible with the is-logged-in API:
https://github.com/privacycg/is-logged-in

See also privacycg/is-logged-in#54

Open question:
Should the JS API use the exact name in the current is-logged-in
explainer (recordLoggedIn) or the more consistent name that this
PR uses (recordSignedIn)?

* grammar fixes
@johannhof
Copy link
Member

A bit late to this but wanted to add my support for this statement by Sam:

I think the only way to bootstrap this API is to start with concrete and useful ways in which it provides value to the Web Platform.

and note that based on @johnwilander it sounds like we're thinking of different APIs, with the main difference being whether or not the login status is a "trusted" signal (one that can't be set by the site for their own gain) or a site-provided signal that the browser will use to enhance the user experience and provide utility to sites in ways that won't be desirable for other sites without the signal. For the former use case, I'm not sure I really see any concrete ideas of execution / utility on the web right now, which is likely to further stall development of the API because of unclear timelines and requirements. I'd like to focus on what we know we can achieve.

@samuelgoto
Copy link
Author

and note that based on @johnwilander it sounds like we're thinking of different APIs, with the main difference being whether or not the login status is a "trusted" signal (one that can't be set by the site for their own gain)

It is critical that we get the design of incentives right, but I don't think that what @johnwilander has in mind is necessarily in conflict with he API that has been proposed in this PR here: we could decide later to create an extension that has the properties that make the signal "trusted", e.g. via prompting the user (either as a modal dialog or a non-modal dialog -- such as a status indicator) such that the browser would be able to be confident enough to respect this signal.

We can cross this bridge when we get there, but here is a code snippet of what that might look like, with what's being proposed:

// Prompts the user for confirmation
navigator.setLoggedIn({
  prompt: true, // prompts the user for confirmation,  prompt: "indicator" may not prompt but indicate
  profile: {
    name: "John Doe",
    picture: "https://website.com/john-doe/profile.png",
  }
});

That is, we designed the API to be extensible enough that it can cover a good amount of ground between "self-declared" signals to "user-approved" signals, so I think a good spectrum of UX choices can be covered with this design.

Copy link

@othermaciej othermaciej left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR contains many not entirely related changes, resulting in a near-total rewrite. Some are style changes, some are API signature changes, and some totally change the security model. It would be easier to review if broken up into smaller PRs.

That said I left some comments.

Here’s how the API for checking the login status could look:
```javascript
partial interface Navigator {
Promise<void> setLoggedIn(optional LoginStatusOptions options);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The set prefix is also weird because it seems like a setter but this is not. How about just logIn / logout or signIn / signOut? Or maybe report instead of record since it’s the site telling the browser?

Here’s how the API for checking the login status could look:
```javascript
partial interface Navigator {
Promise<void> setLoggedIn(optional LoginStatusOptions options);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also what’s with the Signin-Status header and is that beyond being renamed?

Comment on lines -106 to -139
### Defending Against Abuse

If websites were allowed to set login status whenever they want, it
would not constitute a trustworthy signal and would most likely be
abused for user tracking. We must therefore make sure that login status
can only be set when the browser is convinced that the user meant to log
in or the user is already logged in and wants to stay logged in.

Another potential for abuse is if websites don’t call the logout API
when they should. This could allow them to maintain the privileges tied
to login status even after the user logged out.

There are several ways the browser could make sure the login status
is trustworthy:

* Require websites to use WebAuthn or a password manager (including
Credential Management) before calling the API.
* Require websites to take the user through a login flow according to
rules that the browser can check. This would be the escape hatch for
websites who can’t or don’t want to use WebAuthn or a password manager
but still want to set login status.
* Show browser UI acquiring user intent when login status is set.
Example: A prompt.
* Continuously show browser UI indicating an active login session on
the particular website. Example: Some kind of indicator in the URL
bar.
* Delayed browser UI acquiring user intent to stay logged in, shown some
time after the login status was set. Example: Seven days after login
status was set – “Do you want to stay logged in to news.example?”
* Requiring engagement to maintain login status. Example: Require user
interaction as first party website at least every N days to stay
logged in. The browser can hide instead of delete the credential token
past this kind of expiry to allow for quick resurrection of the login
session.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the justification for the removal of this section and replacement with the much weaker “Assumption of Abuse”? It seems like the new explainer doesn’t require or even permit UAs to try to prevent dishonest use of the login status API, and instead tells them to assume the signal may be dishonest. This defeats the original purpose of this API as described by @johnwilander .

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think spirit of this section is represented through the explainer via specific and concrete ways in which a browser can "defending against abuse". That is, rather than a section on "ways the browser could make sure the login status is trustworthy" we are proposing "two specific ways (FedCM and SSA) that the browser could read this signal and trust its veracity -- and, in the future, if we find other ways, we can extend this API to introduce them".

I'd be happy to bring parts of this section back, but I hope that we didn't go as far as defeating the original purpose of this API as @johnwilander intended it to be.

If we did, and you and @johnwilander don't feel that this explainer reconciles with the spirit Login Status API, we could still go back to using our FedCM-specific Sign-in-Status API, and we'd be OK with that too.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be happy to bring parts of this section back, but I hope that we didn't go as far as defeating the original purpose of this API as @johnwilander intended it to be.

Maybe we could start by iterating on the PR to bring all of it back? I do not understand why deleting any of it is necessary to your other changes. If it is, please explain.

If we did, and you and @johnwilander don't feel that this explainer reconciles with the spirit Login Status API, we could still go back to using our FedCM-specific Sign-in-Status API, and we'd be OK with that too.

I'm confused. Are you saying you are willing to bring back some/all of this section (b/c I think removing it does not align with the original spirit of Login Status API), or we have to take this PR as-is or you'll diverge and ship your own thing?

Copy link
Member

@johannhof johannhof Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do think that there's an initial conflict between the goals stated in the original explainer ("If websites were allowed to set login status whenever they want, it would not constitute a trustworthy signal") and how this PR changes things (by allowing websites to set login status whenever they want).

As Sam mentions in #54 (comment) this can probably be overcome, so I think the larger question here is can we find some convergence between the two ideas that leaves the door open for WebKit's login status idea, for the benefit of developers who wouldn't have to deal with two very similar signals.

If we think we can, then I don't think it makes sense to restore this section as-is, as that would be incompatible with some new ideas presented in this PR. Rather, we should adapt it to whatever compromise we arrive at (e.g. a prompt or trusted flag in the setLoggedIn call as Sam suggests in his comment).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do those things, but shouldn't trustworthiness considerations in the Explainer cover the whole span of envisioned use cases, not just the FedCM one?

I think the key part here to make sure we are on the same page is to whether to capture in the explainer (and the spec) what we hypothetically could do or what we are actively planning to do: we propose we focus on the latter. We don't have any active plans to use this API outside of the direct use of FedCM and (possibly) SAA, which are both described in the explainer as concrete things that we would like to do do. We think it is plausible that it could hypothetically be used for other things, so we think it makes sense to have this more general API, but we wanted to be clear that we haven't yet found other uses where the design of incentives and the economics of abuse align.

I'm confused. Are you saying you are willing to bring back some/all of this section (b/c I think removing it does not align with the original spirit of Login Status API), or we have to take this PR as-is or you'll diverge and ship your own thing?

It is important to make sure that we are clear that we haven't found (nor are proposing) use of the Login Status API outside of FedCM (and, as I said, possibly, the Storage Access API), so if you are expecting that this proposal will offer a concrete way in which a website can declare their Login Status in a way that we think that the browser can generally trust (again, outside of how FedCM/SAA would use), then yes, I think this proposal isn't aligned with the original spirit of the Login Status API (and hence, naturally, we'd be happy to make it FedCM-specific).

We do, however, remain of the opinion that, while this is a constrained use of the Login Status API (for FedCM and SAA specifically), it can be designed to be extensible for further user, and hence, is worth using a generalizable/extensible API, so our preference is this PR to be accepted so that we can make FedCM depend on it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know where it got lost in this conversation, but we’ve been clear from the get go that we want a trustworthy signal as to 1) which websites it’s most important to maintain state for, and 2) which websites the user has an established relationship with and is more likely to want to enable powerful but risky features for.

Copy link
Author

@samuelgoto samuelgoto Sep 9, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know where it got lost in this conversation, but we’ve been clear from the get go that we want a trustworthy signal as to 1) which websites it’s most important to maintain state for, and 2) which websites the user has an established relationship with and is more likely to want to enable powerful but risky features for.

I think the disconnect may be on how we are using the term trustworthy: what's written in this PR is trustworthy within the thread model of the specific proposals trying to consume it (FedCM and SAA).

We haven't thought it through, but the intuition is that it is not trustworthy within other threat models, including ones involving what's listed here (e.g. clearing storage, etc), so we are hesitant in introducing those models without having any plans to ship them.

In this proposal, we are (a) proposing a couple of uses that we think that the bit can be used in a trustworthy way (again, within the threat model of how FedCM and SAA operate) and (b) leaving the extensibility points so that other abuse models can be introduced as it goes along (e.g. so that, as they get introduced, it is easier / incremental for developers to adopt).

1. Self-declared: any website can and will lie to gain any advantage
2. Client-side: the state represent the website's client-side knowledge of the user's login status, which is just an approximation of the server-side's state (which is the ultimate source of truth)

One potential for abuse is if websites don’t call the logout API when they should. This could allow them to maintain the privileges tied to login status even after the user logged out.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about the potential for abuse if sites call the login API when the user is not actually logging in?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The specific use being proposed as the first extension of the Login Status API is for FedCM (and possibly the Storage Access API) to use the signal.

In both of these cases, the consumers (FedCM/SAA) have to construct the use of the signal in such a way that assume the signal is self-declared. So, for FedCM specifically, we show an "Error/mismatch UI" when the information we get from (a) the Login Status API and (b) the accounts endpoint returns. The user experience of the Error UI is constructed in such a way that a valid / honest Identity Provider wouldn't want to abuse itself (by lying to the browser), and an dishonest IdP would just show Error UIs to users.

The same occurs for dishonest/honest Identity Providers lying about the user logging-out.

We have constructed the extension of the Login Status API such that a website self-declares its status as an Identity Provider:

// Records that the user is logging-in to a FedCM-compliant Identity Provider.
navigator.setLoggedIn({
  idp: true
});

The idp: true parameter indicates that the website is declaring itself as a FedCM-compatible IdP (which is not game-able). Any other Web Platform API that wanted to consume this signal would have to either (a) have to work within the FedCM assumptions of abuse or (b) extend the Login Status API.

For example, @johannhof is making the case that the SSA API can take this signal as is, so could reuse this signal with:

// Records that the user is logging-in, which allows the Storage Access API to conditionally dismiss its
// UX.
navigator.setLoggedIn();

// In another cross-site top-level document, auto-reject rSA (with some delay to avoid timing attacks) unless the user is logged in
document.requestStorageAccess({rejectUnlessLoggedIn: true}).then(...);

The signal doesn't have to always be self-declared, it can be mediated by the user too. So, for example, we could extend the Login Status API to have a browser prompt (or perhaps just a status indicator), that would make the change visible enough that a browser would be able to trust it as acknowledged by the user.

navigator.setLoggedIn({
  profile: {
    name: "John Doe",
    picture: "https://website.com/john-doe/profile.png",
  }
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could do those things, but shouldn't trustworthiness considerations in the Explainer cover the whole span of envisioned use cases, not just the FedCM one?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does cover use cases that are designed in a way where site-declared login status can safely provide user benefits. Maybe it makes sense to call this a "base" or "untrusted" tier and have another tier for "trusted" applications of the API?

@samuelgoto
Copy link
Author

samuelgoto commented Sep 5, 2023

This PR contains many not entirely related changes, resulting in a near-total rewrite. Some are style changes, some are API signature changes, and some totally change the security model. It would be easier to review if broken up into smaller PRs.

Agreed that it makes it harder to review, but it seemed useful for the original authors to look at the entirety of the changes proposed as a whole, rather than in isolation.

The set prefix is also weird because it seems like a setter but this is not. How about just logIn / logout or signIn / signOut? Or maybe report instead of record since it’s the site telling the browser?

Yeah, we don't feel too strongly about what the names of the methods are ... I agree that set isn't great, but record didn't seem like it had any precedence in the web platform as a prefix for methods (did I get this right?). I think signIn() and signOut() could work too, but they feel like they could have other meanings (e.g. a verb/action rather than a status update).

What about navigator.setSignInStatus("signed-in" | "signed-out")?

Also what’s with the Signin-Status header and is that beyond being renamed?

Nope, not beyond renaming, it is part of this proposal.

We have the Sign-in-Status in origin trials in chrome, but we are happy to change its name if we find enough convergence across browsers.

That said I left some comments.

Responding to other comments inline.

@samuelgoto samuelgoto changed the title A proposal for framing the Login Status API that reconciles how we are planning to use it A proposal for framing the Login Status API that reconciles how FedCM/SAA are planning to use it Sep 9, 2023
@samuelgoto
Copy link
Author

I'm going to close this pull request based on the conclusion that we all collectively arrived at TPAC here.

@samuelgoto samuelgoto closed this Oct 4, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants