Skip to content

Commit

Permalink
Major restructuring pass of non-core elements of the specification (#418
Browse files Browse the repository at this point in the history
)

* Major restructuring pass of non-core elements of the specification

This set of changes attempts to improve the clarity and structure of
the specification outside of the IDP API and Browser API sections.

This should address the following issues from Issue #416: 1-6, 10, 11, 14, 17, 18, 20, 21.

The Markdown files added here are drafts- converting Bikeshed to Markdown is non-trivial and
since they are targetting a return to the core spec it may not be worth the effort to make
a good looking version of the Markdown before creating a PR for them.

* Adopting review from @npm1 and @samuelgoto
  • Loading branch information
bvandersloot-mozilla authored Feb 7, 2023
1 parent bb97791 commit 9d6851a
Show file tree
Hide file tree
Showing 4 changed files with 531 additions and 801 deletions.
80 changes: 80 additions & 0 deletions explainer.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,86 @@ Features which are out-of-scope for the **current** version of FedCM, but are
* Replace OIDC / SAML / OAuth: these efforts should continue to thrive by
offering a better identity-specific foundation

## Use Cases

The below use case scenarios illustrate some basic supported flows. Each
supported flow below occurs inside an iframe or in an XHR request.


### Sign-up

A Sign-up occurs when the user is registering a new account at the
Relying Party using their Identity Provider.

For instance, a user navigates to a Relying Party in their browser
and creates an account. The Relying Party displays supported
Identity Providers to the user who selects their favorite. The user
is prompted "Do you want to sign up on the Relying Party with the Identity Provider?".
Upon user agreement an account is created with the Identity Provider and
the user has a session initialized on Relying Party.

### Sign-in

After a user navigates to a Relying Party in a browser and creates an
account by going through their sign up flow, the user can
sign into their account once their session expires.

A sign-in occurs when the Identity Provider believes it is
necessary to gather an explicit permission from the user to sign into a
Relying Party, typically after the user goes through a
sign out flow.

For example, after the user has done the sign out flow of the
Relying Party they decide to log in again. The user visits the
Relying Party and selects their Identity Provider to sign-in. The
Identity Provider knows:
* the user already has an account with the Relying Party.
* the user has logged out of the Relying Party.

The user is then prompted, "Do you want to sign in on the Relying Party with the Identity Provider?"
and upon user agreement the Relying Party creates a new session with
the users existing account.

#### RP Sign-out

The user can log out through the Relying Party by using a provided
sign-out button or link provided by the Relying Party. This then
removes the user's session and, when the user visits the Relying Party
again they will need to go through the sign in flow
in order to establish a new session.

#### IDP Sign-out

The user can log out through the Identity Provider by using a provided
sign-out system provided by the Identity Provider. After using the
sign-out system the Identity Provider will log the user out of all
Relying Parties the user has signed into along with logging the user
out of the Identity Provider itself. Upon returning to any associated
Relying Party, the user will need to sign in with the Identity Provider
first and go through the sign in flow on the Relying Party.

### Revocation

After a user has created an account on a Relying Party there are two
ways a user can cancel their account with the Relying Party:

#### RP Revocation

The user can delete their account through the Relying Party by using
the provided account revocation system. The Relying Party informs the
Identity Provider that the user has deleted (revoked) their account.
When the user returns to the Relying Party they will need to complete
the sign up flow in order to access the site.

#### IDP Revocation

The user can delete their account with a Relying Party by revoking
Relying Party access through the Identity Provider. This can be done
by going to the Identity Provider and using their revoke access system.
Once access is revoked, when the user returns to the Relying Party they
will need to complete the sign up flow in order to access the
site.

## Example

The following is an example of a website allowing a user to login with
Expand Down
123 changes: 123 additions & 0 deletions proposals/idp-sign-out.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@

# IDP Front-Channel Sign-out

Note: The API specified in this section is not launched in any user agent,
and as such should be considered very experimental and subject to change.

In enterprise scenarios, it is common for the user to want to clear all of
their existing sessions in all of the RPs they are logged into.

It does so by being navigated to their IDP who initiates
what's called a Front-Channel-Logout.

The browser exposes an API that takes the list of [=RP=]s that the
IDP wants to initiate the logout which are loaded in parallel
with cookies.

