v26.4.4
v26.4.4
Authorization codes, access tokens, and SSO sessions now expire on time
Ory Polis now checks whether a record has expired every time it reads one. Authorization codes, access tokens, and SSO sessions
stop working as soon as their lifetime ends. Previously, expiry took effect when the periodic cleanup job removed the record.
/oauth/token rejects an expired code with 403 Invalid code, /oauth/userinfo rejects an expired access token with
403 Invalid token, and an expired SSO session can no longer resume a login. Lifetimes are still set by DB_TTL, and the
expires_in value that /oauth/token returns is unchanged.
Before you deploy this version, run the database migrations if you manage them yourself — on PlanetScale, or with
DB_MANUAL_MIGRATION=true. This release adds an expiresAt column to the jackson_store table and every read uses it, so reads
fail until the column exists. The migration changes only table metadata, so it is quick to apply to a live table. Deployments that
let Ory Polis manage the schema add the column automatically at startup.
Batched directory sync events arrive in the order they happened
With DSYNC_WEBHOOK_BATCH_SIZE set, a connection's queued events could reach the webhook out of order, for example a
group.user_added before the group.created of its group. This happened on DynamoDB once more events were queued than fit on one
page of the database, and between events queued close together on SQLite, SQL Server, Redis and MongoDB. Each connection's events
now go out in the order they were queued on every database engine, and a batch holds up to DSYNC_WEBHOOK_BATCH_SIZE events even
when that is larger than DB_PAGE_LIMIT.
On DynamoDB a batch run now reads the whole event queue with strongly consistent reads, rather than each connection's events through an index that DynamoDB updates a moment after each write, so it sees every event queued before the ones it sends. Reads of the event queue use twice the read capacity they did.
Faster paged lists on SQL databases
Paged lists read from SQL databases, such as the lists of connections and directory sync users, sorted every record of their kind
on each page, so a page took longer the more records there were. A new index on jackson_store (namespace, createdAt) lets the
database read a page in order instead. It replaces the index on jackson_store (namespace), which the new one covers. On
PostgreSQL, CockroachDB and YugabyteDB, lists read through a secondary lookup get the same treatment: jackson_index (key, id)
replaces jackson_index (key).
If you run migrations yourself (DB_MANUAL_MIGRATION), run them before you upgrade. On PostgreSQL the migration builds the index
with CREATE INDEX CONCURRENTLY, and MySQL, MariaDB, CockroachDB and YugabyteDB build it without blocking writes. Otherwise Polis
creates the index when it starts, and on PostgreSQL, SQL Server and SQLite writes to jackson_store wait until it is built: about
a second per million rows on PostgreSQL.
On YugabyteDB whose tables Polis creates when it starts, create the indexes yourself before you upgrade, with
CREATE INDEX CONCURRENTLY IF NOT EXISTS "_jackson_store_namespace_created" ON "jackson_store" ("namespace", "createdAt") and
CREATE INDEX CONCURRENTLY IF NOT EXISTS "_jackson_index_key_id" ON "jackson_index" ("key", "id"). Polis creates them inside a
transaction, where YugabyteDB cannot build an index concurrently, and a nonconcurrent build is not safe while Polis writes to the
table.
Setup links can give their SAML connections their own ACS URL
With ACS_URL_HOST configured, an SSO setup link can now carry an ACS URL ID, so the SAML connections created through it get
their own ACS URL. Tick the new option on the create Setup Link page, or pass acsUrlId to POST /api/v1/sso/setuplinks. The
setup link's instructions show that ACS URL and a matching SP metadata link, so your customer can configure their IdP before the
connection exists. Regenerating or renewing the link keeps the ID. Links created without it work as before.