Open cbiesinger opened 7 months ago
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.
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;
};
{
// 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.
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.
Some thoughts:
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.
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.
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?
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?
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?
+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.
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.
(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.