v26.4.9
v26.4.9
PKCE now requires the S256 code challenge method
By default, the OAuth authorization endpoint (/api/oauth/authorize) accepts only the S256 code challenge method. A request
that sends a code_challenge with code_challenge_method=plain, with any other value, or without the parameter at all is
rejected with an invalid_request error returned to the redirect URI. The code_challenge_methods_supported field of the OpenID
configuration document lists S256 alone, and includes plain on deployments that enable it.
Behavior changes
Clients that use plain, or that rely on the OAuth default of plain by omitting code_challenge_method, stop working. Move
them to S256, where the challenge is the SHA-256 hash of the code verifier, base64url encoded without padding, sent together
with code_challenge_method=S256. Most OAuth libraries do this for you.
The method value is matched exactly, as RFC 7636 requires, so s256 and other spellings are rejected as well. A request that
sends an empty code_challenge, or that repeats the code_challenge or code_challenge_method parameter, is refused as
malformed: an empty challenge is not the same as a request without PKCE. Those two parameters are checked before the redirect URI
has been validated, so the error goes back to the caller rather than to the redirect URI.
If a client cannot be changed yet, set OPENID_PKCE_ALLOW_PLAIN=true (npm library option openid.pkceAllowPlain) to keep
accepting plain while you migrate. plain carries the code verifier in the authorization request in clear text, so remove the
setting once every client uses S256. Requests that name a method Ory Polis does not implement are rejected either way.
Polis API errors share one format
Every management API route now reports an error as { "error": { "message": "..." } }, with the HTTP status carrying the error
code. For a server error, the message no longer includes internal details.
A request that uses a method an endpoint does not support now gets a 405 response with an Allow header listing the supported
methods. The endpoints a browser reaches during login and logout, such as the SAML ACS URL and /api/logout, send the browser to
the Ory Polis error page with that 405 instead.
Breaking changes
- The directory sync routes under
/api/v1/dsyncno longer return acodefield insideerror. If your integration readserror.code, read the HTTP status instead. DELETE /api/v1/dsync/{directoryId}reports a failed delete. Deleting a directory that does not exist returns 404 instead of 200.- The OAuth token endpoint (
/api/oauth/token) answers a failed request with the JSON body RFC 6749 defines,{ "error": "...", "error_description": "..." }, instead of a plain-text message. The HTTP status codes are unchanged. OAuth client libraries read this format already. If you parse the plain-text body yourself, readerror_descriptioninstead.
Removed deprecated SSO connection APIs and legacy API paths
Ory Polis no longer serves the deprecated SAML configuration API or the old API paths kept for backward compatibility.
Breaking changes
These HTTP routes are removed and now return 404 Not Found:
| Removed route | Use instead |
|---|---|
/api/v1/saml/config | /api/v1/sso |
/api/v1/saml/config/exists | /api/v1/sso/exists |
/api/v1/connections/* | /api/v1/sso/* |
/api/v1/directory-sync/* | /api/v1/dsync/* |
/api/v1/saml-traces/* | /api/v1/sso-traces/* |
/api/v1/federated-saml/* | /api/v1/identity-federation/* |
If you embed Polis with the npm package (@boxyhq/saml-jackson):
- The
apiControllerexport is removed. UseconnectionAPIController. - The deprecated
config,getConfig,updateConfig, anddeleteConfigmethods are removed. UsecreateSAMLConnection,getConnections,updateSAMLConnection, anddeleteConnections.getConnectionsreturns an array of connections, not a single connection or an empty object.deleteConnectionsdeletes SAML and OIDC connections unless you passstrategy: 'saml'. - The
GetConfigQueryandDelConfigQuerytypes are removed. UseGetConnectionsQueryandDelConnectionsQuery.
Update any scripts, integrations, or code that use these routes or methods before you upgrade.
SAML audiences must match the SP entity ID exactly
Polis now accepts a SAML response only when its Audience is exactly one of the connection's two SP entity IDs:
- the SP entity ID: the connection's
samlAudienceOverrideif it has one, and otherwiseSAML_AUDIENCE(samlAudiencein the npm library) - the SP entity ID followed by
/and the tenant and product identifier, which the SSO connection setup page shows for identity providers that need a unique entity ID per app
Both keep working. Before, Polis also accepted any Audience that only started with the SP entity ID, such as
https://saml.boxyhq.com/ with a trailing slash, or the entity ID shown for a different tenant or product. Logins through a SAML
connection whose identity provider sends such a value now fail with Invalid audience.
The setup page builds the entity ID it shows from SAML_AUDIENCE, even for a connection with samlAudienceOverride. For such a
connection, the second SP entity ID is the override followed by the same / and identifier, so the value the setup page shows is
not accepted. Use the override, or replace SAML_AUDIENCE at the start of the value the setup page shows with the override.
What you must do
Before you upgrade, compare the Entity ID, Audience URI, or Audience Restriction in each customer's SAML app with the connection's two SP entity IDs. It must be identical to one of them, including case and any trailing slash. For each connection that differs, do one of the following:
- Have the customer set the Entity ID in their SAML app to one of the two SP entity IDs.
- If the identity provider can't be changed, set
samlAudienceOverrideon the connection to the value the identity provider sends. Polis then also uses that value as the issuer of the SAML authentication requests it sends to that identity provider.
After you upgrade, failed logins appear in SSO Traces with the error Invalid audience. The
upgrade guide has the same steps.
Cleaner SBOM and CBOM attestations for OEL images
The SBOM attestations of OEL images now list the license of each Go module. They no longer list the timezone database, shell profile and license text files of the base image, the source repository metadata of the scanner, or secret-pattern matches that are not cryptographic assets. Each document is validated against its schema before it is signed. Tools that ingest the attestations need no changes.
Polis rejects tenant and product selectors that conflict with the client ID
An authorization request that names a registered client, either an SSO connection's client ID or an identity federation app, now
only signs in through connections that client is allowed to use. If the request also passes tenant and product, or encodes
them in access_type, resource or scope, they must match the client's connection or fall within the federation app's tenants.
Otherwise Polis rejects the request.
Selecting a connection by tenant and product works as before when client_id is dummy, the encoded
tenant=<tenant>&product=<product> value, or a value that is not a registered client ID.
SCIM POST /Groups now applies group members
Creating a group with a members list now persists that membership. Until now the create returned 201 and kept the group's
name, but discarded the members, so any client that provisions membership on create left the group empty. A create without
members still creates an empty group, and a malformed members list is now rejected with 400 and the scimType invalidValue
instead of failing with a server error. If applying the members fails, the create is undone and fails, so the identity provider
can retry it.