Each RP endpoint is responsible for clearing its local state
(e.g. clearing cookies).

```
.---------------------------------. .---------------------------------.
| .-----------------------------. | | .-----------------------------. |
| | "https://rp.example" | | | | "https://idp.example" | |
| '-----------------------------' | | '-----------------------------' |
| .-----------------------------. | | .-----------------------------. |
| | | | | | | |
| | Welcome to my website! | | | | John, we are logging out | |
| | | | | | of the relying parties. | |
| | | | | | | |
| +-----------------------------+ | | | +~~~~~~~~~~~~~~~~~~~~~~~+ | |
| | Sign-in to rp.example | | | | :"<script>" : | |
| | with idp.example? | | | | :" IdentityProvider. ": | |
| | | | | | :" logoutRPs([{ ": | |
| | .----. | | | | :" url: ... ": | |
| | | :) | "John Doe" | | --> | | :" accountId: ...": | |
| | '----' "john@email.com" | | | | :" }, { ": | |
| | | | | | :" ... ": | |
| | +-------------------------+ | | | | :" }]); ": | |
| | | Continue as John | | | | | :"<\/script>" : | |
| | +------------+------------+ | | | | +~~~~~~~~~~~+~~~~~~~~~~~+ | |
| '--------------|--------------' | | '--------------|--------------' |
'----------------|----------------' '----------------|----------------'
| |
| |
| +------------------------+ | +-------+
| | | | | |
+------->| Registered RPs |-------+------->| Queue |
| | | |
+------------------------+ +-------+
```

```js
await IdentityCredential.logoutRPs([{
url: "https://rp1.example",
accountId: "123"
}, {
url: "https://rpN.example",
accountId: "456"
}]);
```

IDPs can call `IdentityCredential.logoutRPs()` to log the user out of the RPs they are
signed into.


```idl
dictionary IdentityCredentialLogoutRPsRequest {
required USVString url;
required USVString accountId;
};
[Exposed=Window, SecureContext]
partial interface IdentityCredential {
static Promise<undefined> logoutRPs(sequence<IdentityCredentialLogoutRPsRequest> logoutRequests);
};
```


Proposed algorithm in bikeshed:

```
When the {{IdentityProvider/logoutRPs()}} method is invoked given a [=list=] of
{{IdentityCredentialLogoutRPsRequest}}s |logoutRequests|, the user agent MUST execute the following
steps. This returns a {{Promise}}.
1. Let |promise| be a new {{Promise}}.
1. Let |globalObject| be <a>this</a>'s <a>relevant global object</a>.
1. [=In parallel=], perform the following steps:
1. For each |request| in |logoutRequests|:
1. Let |rpOrigin| be [=this=]'s [=Document/origin=].
1. Let |idpOrigin| be |request|'s {{IdentityCredentialLogoutRPsRequest/url}}'s [=/origin=].
1. Let |account| be |request|'s {{IdentityCredentialLogoutRPsRequest/accountId}}.
1. Let |triple| be (|rpOrigin|, |idpOrigin|, |account|).
1. If [=state machine map=][|triple|] does not exist, continue.
1. Let |accountState| be [=state machine map=][|triple|].
1. If the |accountState|'s {{AccountState/registration state}} is {{unregistered}} or
|accountState|'s {{AccountState/allows logout}} is false, continue.
1. Let |fetchRequest| be a new <a spec=fetch for=/>request</a> as follows:
: [=request/url=]
:: |request|'s {{IdentityCredentialLogoutRPsRequest/url}}
: [=request/mode=]
:: "GET"
: [=request/redirect mode=]
:: "error"
: [=request/client=]
:: null
: [=request/window=]
:: "no-window"
: [=request/service-workers mode=]
:: "none"
: [=request/destination=]
:: "webidentity"
: [=request/origin=]
:: a unique [=opaque origin=]
: [=request/credentials mode=]
:: "include"
1. [=Queue a global task=] on the [=network task source=] given |globalObject|
to [=fetch=] |fetchRequest|.
1. Set the |accountState| {{AccountState/allows logout}} to false.
1. [=Resolve=] |promise| with [undefined].
1. Return |promise|.
```
Loading

0 comments on commit 9d6851a

Please sign in to comment.