Edit Page

Upgrade from 9.11 to 9.12

Prefer not to run it yourself? Ulabase is this, hosted, with sign-up, payments and an MCP server already on. Free to start. Get started →

RESTHeart 9.12 changes how restheart-accounts handles the active team. The tokens it issues no longer carry a team claim, and memberships are stored on the team only.

You are affected if you use restheart-accounts with teams, or restheart-stripe. This page lists the breaking changes, says who is affected and what to do.

What changed

No team claim in the tokens

Before 9.12, the accounts endpoints (activation, email verification, password reset, POST /auth/switch-team, POST /auth/teams, the OAuth callback) put the active team in the JWT as team: { _id, role }.

From 9.12, no token issued by restheart-accounts carries a team claim. The new token after a switch of team carries the user’s system roles from the database, and no team role.

A client that read the team from the JWT reads it from one of these:

  • the POST /auth/switch-team response body, { "team": { "_id": …, "role": … } };

  • the POST /auth/teams response body, { "id": …, "name": …, "role": … };

  • GET /auth/teams, the entry with active: true.

With ?delivery=body, these responses also carry the access_token.

A deployment that still wants the team in every token opts in, on jwtConfigProvider:

jwtConfigProvider:
  account-properties-claims:
    - "@team"     # quoted: @ is reserved in YAML

The claim then appears on every token path, POST /token included. See The active team in the token.

ACL rules read the active team through @team

restheart-accounts registers the ACL variable @team, as { _id, role }. It is resolved at every request from the membership provider, so it follows a switch of team at once. Its name follows accountsConfig.team-claim-name (default team).

@user.team reads the token, which no longer has a team. A rule that uses it resolves to nothing and denies. Replace it.

Before (9.11):

- role: user
  predicate: path-prefix('/orders') and equals(@user.team.role, "owner")
  mongo:
    readFilter: '{"team": "@user.team._id"}'
    mergeRequest:
      team: "@user.team._id"

After (9.12):

- role: user
  predicate: path-prefix('/orders') and equals(@team.role, "owner")
  mongo:
    readFilter: '{"team": "@team._id"}'
    mergeRequest:
      team: "@team._id"

A caller with no active team has @team unresolved, and the rule denies.

Memberships live in team.members only

Before 9.12, the user document also carried teams: [{ id, role }] and the active role in team.role.

From 9.12, the default membership provider stores who belongs to a team, and with which role, in the team’s members only. The user document keeps the active team id:

{
  "_id": "alice@example.com",
  "team": { "_id": { "$oid": "64a1b2c3d4e5f6a7b8c9d0e1" } }
}

teams and team.role on the user are no longer read or written. Access follows team.members. Clients and tools that read them from the user document read GET /auth/teams instead.

A JSON Schema on the users collection that declares teams can drop it.

restheart-stripe resolves the team through @team

The billing entity, for subscriptions and for orders, is the caller’s active team from @team. The JWT team claim is used only as a fallback, where no @team variable is registered. No configuration change is needed.

Migration steps

1. Update your ACL rules

Search your permissions, in the configuration and in the acl collection, for @user.team. Replace @user.team._id with @team._id and @user.team.role with @team.role.

2. Migrate the user documents

Turn on the one-off migration and restart:

accountsConfig:
  migrate-memberships: true

At startup it removes teams and team.role from every user document that still has them. Every membership listed there that the team’s members do not confirm is reported in the log as a warning. Nothing is added to a team. Check the warnings, then set migrate-memberships back to false, its default.

3. Update your clients

Read the active team from the switch-team response or from GET /auth/teams, or list "@team" in jwtConfigProvider.account-properties-claims.