Skip to content

Conversation

@martinml
Copy link

@martinml martinml commented Sep 4, 2025

Description

This PR adds support for Auth0's MRRT feature.

High-level overview of the changes this PR includes:

  1. Audience and organization are now saved within the tokenset.
  2. A "token history" feature that keeps inside the user session a list of previous but non-expired tokens. This is needed so the SDK can find "compatible" tokens when doing a MRRT refresh (i.e. if I have a token for audience A and I need a token for audience B, I can do a refresh from A to B). Can be enabled with the new tokenHistory option, but it's disabled by default.
  3. A refactor of the existing middlewares signatures so they accept an object instead of discrete arguments. This was made so routes can specify an authorizationParams argument that will override the one set at the SDK level. This is not a breaking change since I included a compatibility layer that detects old vs. new arguments and normalizes them (see requiresAuthLegacyArgs.js).
  4. A useMrrt option, to enable the potential usage of MRRT, depending on whatever it's in the token history. It requires tokenHistory to be enabled and proper configuration in Auth0. Disabled by default.
  5. An autoRefreshExpired option, to improve the DX when using MRRT. This way, requesting a series of tokens with different audiences/scopes to protect a route is a declarative operation, instead of having to check whether tokens are expired.
  6. A new cookie format. The previous one was storing the session data directly into the root of the data structure, which made impossible to store "sibling" properties. Old cookies are transparently converted into the new version, and a versioning schema is introduced. Note that this only applies when not using a custom store: we can store other properties adjacent to the session data one.

Testing

  • This change adds test coverage for new/changed/fixed functionality

Checklist

  • I have added documentation for new/changed functionality in this PR or in auth0.com/docs
  • All active GitHub checks for tests, formatting, and security are passing
  • The correct base branch is being used, if not the default branch

martinml added 27 commits May 15, 2025 18:41
@martinml martinml force-pushed the add-support-for-mrrt branch from f5fb9f6 to 68868e6 Compare September 8, 2025 16:17
@martinml martinml force-pushed the add-support-for-mrrt branch from 68868e6 to 5126d4a Compare September 8, 2025 16:20
@martinml martinml marked this pull request as ready for review September 15, 2025 09:14
@martinml martinml requested a review from a team as a code owner September 15, 2025 09:14
findCompatibleActive(tokenSets, authorizationParams) {
return tokenSets.find(
(ts) =>
!TokenSetUtils.isExpired(ts) &&
Copy link
Contributor

Choose a reason for hiding this comment

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

these 3 methods findCompatibleActive, findCompatibleExpired findCompatibleRefreshable looks similar. Could we refactor this?


/** @type {import('..').TokenSetParameters | undefined} */
let found;

Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't we consider the most recent token? Could you re-check this once.

* small enough that a token can't possibly fit inside.
*/
const loggedOutCookies = await context.cookies();
assert.isTrue(loggedOutCookies.find(({ name }) => name === 'appSession').size < 200);
Copy link
Contributor

Choose a reason for hiding this comment

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

here if loggedOutCookies.find does find the cookie it returns undefined
Shall we do something
const appSessionCookie = loggedOutCookies.find(({ name }) => name === 'appSession'); assert.isTrue(!appSessionCookie || appSessionCookie.size < 200);

Copy link
Author

Choose a reason for hiding this comment

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

I think this is fixed now here. Some code was not expecting the possibility of optional props to actually be present in the tokenset but with a nullish value. This caused the cookie not to be properly cleared.

@gyaneshgouraw-okta
Copy link
Contributor

@claude

@github-actions
Copy link

github-actions bot commented Oct 1, 2025

Claude encountered an error —— View job

Failed with exit code 128

I'll analyze this and get back to you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants