Consider supporting federated login without IDP APIs
This is meant to be a conversation-starter around how we can preserve federated login scenarios without adding IDP APIs.
I don't think this needs to be independent of FedCM. However, because it is a large addition and FedCM is sufficiently complicated, I feel more comfortable first writing it as an independent proposal that could be integrated into FedCM.
The rest of this Issue is a proposal for an integration to Credential Management that enables federated logins to work without third-party cookies. The strategy is to pave the cow-path of existing sign-in mechanisms that use a third-party origin to authenticate, requiring minimal changes by the IDP. The goal is to create an easy on-ramp for IDPs to use the Credential Management API and authenticate users to RPs in browsers that have deprecated third-party cookies.
It is named "federated3" because the "Credential Management API" spec defines a "federated" credential and FedCM used "federated2" for a time.
What is the Expected User Experience?
Registration
Registration with the IDP is unchanged.
Linking Registration
- When a user goes to register for an account on a
example.com, they click a "Register with IDP" button.
- A Browser Permission UI appears asking if the user wants to register on
example.com using their information from idp.com.
- The user clicks yes and a popup (or new tab) appears of
idp.com that allows the user confirm the permissions for example.com.
- The popup (or new tab) closes and the user lands back on
example.com, logged in.
Alternatively, via new web UI patterns:
- When a user goes to register for an account on a
example.com, they click a "Register" button.
- A "Credential Chooser" appears presenting WebAuthN, passwords, and/or a few IDPs, depending on
example.com's choices and the browser's support.
- The user selects one of the IDPs.
- Proceed from linking Step 3.
RP Log in
- When a user goes to log in to
example.com, they click a "Log in with IDP" button.
- If the user has already linked
registered and the credential from last time has not expired, they are immediately logged in.
- Otherwise, they proceed from linking
registration Step 2.
Alternatively, via new web UI patterns:
- When a user goes to log in to
example.com, they click a "Log In" button.
- If the user has already linked
registered any Credentials with this site (of any variety) the user may select from them in browser UI.
- The user selects a
federated3 credential, proceed to Log in Step 2.
RP Log out
- When a user wants to log out of
example.com, they click the "Log Out" button.
- The user is logged out only on
example.com.
What is the Expected RP (or IDP Library) Developer Experience?
Linking Registration
- Calls to
navigator.credentials.create with argument key credential3 can specify [1,n] different supported identity providers.
- The RP can also provide a blob of data to each identity provider that they will get sent with a linking
registeration request.
- The user is shown those identity providers and can pick from them.
- Once a choice is made, you know which provider was chosen and get a blob of data in response.
navigator.credentials.store the result from navigator.credentials.create to remember the user as logged in.
Log in
- Calls to
navigator.credentials.get with argument key credential3 can specify [1,n] different supported identity providers.
- If the user already logged in to your service with one of those IDPs, then you will receive a blob of data from the IDP.
- If the user is not logged in with one of those IDPs, but has linked
registered with one on this site before, then the user is logged in and you will receive a blob of data from the IDP.
- If that blob of data is insufficient, you can re-link
re-register with the IDP for more permissions.
- Otherwise,
navigator.credentials.store the result from navigator.credentials.create to remember the user as logged in.
RP Log out
- Call
navigator.credentials.preventSilentAccess().
What is the Expected IDP Developer Experience?
Log in
Add a call to any authentication page that:
- Checks if a Federated Login Status request is pending
- If it is not, return
- Process the pending request (including a blob provided by the RP)
- Call a Federated Login Status response.
Log out
Add a call to any logout callback that:
- Calls a Federated Login Status logout.
How this is Accomplished in Specification?
In order to get the above UX and DX, we need to make only the following changes to the web platform.
This proposal has three key parts, each presented in
A new Permission
We add a new permission, say federated-authentication which is keyed on the origins of the RP and IDP.
Its semantics are that it represents permission for an RP to enter login flows, such as popup, with a given IDP.
A defined Federation Login Status API
We need to have a defined subset of the Login Status API. I propose we introduce at least a subset of it here:
dictionary LoginStatusRequest {
required string relying_party_origin;
string request_blob;
}
[Exposed=Window, SecureContext]
interface LoginStatus {
Promise<LoginStatusRequest?> pendingFederatedLoginRequest();
void completeFederatedLoginRequest(string? response_blob);
}
This can integrate with any other Login Status API implementation to allow calls to completeFederatedLoginRequest to set logged in status for the RP and IDP.
A new Credential
Finally, we need a new credential type that has the blob from the IDP's call to completeFederatedLoginRequest and options to request it.
[Exposed=Window,
SecureContext]
interface FederatedCredential3 : Credential {
readonly attribute USVString blob;
};
dictionary Federated3CredentialRequestOptions {
sequence<FederatedProviderConfig> providers;
};
dictionary FederatedProviderConfig {
required USVString loginURL;
required USVString clientId;
required USVString blob;
FederatedProviderDisplayParameters style;
};
enum FederatedProviderDisplayStyles {
"popup",
"newtab"
};
enum FederatedProviderDisplayPosition {
long width;
long height;
long left;
long top;
}
dictionary FederatedProviderDisplayParameters {
FederatedProviderDisplayStyles? style;
FederatedProviderDisplayPosition? popupPosition;
};
partial dictionary CredentialRequestOptions {
Federated3CredentialRequestOptions federated3;
};
partial dictionary CredentialCreationOptions {
Federated3CredentialRequestOptions federated3;
};
Its [[discovery]] would be "remote" and [[type]] would be "federated3".
This credential would define its [[CollectFromCredentialStore]] and [[Store]] methods to allow storing and retrieving of credentials within the same origin.
This credential would define its [[Create]] method to perform linking registration. This would be something akin to:
- Perform Permission Policy check.
- Show the user UI to pick a given IDP.
- On selection, store a "Pending request" in the browser containing a
LoginStatusRequest with the blob the RP provided and the RP's origin.
- Navigate to the
loginURL chosen, optionally matching the RP requested style.
- Await a call to
completeFederatedLoginRequest in the IDP page.
- Set the
federated-authentication permission for (RP, IDP).
- Return a credential with the blob argument of
completeFederatedLoginRequest.
This credential would define its [[DiscoverFromExternalSource]] method to be what happens when navigator.credentials.get is called, but the user is not currently logged in.
- Perform Permission Policy check.
- If the user has a Federated3Credential, and has
federated-authentication permission for (RP, IDP)
- Return that credential.
- Otherwise, if the user has a Federated3Credential, present that in a prompt with "pick another account"
- If the user selects the existing credential, return it.
- Otherwise, return the result of
[[Create]] with the same arguments.
Open questions
I think the answer to all of these is yes, with some work.
- Can we manage to do front-channel logout if the RP constrains its use of Credentials.
- Can this reasonably integrate with other credentials?
- Can we support redirect login flows with minor changes to this definition and no change in UX or DX?
Out of scope
- Server-side APIs
- One-tap-like integrations.
Consider supporting federated login without IDP APIs
This is meant to be a conversation-starter around how we can preserve federated login scenarios without adding IDP APIs.
I don't think this needs to be independent of FedCM. However, because it is a large addition and FedCM is sufficiently complicated, I feel more comfortable first writing it as an independent proposal that could be integrated into FedCM.
The rest of this Issue is a proposal for an integration to Credential Management that enables federated logins to work without third-party cookies. The strategy is to pave the cow-path of existing sign-in mechanisms that use a third-party origin to authenticate, requiring minimal changes by the IDP. The goal is to create an easy on-ramp for IDPs to use the Credential Management API and authenticate users to RPs in browsers that have deprecated third-party cookies.
It is named "federated3" because the "Credential Management API" spec defines a "federated" credential and FedCM used "federated2" for a time.
What is the Expected User Experience?
Registration
Registration with the IDP is unchanged.
Linking
Registrationexample.com, they click a "Register with IDP" button.example.comusing their information fromidp.com.idp.comthat allows the user confirm the permissions forexample.com.example.com, logged in.Alternatively, via new web UI patterns:
example.com, they click a "Register" button.example.com's choices and the browser's support.RP Log in
example.com, they click a "Log in with IDP" button.registeredand the credential from last time has not expired, they are immediately logged in.registrationStep 2.Alternatively, via new web UI patterns:
example.com, they click a "Log In" button.registeredany Credentials with this site (of any variety) the user may select from them in browser UI.federated3credential, proceed to Log in Step 2.RP Log out
example.com, they click the "Log Out" button.example.com.What is the Expected RP (or IDP Library) Developer Experience?
Linking
Registrationnavigator.credentials.createwith argument keycredential3can specify [1,n] different supported identity providers.registerationrequest.navigator.credentials.storethe result fromnavigator.credentials.createto remember the user as logged in.Log in
navigator.credentials.getwith argument keycredential3can specify [1,n] different supported identity providers.registeredwith one on this site before, then the user is logged in and you will receive a blob of data from the IDP.re-registerwith the IDP for more permissions.navigator.credentials.storethe result fromnavigator.credentials.createto remember the user as logged in.RP Log out
navigator.credentials.preventSilentAccess().What is the Expected IDP Developer Experience?
Log in
Add a call to any authentication page that:
Log out
Add a call to any logout callback that:
How this is Accomplished in Specification?
In order to get the above UX and DX, we need to make only the following changes to the web platform.
This proposal has three key parts, each presented in
A new Permission
We add a new permission, say
federated-authenticationwhich is keyed on the origins of the RP and IDP.Its semantics are that it represents permission for an RP to enter login flows, such as popup, with a given IDP.
A defined Federation Login Status API
We need to have a defined subset of the Login Status API. I propose we introduce at least a subset of it here:
dictionary LoginStatusRequest { required string relying_party_origin; string request_blob; } [Exposed=Window, SecureContext] interface LoginStatus { Promise<LoginStatusRequest?> pendingFederatedLoginRequest(); void completeFederatedLoginRequest(string? response_blob); }This can integrate with any other Login Status API implementation to allow calls to
completeFederatedLoginRequestto set logged in status for the RP and IDP.A new Credential
Finally, we need a new credential type that has the blob from the IDP's call to
completeFederatedLoginRequestand options to request it.Its
[[discovery]]would be"remote"and[[type]]would be"federated3".This credential would define its
[[CollectFromCredentialStore]]and[[Store]]methods to allow storing and retrieving of credentials within the same origin.This credential would define its
[[Create]]method to perform linkingregistration. This would be something akin to:LoginStatusRequestwith the blob the RP provided and the RP's origin.loginURLchosen, optionally matching the RP requestedstyle.completeFederatedLoginRequestin the IDP page.federated-authenticationpermission for (RP, IDP).completeFederatedLoginRequest.This credential would define its
[[DiscoverFromExternalSource]]method to be what happens whennavigator.credentials.getis called, but the user is not currently logged in.federated-authenticationpermission for (RP, IDP)[[Create]]with the same arguments.Open questions
I think the answer to all of these is yes, with some work.
Out of scope