Skip to content

Verified against Salesforce docs: September 2026

SAME_​ORG_​SSO: Why One Experience Cloud Site Cannot Be an Identity Provider for Another

Salesforce blocks OIDC between two Experience Cloud sites in one org. Why a site is not an identity authority, and why SAML is the one route still open.

TL;DR

  • Pointing one Experience Cloud site at another in the same org as an OIDC identity provider fails with ErrorCode=SAME_ORG_SSO, Cannot sign on into same org. There is no setting that turns it off.
  • The reason is structural. An Experience Cloud site is not an identity authority. It is URL and issuer-string scoping over the org's single identity service.
  • The proof is in the keys. The site's JWKS endpoint and the org's return the same key set, including a key id that embeds the org id.
  • Configuring the site correctly as the identity provider does not help, and it is worth knowing that the configuration can be entirely right while the outcome stays impossible.
  • Different subdomains and custom domains do not help. The guard compares org ids, and an org id is not a URL.
  • SAML is the one route with a real chance, because it resolves the user from the assertion's subject and never asks which org the identity belongs to. If nothing resolves an org, the same-org guard has nothing to fire on.

What You'll Learn

  • What SAME_ORG_SSO actually means and why no amount of configuration clears it
  • How to prove a site is not a separate identity authority, in two commands
  • The three errors that sit in front of this one, each hiding the next
  • Why custom domains look like a fix and are not
  • Why SAML differs from OIDC here in a way that matters, and what the remaining caveat is
  • The route that does work when you genuinely need one site to broker sign-in to another

The Problem

You have two Experience Cloud sites in one org. You want a user who is signed in to the first to reach the second without signing in again, and you want to do it properly, through a standards-based flow rather than a link that quietly hands over a session.

OpenID Connect is the obvious choice. Salesforce supports it in both directions. A site can act as an OIDC provider, exposing its own discovery document, authorize endpoint, token endpoint and JWKS. A site can also consume an external identity provider through an Auth Provider. So you configure the first site as the provider, the second as the consumer, and expect to be finished in an afternoon.

You will not be. The flow dies at the last step with an authorization error:

/<site>/_nc_external/identity/sso/ui/AuthorizationError
  ?ErrorCode=SAME_ORG_SSO&ErrorDescription=Cannot+sign+on+into+same+org

This is a platform guard, not a misconfiguration. Salesforce will not let a site authenticate against an identity provider that resolves to the same org that site lives in. No toggle disables it.

The reason this costs so much time is that the guard sits behind three other failures, each of which produces a different error and each of which looks like the whole problem while you are staring at it. You fix a redirect URI, then an issuer mismatch, then a CSRF failure, and each fix feels like progress because the error genuinely changes. Only when all three are cleared does the real answer become visible.

Common questions this article answers:

  • What does SAME_ORG_SSO mean and can I turn it off?
  • I configured the site as the identity provider rather than the org. Why does it still fail?
  • Will a custom domain or a different subdomain get around it?
  • Is SAML any different, and what would it take to test?

Quick Answer

Two Experience Cloud sites in one Salesforce org cannot use OIDC between them. Salesforce refuses with SAME_ORG_SSO because the identity the consuming site resolves belongs to the same org it is running in. You cannot configure your way out, because an Experience Cloud site is not a separate identity authority: it is URL and issuer-string scoping over the org's one identity service. Fetch https://<domain>/<site>/id/keys and https://<my-domain>/id/keys and compare them, and you will find the same key set, including a key id containing the org id. That is the whole explanation. The id_token's iss is the site, so signature validation passes, but the identity behind it is the org's, so userinfo returns the org id and the consumer refuses. Custom domains change the issuer string and the endpoint hosts without giving the org a second identity, so they do not help. The route with a real chance is SAML, which resolves the user from the assertion's subject through SamlUserIdType matched on Federation Id or username, and never asks which org the identity came from. If you need a broker today, use an identity authority that is genuinely different: another org, or an external IdP both sites already trust.

The three errors in front of the real one

Keep these, because each hid the next and the sequence is the same every time.

redirect_uri_mismatch

The first failure comes from the callback URL. An Experience Cloud site serves pages under a site prefix, and the redirect URI registered with the provider has to match the prefix the browser is actually on, exactly. A URI that works from one site path fails from another that differs only by prefix.

This one is real and worth fixing, but it tells you nothing about whether the overall design is viable. It is a registration detail.

Id_Token_Error, the wrong issuer

