Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
213 changes: 213 additions & 0 deletions files/en-us/web/security/authentication/federated_identity/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
---
title: Federated identity
slug: Web/Security/Authentication/Federated_identity
page-type: guide
sidebar: security
---

In a **federated identity** system, a website delegates authentication to a third party.

- The third party, which is commonly called an {{glossary("identity provider", "Identity Provider (IdP)")}}, manages a user's credentials and can authenticate users.
- The website, which is commonly called a {{glossary("relying party", "Relying Party (RP)")}}, trusts the IdP to make assertions about a user's identity.

When the user wants to sign into the website, the website redirects them to the IdP. The user authenticates to the IdP, and the IdP returns a token to the website indicating that the user authenticated successfully. The website checks that the token is valid, and if it is, signs the user in.

![Overview of federated identity sign-in.](federated-identity-overview.svg)

> [!NOTE]
> Federated identity is not really an authentication _method_: it's more like an _architecture_ within which various different authentication methods could be used. That is, an IdP could choose to authenticate users with one or more methods, such as traditional passwords, one-time passwords, biometrics, or passkeys.
This model has some benefits for both users and websites:

- Websites don't have to implement their own authentication, or securely handle user {{glossary("credential", "credentials")}}.
- A single IdP can authenticate users for many different websites. This means that the user doesn't have to use a different credential for each site: if credentials are passwords, this reduces the risk of password reuse or the user choosing weak, easy-to-remember passwords.
- If a user already has an account with an IdP that your website trusts to authenticate users, then it's much easier for users to sign up to your site, because they don't need to get new credentials specifically for your site.

In this guide we'll explore how a website can work with an IdP to add federated sign-in for their users. We'll cover:

