w3c-fedid / FedCM

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

Support personalized sign-in buttons with User Info API #382

Closed yi-gu closed 1 year ago

yi-gu commented 1 year ago

Motivation

Websites may have “Sign in with X” buttons on their page to support federation with an identity provider (IDP). When an end user visits a website (Relying Party, or RP), a personalized button gives them a quick indication of their IDP account status (e.g. name, picture etc.) that is recognizable by users. It could also potentially prevent unnecessary creation of duplicate accounts. See example below for existing personalized buttons on the web.

Currently, personalized buttons are rendered as IDP owned cross-origin iframes on the RP site and have dependency on third-party cookies.

This proposal introduces a new way to implement personalized buttons with the FedCM API for users who have used FedCM to sign in to the RP with the IDP in the past. i.e. it's out of scope if a user never used FedCM on the {RP, IDP} pair in the browser.

See a proof of concept demo below:

https://user-images.githubusercontent.com/23404313/205805729-5713eba4-6d2d-42c0-a187-e1ea0b223144.mov

Proposal

Since the button is rendered inside a cross-origin iframe, a permissions policy is required to use FedCM for it. e.g. the top frame needs to specify the existing identity-credentials-get Permissions Policy for the button iframe. In addition, a new API is exposed for the IDP owned iframe to retrieve user information.

Note: to prevent abuse, we only support showing personalized buttons for returning users. i.e. if a user visits an RP with a “Sign in to IDP” button but they never created an account on the RP with the IDP using FedCM API, the user won’t see a personalized button because the browser will not share the user info with the IDP owned iframe.

New Flow Overview

The existing FedCM API for authentication is targeted at all types of users regardless whether they have created a federated account with FedCM before. The browser needs to ask for user permission explicitly before resolving the promise and handing over the token to the API caller.

Since “Personalized button” is targeted only at returning users who have granted permission on the FedCM UI before, i.e. the user must have clicked the “Continue as” button to use a federated account on the RP with their IDP before, under certain circumstances (see below) the browser is allowed to share some user info (e.g. name, picture, email) that is fetched from an IDP with the IDP owned iframe without sacrificing privacy or security. We propose to extend the existing FedCM API to achieve this goal. Below is a flowchart with the high level algorithm.

Personalized button

There are a couple of key checkpoints in the flow:

Notes

API options

The IDP iframe needs to indicate their intention to use FedCM for personalized buttons instead of tokens. This can be achieved by the options below.

Static getIdentityUserInfo in IdentityCredential

const user_info = await IdentityProvider.getUserInfo({
    configUrl: "https://idp.example/fedcm.json",
    clientId: "client1234"
});

if (user_info.length > 0) {
  // It's up to the IDP regarding how to display the returned accounts. Accounts are sorted based on RP registration status.
  const name = user_info[0].name;
  const given_name = user_info[0].given_name;
  const display_name = given_name ? given_name : name;
  const picture = user_info[0].picture;
  const email = user_info[0].email;
}

Considered alternatives

Alternative 1: Static getIdentityUserInfo in IdentityCredential

const user_info = await IdentityCredential.getUserInfo({
    configUrl: "https://idp.example/fedcm.json",
    clientId: "client1234"
});
// same as above

Alternative 2: RequestType in IdentityProvider

const cred = await navigator.credentials.get({
    identity: {
        providers: [{
          configUrl: "https://idp.example/fedcm.json",
          clientId: "client1234",
          requestType: "userInfo"  // optional, "userInfo": personalized button flow, "token"(default): token flow 
        }]
      }
});
const user_info= cred.identityUserInfo;
// same as above

Privacy Consideration

The major difference between the existing token flow and the personalized button flow is that the latter does not require explicit user permission at API invocation time. However, an explicit user permission to allow the RP-IDP communication MUST be 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”. As shown in the demo, a user won’t see their personal information on a button before they use FedCM to sign in to the RP with the IDP.

One caveat on the permission: while it's up to the user agents to decide whether to revoke it upon clearing browsing history or whether to sync it across devices, it should not be revoked when the user signs out from the RP or IDP because the user is not explicitly revoking the granted permission in that case. We are planning to ship a Revocation API to allow users to disconnect RP and IDP and the permission should be revoked there.

It’s worth noting that there’s a potential invisible tracking problem in the FedCM API. The way we mitigate the problem is to make sure that all accounts fetches end up with some browser UI to make the tracking visible to users. Unlike the token flow which is targeted at all users, the personalized button flow only works for returning users. i.e. 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. Therefore, if the accounts request fails silently or the IDP iframe chooses to display nothing, there’s no new privacy risk introduced.

Security Consideration

The personalized button flow is only supported when the API is invoked from an IDP owned iframe to avoid leaking user information to an arbitrary party. In addition, we limit the size of the IDP list to 1 to avoid leaking user information to unrelated IDPs. In addition, the user permission granted in the past to gate the personalized button flow does not get synced across devices so that there’s no security risk there either.

It’s worth noting that technically speaking the IDP iframe can share the information with its embedder or even embeddees. Given that the feature is for users who have granted permission to allow RP-IDP communication in the past, the potential abuse is impractical.

Notes about why we propose a new userInfo flow: compared to the existing token flow, it

The new flow provides a dedicated high level API for IDPs. However, from security’s point of view, it does not really ensure anything more than using the userInfo flow with the same restrictions because IDP can still pass in extra information in the preset fields so “less user information” cannot really be enforced by the browser.