Once the callback lands, the consumer validates the id_token. If the Auth Provider's configured token issuer does not match the iss claim in the token, validation fails.

The fix is to set the issuer to the site-prefixed value rather than the org's My Domain, because a site publishing its own discovery document issues tokens under its own issuer string. After that, validation passes and keeps passing.

This is the most instructive of the three, because it is genuine evidence that site-as-issuer is a real thing the platform supports. Salesforce would not accept a token whose iss is the org's My Domain against an issuer string naming the site. It really is site-scoped, which is exactly why the eventual failure is so counterintuitive.

CSRF mismatch on a cold start

The third is a state parameter failure on a cold start, and it is downstream of the other two rather than independent. Once the earlier problems are fixed and the flow is not restarting mid-handshake, it stops.

Clear all three and you finally see SAME_ORG_SSO, which is the one that does not move.

The site really is configured as the identity provider

Before concluding that anything is misconfigured, it is worth establishing that it is not, because this is where most of the time goes. Three independent confirmations, all of which you can check yourself.

The Auth Provider points at the site's endpoints. AuthorizeUrl, TokenUrl and UserInfoUrl all carry the site prefix rather than a bare My Domain host.

The site publishes its own OIDC discovery document, with its own issuer:

curl -s "https://<domain>/<site>/.well-known/openid-configuration" | python3 -m json.tool
issuer                  https://<domain>/<site>
authorization_endpoint  .../<site>/services/oauth2/authorize
token_endpoint          .../<site>/services/oauth2/token
userinfo_endpoint       .../<site>/services/oauth2/userinfo
jwks_uri                .../<site>/id/keys

The id_token validates against that site issuer, which is the strongest of the three, as described above.

So the request side, the issuer string and the signature check are all site-scoped. This is site-as-IdP, correctly set up. And it still cannot work.

Why it cannot work: the keys give it away

Compare the two JWKS endpoints:

curl -s "https://<domain>/<site>/id/keys"      | python3 -c "import json,sys;print([k['kid'] for k in json.load(sys.stdin)['keys']])"
curl -s "https://<my-domain>/id/keys"          | python3 -c "import json,sys;print([k['kid'] for k in json.load(sys.stdin)['keys']])"
Site JWKS Org JWKS
Key count 6 6
Key ids 264, 262, 266, CORE_ATJWT.<org-id>.<timestamp>, ... the same

The site and the org sign with the same keys, including one whose key id literally embeds the org id. The site is a facade over the org's single identity service, not an authority of its own.

That one fact explains every symptom consistently:

  • The id_token's iss is the site, so validation passes.
  • The identity behind it is the org's, so userinfo returns the org's id.
  • Dropping the id scope changes nothing, because the org identity comes back through userinfo regardless.
  • The consuming site resolves that identity, sees its own org, and refuses.

There is one identity per org, and every site is a door onto it. No site-level configuration can make a site issue an identity that is not the org's, because there is no second identity to issue.

Why a custom domain does not rescue it

This is the next idea everyone has, and it is a good one, because the error looks like it might be about hosts. It is not.

The guard compares org ids, and an org id is not a URL.

The evidence is almost accidental. The identity URL the consuming site resolves during a failed attempt is of the form:

https://test.salesforce.com/id/<org-id>/<user-id>

That host belongs to neither site. It is not the site's domain, not the other site's domain, not my.site.com at all. The refusal happened anyway, because what the guard acted on is the org id embedded in that URL, and that id is unchanged by any domain, subdomain, custom domain or CDN you put in front of a site.

A custom domain changes the issuer string and the endpoint hosts. It does not give the org a second identity. Treat that as strong inference from the payload rather than a direct test, since testing it properly needs a real custom domain with DNS and a certificate, but the mechanism is clear enough to plan around.

SAML: the one route with a real chance

SAML is worth taking seriously here, and not as wishful thinking. It differs from OIDC in exactly the place that matters.

SAML resolves the user from the assertion's subject, matched by SamlUserIdType against Federation Id or username. It never asks the identity provider "which org is this identity from", which is precisely the question that fails under OIDC. If nothing in the flow resolves an org, the same-org guard has nothing to fire on.

The groundwork usually already exists. An org enabled as a SAML identity provider serves metadata at /.well-known/samlidp.xml and responds on its /idp/endpoint/* routes, and most orgs have certificates available. What is typically missing is a SamlSsoConfig on the consuming site, and a Connected App describing that site as the service provider.

What it takes to test:

Step Where Notes
Connected App describing the consuming site as the service provider, with Entity Id and ACS URL on that site, subject set to Federation Id Setup UI Connected Apps are often not retrievable as metadata, so expect this to be a hand step
SamlSsoConfig on the consuming site: issuer, entity id, IdP certificate, user id type Deployable metadata can be written and deployed from source control
Add the SAML config to the consuming site's login options Setup UI the login-options list is org state rather than metadata

Two Setup steps and one deployment, and none of it disturbs existing profiles or credentials on the consuming site.

The caveat, recorded because it is the same shape as everything else here. A site's SAML metadata declares an entityID of the org, not the site. Under SAML too, the issuing authority is the org and the site is a facade. The open question is only whether the service provider side cares, and unlike OIDC there is reason to think it does not, because the subject is what drives user resolution. That is a genuine unknown rather than a promise, so test it before you design around it.

What to do if you need this working now

Use an identity authority that is genuinely different from the org.

A broker has to be a different authority: another Salesforce org, or a non-Salesforce identity provider. If both of your sites already trust an external IdP, and that IdP already holds the user's session, then routing through it is the short path. It is the only issuer in reach that is not this org, which is the single property the guard is testing for.

That is worth stating as a design rule, because it generalises past this error: if two things need to federate, they have to be two identity authorities. Two doors onto one authority can look like two parties from the outside, right up until something asks who issued the identity.

Frequently Asked Questions

Q: Can SAME_ORG_SSO be disabled with a setting or a support case?

A: No. It is a platform guard rather than a configuration option, and there is no toggle exposed for it. It is also not arbitrary. The consuming site is being asked to trust an assertion about an identity that belongs to the org it is already running inside, which is a loop rather than a federation. The fix is to stop asking one org to federate with itself, not to look for a switch.

Q: I set the site rather than the org as the identity provider. Why does that not help?

A: Because the distinction is real at the URL and issuer level but not at the identity level. The site publishes its own discovery document and issues tokens under its own issuer string, which is why id_token validation passes once the issuer is set correctly. Underneath, the site and the org sign with the same keys and userinfo returns the org's identity. You configured it correctly and the outcome is still impossible.

Q: Would putting the two sites on different custom domains work?

A: No. The guard compares org ids, not hosts. In a failed attempt the resolved identity URL can be on a host belonging to neither site and the refusal still happens, because the org id inside that URL is what is being checked. A custom domain changes issuer strings and endpoint hosts without creating a second identity.

Q: Is SAML guaranteed to work?

A: No, and it should not be presented that way. It has a real mechanical reason to work, which is that user resolution happens from the assertion subject rather than from an org lookup, so the question that trips OIDC is never asked. The caveat is that a site's SAML metadata still declares the org as the entity id, so the site is a facade under SAML too. Whether the service provider side cares is the thing to test, and it is a short test.

Q: What is the actual fix if I just need single sign-on between two sites today?

A: Either route through an identity authority that is genuinely different, such as an external IdP both sites already trust, or reconsider whether you need federation at all. Two sites in one org already share a session, so moving a user between them may be a navigation problem rather than an authentication one.

Key Takeaways

  • SAME_ORG_SSO is a platform guard with no off switch. A site cannot authenticate against an identity provider that resolves to its own org.
  • An Experience Cloud site is not an identity authority. It is URL and issuer-string scoping over the org's single identity service.
  • The keys prove it. The site JWKS and the org JWKS return the same key set, including a key id embedding the org id.
  • Correct configuration and an impossible outcome coexist here. Site-scoped endpoints, site issuer and passing id_token validation are all real, and none of them create a second identity.
  • Custom domains do not help, because the guard compares org ids and an org id is not a URL.
  • SAML is the one route with a mechanical reason to work, since it resolves the user from the assertion subject, but the site still declares the org as its entity id, so test rather than assume.
  • Federation needs two authorities. Two doors onto one authority will pass as two parties only until something asks who issued the identity.

What's Next?

Recommended Reading:

Action Items:

  1. Before designing any site-to-site federation, fetch both JWKS endpoints and compare the key ids. If they match, the two sites are one authority and OIDC between them will not work.
  2. If you are mid-debug on a chain like this, clear the redirect URI, issuer and CSRF failures first, because each one hides the next and the real answer is only visible once all three are gone.
  3. Inventory which external identity providers both sites already trust, since that list is your set of viable brokers.
  4. If you try the SAML route, test user resolution specifically, because that is the step the whole idea rests on.

Resources & References

Responses

Checking your session.

Loading responses.