w3c-fedid / custom-requests

This is a proposal to extend FedCM to allow RPs to make custom requests to the IdP
3 stars 1 forks source link

Allow IdPs to continue and finish the request in a popup window #1

Open cbiesinger opened 7 months ago

cbiesinger commented 7 months ago

(this has been split out of w3c-fedid/FedCM#477 )

FedCM’s account chooser and disclosure dialog only allows asking for permission to share standard claims (e.g. user’s name, email address and profile picture). However, commonly Identity Providers (IdPs) need to ask for additional information before returning the token to the relying party (RP), such as requesting re-authentication, scopes beyond standard claims (e.g. API access), verifying up-to-date contact information, parental controls, etc.

There is currently no mechanism that an IdP can use to use their own words to request their user's permission before returning a token to the RP.

cbiesinger commented 7 months ago

Proposal

We are proposing to extend the ID assertion response to let the IDP specify a field called continue_on (which can be used in replacement of token). This field would contain a (same-origin) URL that the user agent can use to show a popup so that the user can continue the signin flow.

Once finished, the identity provider will call a new function IdentityProvider.resolve(token) in the popup to indicate that the flow is finished and to provide the token to pass back to the RP.

IDL

dictionary IdentityResolveOptions {
 USVString accountId;
};

partial interface IdentityProvider
    // Allows an IdP to return a token to the RP from the content area,
    // as opposed to over HTTP with the id_assertion_endpoint.
    static Promise<undefined> resolve(USVString token,
        optional IdentityResolveOptions options = {});
};

And the dictionary for the ID assertion response would be extended like this:

dictionary IdentityProviderToken {
  optional USVString token;
  optional USVString continue_on;
};

Example

{
  // In the id_assertion_endpoint, instead of returning a typical
  // "token" response, the IdP decides that it needs the user to
  // continue on pop-up window:
  "continue_on": "/oauth/authorize?scope=..."
}

The popup might then contain code like this:

document.getElementById("allow_btn").addEventListener("click", async () => {
  let accessToken = await fetch(`/generate_access_token.cgi`);
  // Closes the window and resolves the promise (that is still hanging
  // in the relying party's renderer) with the value that is passed.
  IdentityProvider.resolve(accessToken);
});

The user agent will then close the popup and resolve the promise (returned from navigator.credentials.get) with the provided token.

If for some reason the user has changed in the popup (e.g. the IDP offers a “switch user” function or in delegation cases), the resolve call takes an optional second argument allowing something like:

  IdentityProvider.resolve(token, {accountId: "1234");

If not provided, the user agent will assume the account ID is unchanged from what the user has selected.

Considerations

Because this happens after the user has selected an account, it is safe to allow access to unpartitioned cookies in the popup. However, we still do not allow direct communication with the RP – the popup behaves as if noopener,noreferrer was specified (thus, window.opener is null). The only way to communicate with the RP should be a one-time IdentityProvider.resolve call, which also closes the popup.

We only want to allow popups when we had a user interaction. Therefore, we allow them when the user selected an account in the account chooser, or in button mode (which always requires user activation). But we don’t want to allow the popup for mediation: silent (a popup is pretty loud), and for mediation: optional for the widget mode we check for transient user activation. Otherwise, we open no popup and reject the promise.

Due to its versatility, this proposal can also be used for cases where no token will be returned, such as for showing custom error messages. We think this is a feature, not a bug.

achimschloss commented 6 months ago

Some thoughts:

cbiesinger commented 6 months ago

This is intended to be a regular popup where you can redirect as much as you like. Can you remind me whether you needed the resolve call to be possible from a different domain as well? (close is largely unrelated to this proposal)

No requirements for user interaction, as you point out.

samuelgoto commented 6 months ago

Posting this on behalf of @panva

It would be cool if the IdP had a HTTP header version of the IdentityProvider.resolve() call to fit within the current deployment.

samuelgoto commented 6 months ago

Also from @panva:

Do the requests shown in a window in response to the "IDP login dialog" flow include the "Sec-Fetch-Dest: webidentity" HTTP header? If not, why?

samuelgoto commented 6 months ago

It would be cool if the IdP had a HTTP header version of the IdentityProvider.resolve() call to fit within the current deployment.

That seems reasonable to me. @cbiesinger, any concern?

samuelgoto commented 6 months ago

Do the requests shown in a window in response to the "IDP login dialog" flow include the "Sec-Fetch-Dest: webidentity" HTTP header? If not, why?

I believe the answer is "no". @cbiesinger ack?

vaceksimon commented 6 months ago

+1 to the HTTP header version of the js call. This could also be considered for the dynamic sign-in flow. After authenticating the user, the IdP could send the successful authn response only with extra headers causing the pop-up window to close, without the need to modify the signing in process any futher.

panva commented 6 months ago

It would be cool if the IdP had a HTTP header version of the IdentityProvider.resolve() call to fit within the current deployment.

That seems reasonable to me. @cbiesinger, any concern?

For clarity I don't think it would be cool per se. I think it is a prerequisite for being able to fit the FedCM signals to an existing IdP login interaction rather than having to define a new login form response that is a blank HTML with a Githubissues.

  • Githubissues is a development platform for aggregating issues.