Single Sign-On
Ory Polis takes a multi-tenanted approach to implementing SSO, abstracting away all the complexities of the underlying SAML/OIDC protocol. What this means is you can enable SSO for all your customers across products from a single instance of Ory Polis, and works with both SAML and OIDC Identity Providers (IdPs).
Note: All the APIs below support both
application/x-www-form-urlencodedandapplication/jsoncontent types. Examples below useapplication/x-www-form-urlencoded.
Note: OAuth 2.0 protocol uses underscore casing for the parameters, we use camel casing for all Ory Polis APIs. For example it's
client_idin the OAuth 2.0 flow andclientIDin Ory Polis APIs.
Set up SSO provider
Please follow the instructions here to guide your customers in setting up SAML/OIDC correctly for your product(s). You should create a copy of the doc and modify it with your custom settings, we have used the values that work for Ory Polis demo apps.
SSO Connection API
You will need to provide a place in the UI for your customers (The account settings page is usually a good place for this) to configure this and then call the APIs below.
Add connection
- SAML
- OIDC
Once your customer has set up the SAML app on their Identity Provider, the Identity Provider will generate an IdP or SP metadata file. Some Identity Providers only generate an IdP metadata file but it usually works for the SP login flow as well. It is an XML file that contains various attributes Ory Polis needs to validate incoming SAML login requests. This step is the equivalent of setting an OAuth 2.0 app and generating a client ID and client secret that will be used in the login flow.
The following API call sets up the connection in Ory Polis:
curl --location --request POST 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'encodedRawMetadata=Base64(<IdP/SP metadata XML>)' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/saml' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo' \
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo SAML connection'
-
metadataUrl: URL containing the SAML metadata contents. Either this orencodedRawMetadataneeds to be specified -
encodedRawMetadata: Base64 encoding of the XML metadata your customer gets from their Identity Provider. Either this ormetadataUrlneeds to be specified -
defaultRedirectUrl: The redirect URL to use in the IdP login flow. Ory Polis will call this URL after completing an IdP login flow. -
redirectUrl: Allowed redirect URL. Repeat this field multiple times to allow multiple redirect URLs. Ory Polis will disallow any redirects not on this list (or not the default URL above).Both fields accept the private-use schemes native apps register, such as
com.example.app:/oauth2redirectormyapp://callback. Ory Polis rejects the schemes a browser executes as script (javascript:,data:,vbscript:) and URLs that embed credentials in the authority.An entry is matched on scheme, host and port, so it allows any path under the same origin — and a private-use scheme with no host, such as
com.example.app:, allows any URL using that scheme. SetOPENID_REDIRECT_EXACT_MATCHto compare the full URL instead. -
tenant: Ory Polis supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id. Should not contain the : character since we use it as a delimiter internally -
product: Ory Polis support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using. Should not contain the : character since we use it as a delimiter internally -
name: A friendly name to identify the SAML connection -
description: A short description with some information of the connection -
acsUrlId: Optional. A unique identifier (4-64 URL-safe characters) that gives the connection its own ACS endpoint at/api/oauth/saml/<acsUrlId>. See Per-connection ACS URLs. -
acsUrlHost: Optional. The hostname to associate with this connection's ACS URL. When omitted, Ory Polis uses theACS_URL_HOSTconfig value. -
idpInitiatedLoginEnabled(for SAML SSO Connections): Controls IdP-initiated login for this connection. Set totrueto always allow it, orfalseto always block it. When you leave it unset, the connection follows the deployment-wideIDP_ENABLEDswitch. Enable IdP-initiated login only where you need it, and review the security considerations first. -
identifierFormat(for SAML SSO Connections): The NameID format Ory Polis requests from the IdP in theNameIDPolicyof the SAML request. Defaults tourn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress.
The response returns a JSON with clientID and clientSecret that can be stored against your tenant and product for a more
secure OAuth 2.0 flow. If you do not want to store the clientID and clientSecret you can alternatively use
client_id=tenant=<tenantID>&product=<productID> and use dummy (or the value you set for the
secret verifier env) as the value for client_secret when setting up the
OAuth 2.0 flow. Additionally a idpMetadata.provider attribute is also returned which indicates the domain of your Identity
Provider.
Once your customer has set up the OIDC app on their Identity Provider, the Identity Provider will generate a clientId and clientSecret.
The following API call sets up the connection in Ory Polis:
curl --location --request POST 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/oidc' \
--data-urlencode 'oidcDiscoveryUrl=<well-known url of OIDC Provider>' \
--data-urlencode 'oidcClientId=<clientId of IdP Registered App>' \
--data-urlencode 'oidcClientSecret=<clientSecret of IdP Registered App>' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo' \
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo OIDC connection'
-
oidcDiscoveryUrl: OpenID Providers supporting discovery make the metadata available at the endpoint obtained by concatenating issuer and/.well-known/openid-configuration -
oidcClientId: The client identifier issued to the client during the IdP registration process. -
oidcClientSecret: The client secret issued to the client during the IdP registration process. -
defaultRedirectUrl: The redirect URL to use in the IdP login flow. Ory Polis will call this URL after completing an IdP login flow. -
redirectUrl: Allowed redirect URL. Repeat this field multiple times to allow multiple redirect URLs. Ory Polis will disallow any redirects not on this list (or not the default URL above).Both fields accept the private-use schemes native apps register, such as
com.example.app:/oauth2redirectormyapp://callback. Ory Polis rejects the schemes a browser executes as script (javascript:,data:,vbscript:) and URLs that embed credentials in the authority.An entry is matched on scheme, host and port, so it allows any path under the same origin — and a private-use scheme with no host, such as
com.example.app:, allows any URL using that scheme. SetOPENID_REDIRECT_EXACT_MATCHto compare the full URL instead. -
tenant: Ory Polis supports a multi-tenant architecture, this is a unique identifier you set from your side that relates back to your customer's tenant. This is normally an email, domain, an account id, or user-id. Should not contain the : character since we use it as a delimiter internally -
product: Ory Polis support multiple products, this is a unique identifier you set from your side that relates back to the product your customer is using. Should not contain the : character since we use it as a delimiter internally -
name: A friendly name to identify the OIDC connection -
description: A short description with some information of the connection
The response returns a JSON with clientID and clientSecret that can be stored against your tenant and product for a more
secure OAuth 2.0 flow. If you do not want to store the clientID and clientSecret you can alternatively use
client_id=tenant=<tenantID>&product=<productID> and use dummy (or the value you set for the
secret verifier env) as the value for client_secret when setting up the
OAuth 2.0 flow. Additionally a idpMetadata.provider attribute is also returned which indicates the domain of your Identity
Provider.
Get connections
This endpoint can be used to retrieve SAML/OIDC connections configured for a tenant/product. This can be used to check and display the details to your customers. Look connections up by one of:
tenantandproduct: every connection of that tenant and product.clientID: the connection with that client ID.entityId: SAML connections for that IdP entity ID that were created without anacsUrlId.entityIdandacsUrlId: the SAML connection with that per-connection ACS URL. Connections created with anacsUrlIdare only found this way, never byentityIdalone. Also passacsUrlHost, the host the connection was created under; it defaults to theACS_URL_HOSTconfig value, and without either the request is rejected.
When more than one is given, entityId wins over clientID, which wins over tenant and product. acsUrlId and acsUrlHost
are ignored without entityId; acsUrlHost with entityId but no acsUrlId is rejected.
- SAML
- OIDC
curl -G --location 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo'
curl -G --location 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>'
Connections created without an acsUrlId, by IdP entity ID:
curl -G --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'entityId=<IdP entity ID>'
A connection created with an acsUrlId. Omit acsUrlHost if ACS_URL_HOST is configured:
curl -G --location 'http://localhost:5225/api/v1/connections' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'entityId=<IdP entity ID>' \
--data-urlencode 'acsUrlId=customer-a' \
--data-urlencode 'acsUrlHost=sso.example.com'
The response returns a JSON with idpMetadata.providerindicating the domain of your Identity Provider. If an empty JSON payload
is returned then we do not have any connection stored for the attributes you requested.
curl -G --location 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo'
curl -G --location 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>'
The response returns a JSON with oidcProvider.provider indicating the domain of your Identity Provider. If an empty JSON payload
is returned then we do not have any connection stored for the attributes you requested.
Check whether a connection exists
This endpoint takes the same query as Get connections and answers 204 when at least one connection matches,
or 404 when none does, without returning the connections.
curl -G --location 'http://localhost:5225/api/v1/sso/exists' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo'
Update connection
This endpoint can be used to update an existing SSO Connection.
Identify the connection with clientID and clientSecret. Fields you leave out keep their current values.
When the update sends SAML metadata, or oidcClientId for an OIDC connection, also send the connection's tenant and product.
Ory Polis uses them to check that the metadata or client ID still matches the connection, so an update can't change the identity
provider's entity ID or the OIDC client ID. To change either, create a new connection.
- SAML
- OIDC
curl --location --request PATCH 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>' \
--data-urlencode 'clientSecret=<Client Secret>' \
--data-urlencode 'encodedRawMetadata=Base64(<IdP/SP metadata XML>)' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/saml' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo' \
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo SAML connection'
curl --location --request PATCH 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>' \
--data-urlencode 'clientSecret=<Client Secret>' \
--data-urlencode 'oidcDiscoveryUrl=<well-known url of OIDC Provider>' \
--data-urlencode 'oidcClientId=<clientId of IdP Registered App>' \
--data-urlencode 'oidcClientSecret=<clientSecret of IdP Registered App>' \
--data-urlencode 'defaultRedirectUrl=http://localhost:3366/login/oidc' \
--data-urlencode 'redirectUrl=http://localhost:3366/*' \
--data-urlencode 'redirectUrl=http://localhost:3000/*' \
--data-urlencode 'tenant=ory.com' \
--data-urlencode 'product=demo' \
--data-urlencode 'name=demo-connection' \
--data-urlencode 'description=Demo OIDC connection'
Ory Polis tells a SAML update from an OIDC update by the fields in the request: encodedRawMetadata, rawMetadata or
metadataUrl mark it as SAML, and oidcDiscoveryUrl or oidcMetadata mark it as OIDC. If an update sends none of these, for
example when it only changes the connection's name, add isSAML=true or isOIDC=true. Without it, the request fails with
400 Missing SSO connection params.
curl --location --request PATCH 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'clientID=<Client ID>' \
--data-urlencode 'clientSecret=<Client Secret>' \
--data-urlencode 'isSAML=true' \
--data-urlencode 'name=renamed-connection'
An OIDC connection logs in with either its discovery URL or its OpenID Provider metadata. An update with oidcDiscoveryUrl
switches the connection to that URL and drops any stored metadata. An update with oidcMetadata and no oidcDiscoveryUrl merges
the fields it sends into the stored metadata and drops the discovery URL. The merged metadata must still have issuer,
authorization_endpoint, token_endpoint, userinfo_endpoint and jwks_uri, or the update fails with 400 and the connection
stays as it was. An empty value counts as missing, so an update cannot clear a field.
Delete connections
This endpoint can be used to delete existing connections either by tenant/product or clientID. When deleting by clientID, send the
connection's client secret in the x-polis-client-secret header.
curl -X "DELETE" --location 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--url-query 'tenant=ory.com' \
--url-query 'product=demo'
curl -X "DELETE" --location 'http://localhost:5225/api/v1/sso' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'x-polis-client-secret: <Client Secret>' \
--url-query 'clientID=<Client ID>'
Per-connection ACS URLs
By default, all SAML connections share a single Assertion Consumer Service (ACS) URL (samlPath). When multiple tenants use the
same Identity Provider (same entity ID), Ory Polis resolves the connection by tenant and product.
Per-connection ACS URLs give each connection its own ACS endpoint, which is useful when your customers' IdPs require a unique ACS URL per app or when multiple connections share the same entity ID and you need the IdP to route responses to a specific connection.
1. Configure the default host
Set the ACS_URL_HOST environment variable to the public hostname of your Ory Polis instance:
ACS_URL_HOST=sso.example.com
This tells Ory Polis which hostname to store on connections and to use when looking up connections from incoming SAML responses. See ACS_URL_HOST for details.
2. Create a connection with acsUrlId
Pass acsUrlId when creating the SAML connection. The value must be 4-64 characters using letters, numbers, dots, hyphens,
underscores, and tildes.
curl --location --request POST 'https://sso.example.com/api/v1/connections' \
--header 'Authorization: Api-Key <Ory Polis API Key>' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'encodedRawMetadata=Base64(<IdP/SP metadata XML>)' \
--data-urlencode 'defaultRedirectUrl=https://your-app.com/sso/callback' \
--data-urlencode 'redirectUrl=https://your-app.com/*' \
--data-urlencode 'tenant=customer-a.com' \
--data-urlencode 'product=your-app' \
--data-urlencode 'acsUrlId=customer-a'
The response includes the connection's unique ACS URL in the acsUrlOverride field:
https://sso.example.com/api/oauth/saml/customer-a
Give this URL to your customer to configure as the ACS URL in their Identity Provider.
3. Handle the SAML response
Add a route that matches the per-connection ACS path and extracts the acsUrlId from the URL. Then pass it to samlResponse:
// Route: POST /api/oauth/saml/:acsUrlId
const { acsUrlId } = req.params
const { SAMLResponse, RelayState } = req.body
const result = await oauthController.samlResponse({
SAMLResponse,
RelayState,
acsUrlId,
acsUrlHost: "sso.example.com",
})
When using the Ory Polis service (not the npm library), this route is built in and works automatically.
OAuth 2.0 flow
OpenID Connect flow
Ory Polis also supports the OIDC flow. By including openid in the
scope param, an additional id_token is returned from the token endpoint which contains the user claims:
id, email, firstName, and lastName. To enable the flow on Ory Polis, be sure to configure the keys and algorithm in
OpenID configuration. If the authentication request contained nonce then it
is passed unmodified to the ID Token, which the client can use to validate and mitigate replay attacks. The ID Token's
polis_login_id claim is the ID of the login at Ory Polis; send the ID Token back as id_token_hint when you log the user out
(see SAML SLO).
Ory Polis has been designed to abstract the underlying SAML/OIDC login flow as a pure OAuth 2.0 flow. This means it's compatible with any standard OAuth 2.0 library out there, both client-side and server-side. It is important to remember that SSO Connection is configured per customer unlike OAuth 2.0 where you can have a single OAuth app supporting logins for all customers.
Ory Polis also supports the PKCE authorization flow, so you can protect your SPAs.
If for any reason you need to implement the flow on your own, the steps are outlined below:
Authorize
The OAuth flow begins with redirecting your user to the authorize URL:
https://localhost:5225/api/oauth/authorize
?response_type=code&provider=saml
&client_id=<clientID or tenant and product query params as described in the SSO connection API section above>
&redirect_uri=<redirect URL>
&state=<randomly generated state id>
response_type:codeis the only supported type for now but maybe extended in the futureclient_id: Use the client_id returned by the SSO connection API or usetenant=<tenantID>&product=<productID>to use the tenant and product IDs instead. Note: Please don't forget to URL encode the query parameters includingclient_id.tenant: Optionally you can provide usedummyas the value forclient_idand specify thetenantandproductcustom attributes (if your OAuth 2.0 library allows it).product: Should be specified if specifyingtenantaboveidp_hint: Can be used to select the Identity Provider if multiple connections match for the sametenant/product. Should point to the absolute "clientID" of the SSO Connection in Ory Polis.redirect_uri: This is where the user will be taken back once the authorization flow is completestate: Use a randomly generated string as the state, this will be echoed back as a query parameter when taking the user back to theredirect_uriabove. You should validate the state to prevent XSRF attacks.nonce(for OIDC flow): String value used to associate a Client session with an ID Token, and to mitigate replay attacks. The value is passed through unmodified from the Authentication Request to the ID Token. Sufficient entropy MUST be present in the nonce values used to prevent attackers from guessing values.forceAuthn(for SAML SSO Connections): If passed in with the valuetrue, the outgoing SAML request to IdP will have the paramForceAuthnset as true forcing the user to re-authenticate even if they have an active session.login_hint(Relevant for OIDC IdPs like Google): If passed in, the parameter will be forwarded in the OIDC IdP authorize request. The IdP can use this value (normally an account identifier such as an email address) as a hint to skip the account selection page.
NOTE: You can also pass the encoded tenant/product in either
scopeoraccess_typeorresource(Setclient_idasdummy). This will come in handy for some setups where the client_id can't be set dynamically.
The user will be taken to the IdP based on the configured SAML/OIDC metadata. In case of any errors, we return the error,
error_description and state (from original request) (see
Error Response) back to the redirect_uri
(redirect_uri is validated against the saml connection to prevent open redirects).
Code exchange
Once the user logs in successfully at the IdP, IdP sends back the SAML/OIDC response to Ory Polis. For SAML, the response contains
the user profile. In the case of OIDC, the response contains the authorization code that is used by Ory Polis to obtain token and
userprofile from the OIDC IdP. Ory Polis generates a short lived code and stores the user profile against it. After successful
authorization, the user is redirected back to the redirect_uri. The query parameters will include the code and state
parameters. You should validate that the state matches the one you sent in the authorize request.
The code can then be exchanged for a token by making the following request:
curl --request POST \
--url 'http://localhost:5225/api/oauth/token' \
--header 'content-type: application/x-www-form-urlencoded' \
--data 'grant_type=authorization_code' \
--data 'client_id=<clientID or tenant and product query params as described in the SAML connection API section above>' \
--data 'client_secret=<clientSecret or clientSecretVerifier if set (which otherwise defaults to "dummy")' \
--data 'redirect_uri=<redirect URL>' \
--data 'code=<code from the query parameter above>'
grant_type:authorization_codeis the only supported flow, for now. We might extend this in the futureclient_id: Use the clientID returned by the SSO connection API or usetenant=<tenantID>&product=<productID>to use the tenant and product IDs instead. Note: Please don't forget to URL encode the query parameters includingclient_id.client_secret: Use the clientSecret returned by the SAML connection API or clientSecretVerifier (which defaults to "dummy") if using the tenant and product in the clientIDredirect_uri: This is where the user will be taken back once the authorization flow is complete. Use the same redirect_uri as the previous request
If everything goes well you should receive a JSON response that includes the access token. This token is needed for the next step where we fetch the user profile.
{
"access_token": <access token>,
"token_type": "bearer",
"expires_in": 300
}
Profile request
The short-lived access token can now be used to request the user's profile. You'll need to make the following request:
curl --request GET \
--url 'https://localhost:5225/api/oauth/userinfo' \
--header 'authorization: Bearer <access token>'
If everything goes well you should receive a JSON response with the user's profile:
{
"id": <id from the Identity Provider>,
"firstName": "SAML",
"lastName": "Ory Polis"
"raw": {
...
},
"requested": {
...
}
}
id: The identifier of the user. For a directly configured SSO connection this is the identifier the Identity Provider provided. For an Identity Federation app it is derived from the upstream connection that authenticated the user, so that two connections behind one app cannot return the same identifier for two different people. Use it as the key you store the account under.upstream_sub: Identity Federation apps only. The identifier the upstream Identity Provider asserted. Two connections behind one app can assert the same value, so do not store an account under it — but SAML single logout needs it, because the upstream Identity Provider knows the user by this value and not byid.legacy_sub: Identity Federation apps only, and only whileOPENID_IDFED_LEGACY_SUBJECTistrue. The identifier the app returned before identifiers became connection-scoped. Use it once, to find an account you stored under the old identifier and saveidin its place. Do not store it: it is not unique across the connections behind an app and the claim will be removed in a later release.email: The email address of the user as provided by the Identity ProviderfirstName: The first name of the user as provided by the Identity ProviderlastName: The last name of the user as provided by the Identity Providerraw: This contains all claims attributes returned by the SAML providerrequested: This contains thetenant,product,client_idandstatefrom the authorize request. It can be used to reconcile context on the client side if needed
SAML SLO
SLO is a SAML flow that allows an end-user to logout of a single session and be automatically logged out of all linked sessions created during the SSO process.
The SLO flow begins with redirecting your user to the /api/logout endpoint.
https://localhost:5225/api/logout
?nameId=google-auth0-f92cc1834efc0f73e9c09
&tenant=ory.com
&product=demo
&redirectUrl=http://www.example.com/logout
nameId: Identifies the subject of a SAML assertion (Typically the user who is authenticated)tenant: The tentantproduct: The productclientID: The client ID of the SAML connection the user signed in through. Optional when only one SAML connection for the tenant and product supports SLO. You can sendclientIDinstead oftenantandproduct.redirectUrl: Post logout redirect URLid_token_hint: Optional. The ID Token Ory Polis issued for the login you are ending, even if it has expired. Ory Polis reads itspolis_login_idclaim to tie the logout to that login in its telemetry. A token Ory Polis did not sign is ignored, and the logout goes ahead without it. LikenameId, the token travels in the URL, so browser history and request logs can keep it, along with the user claims it carries. Leave it out if that is not acceptable for your deployment.
A logout request is only meaningful to the identity provider that authenticated the user. If more than one SAML connection for the
tenant and product supports SLO, Ory Polis responds with 400 Bad Request unless you pass clientID. The profile returned by
userinfo carries the connection's client ID in requested.idp_hint when the user picked an identity provider on the selection
page, and in requested.client_id when you started the sign-in with that client ID.
IdP will send a response to a specific URL (Single Logout URL) for the logout request. You need to register this URL on the IdP
/api/logout/callback to handle the response. It accepts both the HTTP-POST binding, where the LogoutResponse carries an XML
signature, and the HTTP-Redirect binding, where the IdP signs the query string. On the HTTP-Redirect binding Ory Polis verifies
the signature with the IdP certificates from the connection's metadata and accepts SHA-256, SHA-384 and SHA-512 signatures only.
If a connection stored only the certificate's thumbprint, update it with the IdP metadata again.
Ory Polis will redirect users to redirectUrl after the successful logout.
If the logout response is unsigned or its signature does not validate, Ory Polis responds with 403 Forbidden and a message that
names the problem instead of redirecting. When the cause is an algorithm the platform refuses, such as RSA-SHA1, the message asks
you to configure the IdP to sign with RSA-SHA256.
You should save the identifier returned by userinfo for a user so that you can pass it as nameId with an SLO request. For a
directly configured SSO connection that is id. For an Identity Federation app, pass upstream_sub instead — id is scoped to
the app and the upstream Identity Provider will not recognise it.