- The main flows defined in the [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/) protocol, which is the dominant standard for federated identity, and good practices to follow when implementing them.
- Third-party services that can simplify the process of implementing federated identity.
- How browser restrictions on third-party cookies create problems for federated identity implementations.
- The [Federated Credential Management (FedCM) API](https://developer.mozilla.org/en-US/docs/Web/API/FedCM_API), which makes the browser's role much more active, to simplify the role of the RP and avoid relying on third-party cookies.

## OpenID Connect

The standard most commonly used for federated identity on the web is [OpenID Connect (OIDC)](https://openid.net/developers/how-connect-works/), which is an authentication protocol built on top of the [OAuth 2.0 authorization framework](https://datatracker.ietf.org/doc/html/rfc6749).

### Authentication flow

In this section we'll start by walking through the main authentication flow defined in OIDC. There are many options within the OIDC authentication flow: in this walkthrough we'll present the recommended options, and we will talk later about alternatives.

This flow is defined in the [OpenID Connect Core](https://openid.net/specs/openid-connect-core-1_0.html) specification.

As a prerequisite, the RP needs to be known to the IdP: the IdP needs to have an ID for the RP, which is called a client ID, and the RP must be able to authenticate itself to the IdP, for example using a shared secret called a client secret or using some other mechanism such as TLS client authentication.

> [!NOTE]
> The OpenID specifications use the term "OpenID Provider" (OP) to refer to what we call an IdP in this guide.
![The OIDC authentication flow](oidc-auth-flow.svg)

The first thing to note here is that the flow consists of two parts.

- **Authentication request**: the RP asks the IdP to authenticate the user by making a request to the IdP's _authorization endpoint_. The IdP authenticates the user and returns an _authorization code_ to the RP. The code expires after a short period of time (recommended to be no more than 10 minutes).
- **Token request**: the RP sends the authorization code to a separate endpoint in the IdP, called the _token endpoint_, and this endpoint responds with an object containing two tokens:
- An _access token_, which enables the user to access specific resources in the website (like an API key)
- An _ID token_, which identifies the user, and enables the RP to sign the user in.

In the authentication request:

1. The user asks to sign into the RP.

2. The RP redirects the browser to the IdP's authorization endpoint, asking it to authenticate the user. The RP can provide various parameters along with the request, including:
- `client_id`: Identifies this RP to the IdP.
- `response_type`: Always `"code"` if we are using the two-part flow described here, which is the recommended option.
- `redirect_uri`: The URL in the RP, that the IdP should redirect to once it has attempted to authenticate the user. This is the URL to which the IdP will deliver the authorization code.
- `code_challenge`: A cryptographic {{glossary("hash")}} of a secret specific to this authorization request, which will be used by the token endpoint to ensure that the token request is really the counterpart of this authorization request.
- `scope`: A list of strings that specify which sets of user data the RP wishes to access.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Practically" what might be in the scope is not clear. I assume this perhaps means email addresses and such. Not sure whether it matters.


3. The IdP authenticates the user. The protocol does not specify a particular method for this: the IdP could use a password, a one-time password, a biometric, or any other appropriate method.

4. If authentication is successful, the IdP generates the authorization code. It also stores the `code_challenge` value, and associates it with the authorization code. The IdP then redirects the browser to the RP's redirect URL, passing the authorization code as a parameter.

In the token request:

1. The RP makes a {{httpmethod("POST")}} request to the token endpoint. This request includes the following parameters:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. The RP makes a {{httpmethod("POST")}} request to the token endpoint. This request includes the following parameters:
1. The RP makes a {{httpmethod("POST")}} request to the IdP's token endpoint. This request includes the following parameters:

- `client_id`: Identifies this RP to the IdP.
- `client_secret`: The secret used to authenticate the RP to the token endpoint. The RP could use some alternative mechanism for client authentication, such as TLS client authentication.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Presumably this is just a number right? Presumably this is all done via HTTPs so it can never leak?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, just an opaque value. And yes, everything over HTTPS. I didn't say that because it feels like the default. Worth spelling out do you think?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth implying it can be any value maybe, but not that it needs to be HTTPs.

So maybe "The secret used to authenticate the RP to the token endpoint; this can be any value agreed between the RP and IdP."

In "The RP could use some alternative mechanism for client authentication, such as TLS client authentication." The "RP could use" reads as though the RP is doing the authentication and deciding what the authentication is. If that is correct then cool, but I assumed that this was to identify the RP to the IdP - so it is the IdP doing the authentication of the client.

Does this make sense as a question/ambiguity?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have tried using different/more words in f97f769, I'm not sure if it is clearer or not.

- `grant_type`: This should be `"authorization_code"`.
- `code`: The authorization code.
- `code_verifier`: This is the original secret that was used to produce the `code_challenge` parameter in the authentication request.

2. The IdP validates the request:
- It authenticates the RP using client authentication.
Copy link
Collaborator

@hamishwillee hamishwillee Nov 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps something along the lines of

Suggested change
- It authenticates the RP using client authentication.
- It authenticates that the request is from the particular RP using the client secret or some other form of client authentication.

- It hashes the `code_verifier` parameter, and then checks that the result matches `code_challenge`.

3. If the request is valid, the IdP responds with two tokens:
- An access token, which grants the user access to some resource in the RP.
- An ID token, which identifies the user. This is a cryptographically signed [JSON Web Token](https://www.jwt.io/).

4. The RP validates the tokens: among other checks, it verifies the IdP's signature on the ID token. If validation succeeds, the RP signs the user in.

### Security features

In this section we will summarize the main security features of the OIDC authentication flow we've just described.

#### Authorization code flow

The two-step flow we have described is called the "authorization code flow". In an alternative flow, called the "implicit flow", only the first step exists, and the response to the authentication request already contains the access and ID tokens. This is unsafe, because the tokens are exposed to the RP's front end, which is regarded as much less secure than the back end. For example, in a successful [XSS](/en-US/docs/Web/Security/Attacks/XSS) attack, or if the user installs a malicious browser extension, then the attacker might be able to steal the user's tokens.

For this reason, websites should always use the authorization code flow. Even if an attacker can steal the authorization code, they still need to convince the token endpoint to give them the tokens in exchange for the code.

#### Client authentication

In the flow we have described, the RP authenticates itself to the token endpoint when it makes the token request. This means that if an attacker does manage to steal the authorization code, it still has to successfully impersonate the RP to get the tokens from the IdP.

The OAuth specification distinguishes between [_confidential_ and _public_ clients](https://datatracker.ietf.org/doc/html/rfc6749#section-2.1). Confidential clients are essentially clients that can keep a secret, and public clients are those that can't.

The specification considers that clients running on the user's browser are public clients, for the same reason we've already encountered: it's too easy for an attacker to access secrets in a browser via attacks such as XSS. Clients running on a web _server_ are confidential clients.

In OIDC, only confidential clients may use client authentication, because only confidential clients can be trusted to maintain the security of the client's credentials.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe here we are using the term client authentication to mean "RP authenticating its identity to the IdP. It feels like at this point we're using the term client without having ever defined what a client is in this context.

This is kind of what I was getting to in https://github.com/mdn/content/pull/41779/files#r2548032506

I don't know if you agree this needs to be f"ixed", but perhaps here.

Suggested change
In OIDC, only confidential clients may use client authentication, because only confidential clients can be trusted to maintain the security of the client's credentials.
In OIDC, only confidential clients, such as the RP server, may can authenticate themselves as clients of the IdP, because only confidential clients can be trusted to maintain the security of the client's credentials.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in OAuth/OIDC, "client" always means RP.

Maybe I could extend the note at the start of https://pr41779.review.mdn.allizom.net/en-US/docs/Web/Security/Authentication/Federated_identity#authentication_flow, to mention this as well as IdP->OP. And maybe in this section, when I say:

The OAuth specification distinguishes between confidential and public clients. Confidential clients are essentially clients that can keep a secret, and public clients are those that can't.

I could instead say

The OAuth specification distinguishes between confidential and public clients. Confidential clients are essentially RPs that can keep a secret, and public clients are those that can't.

...just to reinforce the usage in this section.

I don't particularly want to say things like "client (which means the RP) everywhere", it will get tortured.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe add it just once in the first sentence - styled as code to highlight

In the flow we have described, the RP ("client") authenticates itself to the IdP's token endpoint when it makes the token request. This means that if an attacker does manage to steal the authorization code, it still has to successfully impersonate the RP to get the tokens from the IdP.

That makes it very clear what the client is for client authentication. I would also be happy with "as well", your suggestion:

The OAuth specification distinguishes between confidential and public clients. Confidential clients are essentially RPs that can keep a secret, and public clients are those that can't.


#### Proof Key for Code Exchange (PKCE)

The `code_challenge` and `code_verifier` values that the RP provides in the authentication request and token request, respectively, are part of a mechanism called _Proof Key for Code Exchange_ (PKCE), specified in {{rfc("7636")}}.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps pull the sentence from the end https://github.com/mdn/content/pull/41779/files#r2548065911 to be clear up front why users should care about PKCE.

Suggested change
The `code_challenge` and `code_verifier` values that the RP provides in the authentication request and token request, respectively, are part of a mechanism called _Proof Key for Code Exchange_ (PKCE), specified in {{rfc("7636")}}.
The `code_challenge` and `code_verifier` values that the RP provides in the authentication request and token request, respectively, are part of a mechanism called _Proof Key for Code Exchange_ (PKCE), specified in {{rfc("7636")}}.
This mechanism defends against two attacks: [CSRF against the RP's redirect URL](#csrf_against_the_redirect_url), and [authorization code injection](#authorization_code_injection).

You might then have to have "In the PKCE authentication request"


In the authentication request:

- The RP generates a value that is hard to guess and is specific to this authentication request. This value is called the _code verifier_.
- The RP creates a {{glossary("hash", "cryptographic hash")}} of the code verifier, and uses it as the `code_challenge` parameter in the authentication request.
- The IdP stores the code challenge, and associates it with the access code that it returns to the RP.

In the token request:

- The RP passes the code verifier in the _code_verifier_ parameter.
- The IdP hashes the code verifier, and compares the result with the stored code challenge: if they do not match, then the token request is denied.

This defends against two attacks: CSRF against the RP's redirect URL, and authorization code injection.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Link to attack page for CSRF

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-> 412b8ef


The CSRF attack works as follows:

1. The attacker makes an authentication request to the IdP for themselves, and gets back an authorization code for their own tokens.

2. The attacker tricks the user's browser into making an HTTP request to the RP's redirect URL, including the attacker's authorization code. To the RP, this looks like a response from the IdP to an authentication request originating from the user.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth numbering the point of injection on the preceding flow so it is easier to see what is happening (just thinking aloud)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure exactly what change is needed here.


3. The RP makes a token request to the IdP, including the attacker's authorization code.

4. The IdP responds with the attacker's tokens.

5. The RP signs the user into the attacker's account: now any information or instructions they provide are under the attacker's control.

Essentially, the attack succeeds because the RP doesn't know that the authentication response is not a response to a request made on behalf of the user. PKCE prevents this attack because the IdP would have a stored code challenge for the attacker's access code, and this would not match the code verifier that the RP passes into the token request.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If possible, it might be nice to capture a flavour of your comment below here:

Why can't the attacker steal the user's code verifier too? Because it's never exposed to the front end, it only ever lives in the RP, server-side.

An alternative protection against this attack is the `state` parameter defined in OAuth 2.0. In this defense, the RP provides an unpredictable value as a parameter in the authentication request, and the IdP includes the same value in the response: the RP checks that they match. Because the attacker can't predict the value of `state`, they can't pass a matching value to the RP's redirect URL.

In the authorization code injection attack:

1. The attacker is able to steal the user's authorization code.

2. The attacker starts its own OIDC authentication flow, but intercepts the IdP's authentication response, replacing the authorization code with the code it stole from the user. This is straightforward, because the authentication response is for the attacker, so it passes through the attacker's device.

3. The RP then continues its authentication flow for the attacker by making the token request to the IdP, including the user's authorization code that the attacker has injected.

4. The IdP responds with the user's tokens.

5. The RP signs the attacker into the user's account.

Note that this is really the inverse of the CSRF attack. Note also that the `state` parameter doesn't help here, because the authentication request and response really do belong to the same flow - the attacker's.

PKCE protects against this attack, because the IdP's token endpoint will check the `code_verifier` in the token request against the code challenge that it received in the authentication request.

- Because the IdP's stored code challenge is associated with the authorization code, it will be the challenge for the user.
- Because the `code_verifier` in the token request is part of the attacker's flow, it will be the verifier for the attacker.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is meant by ", it will be the challenge for the user." and " it will be the verifier for the attacker.". I can tell this is "the point", but I don't get it.

I think you're saying that

  • when the authorization request was made for the stolen auth code it included a code_challenge, (which is a hash of the RP code verifier) is stored by the idp and associated with the code.
  • the auth code gets passed into the flow just before the token request. My understanding is that the RP would include the code_verifier which is a hash of its original challenge
  • But what happens now is a mystery, because the RP only knows its original request, so presumably that is the correct code_verifier for the original challenge.

I suspect that "t will be the challenge for the user" means that somehow the RP associated the code_verifier that it sends with the token with the user, so when the attacker injects itself into the flow it will have some (or no) code_verifier associated with it.

Whatever the case, I'm not sure the relationships are clear enough.

Copy link
Collaborator Author

@wbamberg wbamberg Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps it's clearer if we start earlier, with the user's flow. And lets look at how it works without PKCE, first.

  1. the legitimate user tries to sign in
  2. the RP makes an authentication request to the IdP
  3. the IdP authenticates the user and sends the authorization code
  4. BUT the user has installed a malicious extension, that steals the code, sends it to the attacker, and terminates the user's flow. The user just thinks "something went wrong".
  5. now the attacker has the authorization code. But they can't just make a token request directly, because of client authentication (the attacker can't impersonate the RP).
  6. so instead, the attacker starts their own authentication flow with the RP.
  7. when the IdP sends them the authorization code, they intercept the redirect and replace their code with the the user's code that they stole. Remember, the user's code is for the user's tokens.
  8. next, the RP processes the next step of the attacker's flow, which is the token request. But they're sending the user's code, so it returns the user's tokens to the attacker's flow. Result: the attacker is signed into the user's account

Basically the attack is just the attacker signing in, but splicing in the user's auth code.

(It's the inverse of CSRF, because with CSRF it's the user signing in, but splicing in the attacker's auth code.)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, so in the token request the code_verifier cannot be hashed to the code challenge, because the code challenge was produced in the users original authoriseation flow thingy?

Thanks you. Makes sense.

Now you're going to have to think "did Hamish need me to go through that because it was unclear or because he is an idiot". I think there is room for improvement. But if you want me to suggest something might need to wait until Friday.

Copy link
Collaborator Author

@wbamberg wbamberg Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With PKCE:

  1. the legitimate user tries to sign in
  2. the RP makes an authentication request to the IdP. -> the RP generates a code verifier, and sends the hashed verifier (i.e. the challenge) to the IdP.
  3. the IdP authenticates the user and sends the authorization code ->the IdP stores the code challenge with the user's code
  4. BUT the user has installed a malicious extension, that steals the code, sends it to the attacker, and terminates the user's flow. The user just thinks "something went wrong".
  5. now the attacker has the authorization code.
  6. the attacker starts their own authentication flow with the RP. ->the RP generates a new code verifier, and the IdP stores this new code challenge next to the attacker's code
  7. When the IdP sends them the authorization code, they intercept the redirect and replace their code with the the user's code that they stole. Remember, the user's code is for the user's tokens.
  8. next, the RP processes the next step of the attacker's flow, which is the token request. ->the RP sends the attacker's code verifier and the user's code. The IdP looks up the user's code, finds the user's verifier, and it doesn't match the code verifier it was passed. So it returns an error.

Why can't the attacker steal the user's code verifier too? Because it's never exposed to the front end, it only ever lives in the RP, server-side.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"did Hamish need me to go through that because it was unclear or because he is an idiot"

It's hard. It took me a while. One challenge is that using more words and taking it step by step helps, but I don't want to spend too many words on this. Another is that once you understand it, it makes sense, and it's hard to know if your explanation makes sense to someone else who doesn't understand it yet! I do think I have probably tried to compress it too much here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

However, I'm pretty sure that omitting the user's initial flow is a mistake, and perhaps including that is enough for this to make sense?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK I have tried in 412b8ef to clarify the auth code injection attack and defense.

BTW there is a great presentation on this attack here: https://www.youtube.com/watch?v=moQidjdV5cw , probably I should include this too. But I'd appreciate if you can see if the words make sense before watching this :).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made some whiny comments, that don't take away from the fact that this is IMO crystal clear now.


So the codes won't match, and the token request fails.

An alternative to PKCE, specified in OIDC, is the [`nonce`](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-security-topics#name-nonce) value. The RP includes this as another parameter in the authentication request: the IdP stores it, and the token endpoint returns it to the RP along with the tokens. The RP then checks that the returned value is the same as the original value.

### Architectures for OIDC clients

The [OAuth 2.0 for Browser-Based Applications](https://datatracker.ietf.org/doc/html/draft-ietf-oauth-browser-based-apps-25) specification describes how web application architecture can affect the security threats faced by OIDC clients (that is, relying parties), and makes some recommendations for web application architecture.

In particular, it finds that:

- The most secure pattern is one in which the website uses a web server to handle all OAuth/OIDC interactions and interactions with APIs that are protected by access tokens. In this pattern, the RP can be a confidential client, because it can keep client secrets in the server. It can also keep all tokens in the server, including access tokens.

- The next most secure pattern is one in which the website uses a web server to handle all OAuth/OIDC interactions, but then returns the access token to the front end, and the front end then makes API requests directly. In this scenario the website can be a confidential client but malicious code running in the browser (for example, through an XSS attack) can potentially steal access tokens. However, the front end doesn't have to store access tokens long-term: it can retrieve them from the backend when it needs them.

- The least secure pattern is one in which OAuth/OIDC interactions and interactions with APIs both take place in the front end. This, for example, would be the natural architecture for a {{glossary("SPA", "Single-page app")}}, where the entire application executes in the browser. In this architecture the RP can't be a confidential client, because it can't reliably keep a client secret. This means that it can't authenticate itself to the IdP. It also has to persistently store tokens, which increases the risk of malicious code stealing them.

The specification also includes detailed recommendations for security practices to follow in each of these three scenarios.

### OIDC sign-out

Sign-out scenarios are more complex in a federated identity system than in a non-federated system, because:

- The user might sign out of the RP either on the RP's site or on the IdP's site.
- The user might choose to sign out of the RP only, or to sign out globally: that is, to sign out of all RPs that they are signed into with this IdP. This is a common requirement when we use federated identity to build a {{glossary("single sign-on", "single sign-on (SSO)")}} system, in which an employee might use a single set of corporate credentials to sign into email, a bug tracker, and a discussion forum.

Supporting these scenarios means implementing some communication mechanism between the RP and the IdP. For example:

- If the user signs out at the IdP, then the RP should be notified, and sign the user out in the RP.
- If the user signs out at the RP, then the IdP should be notified, and be able to sign the user out of all RPs that they are currently signed into.

The OpenID specifications define two general approaches to implementing this coordination, which they call "front channel logout" and "back channel logout".

In [front channel logout](https://openid.net/specs/openid-connect-frontchannel-1_0.html), the browser is used to mediate the communication, by embedding an {{htmlelement("iframe")}} in a page from the sender, whose content is loaded from the recipient. For example, if the user signs out at the IdP, the IdP may embed an `<iframe>` whose `src` attribute points to the RP's logout URL: when the `<iframe>` is rendered, the browser makes a {{httpmethod("GET")}} request to that URL, which the RP interprets as an instruction to sign the user out.

In [back channel logout](https://openid.net/specs/openid-connect-backchannel-1_0.html), the RP and the IdP communicate directly with each other, bypassing the browser.

## Identity providers

## Third-party cookies

When implementing a federated identity system, we have to coordinate the interactions between the RP, the IdP, and the user. Some implementations of this coordination depend on browser support for [third-party cookies](/en-US/docs/Web/Privacy/Guides/Third-party_cookies).

For example, in front-channel logout (one of the approaches to implementing [sign-out in OpenID Connect](#oidc_sign-out)) we use cross-site {{htmlelement("iframe")}} elements, in which the RP's document contains an `<iframe>` whose content is loaded from the OP, or vice versa. This depends on the embedded `<iframe>` being able to send its cookies to its origin.

Similarly, while the main [OpenID Connect authentication flow](#authentication_flow) uses full-page redirects to coordinate between the participants, this is a distracting experience for users and is difficult for {{glossary("SPA", "single-page apps")}} to support. A better user experience can be achieved by embedding the IdP as an `<iframe>` in the RP's page, and this again depends on third-party cookies.

However, because third-party cookies are widely used for [tracking users](/en-US/docs/Web/Privacy/Guides/Third-party_cookies#what_is_the_problem_with_third-party_cookies), browsers have taken steps to deprecate and remove support for them, and they are now not supported by default in some browsers.

As such, we don't recommend implementing federated identity features in a way that depends on third-party cookies.

## The FedCM API
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading