# Upgrading from rc.13 to 1.1.0-rc.1

This page lists what you must change, and what behaves differently, when you move a HelixIAM install from `v1.0.0-rc.13` to `v1.1.0-rc.1`. The source is the `v1.1.0-rc.1` release notes and upgrade notes.

The release adds decentralised-identity features, all **Preview** and not yet tested with a real national wallet: [wallet step-up and profile](../federation/wallet-step-up-and-profile.md), [credentials beyond the PID](../federation/wallet-credentials.md), [credential issuance](../federation/credential-issuance.md), [verified data for applications](../integration/verified-claims.md), the [verification API](../integration/verification-api.md), [transaction confirmation](../federation/wallet-transaction-confirmation.md), [DIDs](../federation/dids.md), and automation for [trusted lists](../federation/trusted-lists.md). None of them is on until you configure it. The items below apply whether or not you use them.

## Before you upgrade: checklist

| # | Do this | Applies if |
| --- | --- | --- |
| 1 | Make sure every `private_key_jwt` / `client_secret_jwt` client sends a [fresh, short-lived assertion with `jti` and `exp`](#1-client-assertions-are-single-use) | any client authenticates with a signed assertion |
| 2 | [Review the typed mappers on your wallet connections](#2-wallet-connections-now-run-their-typed-mappers) | you have EUDI Wallet connections with typed identity-provider mappers |
| 3 | Set [`IDP_BASE_URL`](#3-the-credential-issuer-needs-idp_base_url) to the public base URL | you will issue credentials |
| 4 | Re-write the profile attributes you will [match wallets against](#4-profile-attributes-record-who-set-them) | you will turn on wallet attribute matching |
| 5 | Move PID trust away from [this deployment's own issuer](#5-own-issuers-are-never-trusted-for-the-pid) | a wallet connection trusts this server's issuer for the PID, or a template uses a PID type |
| 6 | Let the [Flyway migrations V90–V135](#6-new-flyway-migrations-v90v135) run | always |
| 7 | Read the [other behaviour changes](#7-other-behaviour-changes) | you use verify-only wallet connections or trusted lists |

Back up the database first, as for every upgrade, and keep `DB_ENCRYPTION` with the backup.

---

## 1. Client assertions are single use

**What changed.** Every client that authenticates with a signed assertion (`private_key_jwt`, `client_secret_jwt`) — at the token endpoint, PAR, introspection, revocation and the wallet verification API — must now:

- send `jti` and `exp` in every assertion (an assertion without either is refused with `invalid_client`);
- keep its lifetime at most **5 minutes** (`exp − iat`, and `exp` at most 5 minutes after the server's clock, with 60 s of skew);
- create a **fresh assertion for every request**: a `jti` is accepted once per client until the assertion expires (RFC 7523 §3), recorded in the shared PostgreSQL replay store (`credential_attestation_jti`), so a replay on any replica is refused.

**Fail closed.** When the replay store (the database) cannot record a `jti`, the assertion is refused, so these clients cannot authenticate during a database outage. Clients using `client_secret_basic` are not affected.

**What you must do.** Check your client libraries. Most (Nimbus, MSAL, Spring Security's `NimbusJwtClientAuthenticationParametersConverter`) already send a random `jti` and a short `exp` per request. A client that caches and reuses one assertion must stop doing so.

## 2. Wallet connections now run their typed mappers

**What changed.** Wallet logins now apply the typed identity-provider mappers like every other connection: at just-in-time provisioning every mapper applies (attribute importer, hardcoded attribute and role, claim-to-role), and at a later sign-in the `FORCE` mappers apply (attributes overwritten, mapper-assigned roles added and removed). Before, only the legacy `mappers` setting applied, and only at just-in-time provisioning. **A typed mapper saved on a wallet connection earlier now runs.** A mapper that cannot be applied refuses the sign-in.

**What you must do.** Before upgrading, open each EUDI Wallet connection's **Mappers** tab (or list `GET /admin/realms/{realm}/identity-providers/{alias}/mappers`) and review what it does, especially role mappers. Remove or change any you did not mean to run. See [Credentials beyond the PID](../federation/wallet-credentials.md#mapping-claims-to-attributes-and-roles).

## 3. The credential issuer needs `IDP_BASE_URL`

**What changed.** A realm can now issue credentials over OpenID4VCI. The credential issuer identifier is `{IDP_BASE_URL}/realms/{realm}` (or the realm's own issuer setting), taken from configuration and never from the request's `Host` header, because it is signed into every credential, names the status lists and is the audience of every key proof.

**What you must do.** If you will issue credentials, set `IDP_BASE_URL` to the public base URL. Without it the realm cannot issue. Issuer keys also need `DB_ENCRYPTION` outside the `dev` profile. Nothing issues until an administrator enables the issuer settings of a realm. See [Credential issuance](../federation/credential-issuance.md#before-you-start).

A new admin permission, `manage-credential-issuance`, covers templates, offers and issued credentials; `realm-admin` includes it. See [Admin roles](admin-roles.md).

## 4. Profile attributes record who set them

**What changed.** Flyway V123 adds `user_profile_provenance`: from this release on, every write of a profile attribute records its source — `ADMIN` (admin API and console), `SCIM`, `IMPORT` (user CSV import, realm import), `SELF` (account console), `REGISTRATION` (self sign-up), `FEDERATION_MAPPER` (identity-provider just-in-time provisioning and mappers) — with a keyed hash of the value. Only the opt-in wallet [attribute matching](../federation/wallet-step-up-and-profile.md#binding-a-wallet-by-matching-attributes) reads it, and it trusts only `ADMIN`, `SCIM` and `IMPORT` values that have not changed since.

**Existing attributes have no recorded source and count as untrusted (fail closed):** attribute matching refuses them (`UNTRUSTED_SOURCE`) until an administrator, SCIM or an import writes them again. Re-running your SCIM sync or user import is enough. Nothing else changes for existing attributes. V120–V122 add the wallet step-up and profile tables; all those features are off by default.

## 5. Own issuers are never trusted for the PID

**What changed.** A wallet connection may no longer trust this deployment's own credential issuers (any realm's did:web, issuer key, issuer certificate or the CA that issued it) for the **PID**, and a credential template may no longer use a PID type or a claim the wallet subject is derived from (`personal_administrative_number`, `issuing_country`). See [This deployment's own issuer](../federation/wallet-credentials.md#this-deployments-own-issuer).

**What you must do.** A stored wallet connection whose PID trusts an own issuer fails validation at start-up and is skipped (logged): move that trust to a credential besides the PID, or trust the real PID provider. A template with a PID type or a subject claim can no longer issue: give it its own type and drop those claims.

## 6. New Flyway migrations V90–V135

The migrations run on start-up. They only add tables, columns and indexes:

| Migration | What it adds |
| --- | --- |
| `V90__trusted_list_rotation_and_pointers.sql` | trusted list sources: signer rotation, pointer depth, announced signers, retry backoff counter, load generation; per member: depth and signers |
| `V95__credential_issuance.sql` | the credential issuer: settings, issuer keys, the development CA, templates, offers, issuer access tokens, nonces, the `credential_attestation_jti` replay store (also used for client assertions), status lists, issued credentials |
| `V96__credential_issuance_hardening.sql` | issuer review round: wallet clients, offers served by reference, offers delivered to the user, DPoP binding of pre-authorized tokens |
| `V97__credential_token_configuration_use.sql` | a pre-authorized token used once per credential configuration |
| `V110__client_verified_claims.sql` | per-client `verified_claims` release policies (deleted with the client and the realm) |
| `V115__wallet_verification_api.sql` | the verification API opt-in on the policy, and per-client API settings |
| `V116__wallet_verification_template.sql` | verification templates |
| `V117__wallet_verification.sql` | verifications (status and names kept 7 days) |
| `V120__wallet_profile_settings.sql` | per verify-only connection: step-up lifetime, attribute matching and kept-attribute settings |
| `V121__user_verified_attribute.sql` | verified attributes kept on the profile, sealed |
| `V122__verified_claims_stored_attributes.sql` | `useStoredAttributes` on the verified-claims policy |
| `V123__user_profile_provenance.sql` | who set each profile attribute ([above](#4-profile-attributes-record-who-set-them)) |
| `V125__wallet_transaction_data.sql` | the encrypted `transaction_data` of a wallet transaction |
| `V130__did_support.sql` | `publish_did_web` on the issuer settings, `signing_method` on templates |
| `V135__credential_offer_user_index.sql` | an index for a user's open credential offers |

## 7. Other behaviour changes

- **Step-up without the first factor.** A signed-in user asked for `acr_values` by a client whose flow has a top-level REQUIRED wallet step is no longer sent to the sign-in page first: they go straight to the wallet step, keeping the session. See [Wallet step-up and profile](../federation/wallet-step-up-and-profile.md#step-up-without-the-first-factor).
- **No credential offers to yourself.** An administrator can no longer offer a credential to their own account (`403`).
- **No BSN through issued credentials.** Every issued claim goes through the central BSN detector; BSN-like claim names and BSN-shaped `const:` values are refused when a template is saved.

- **Verify-only release value.** The `verified_claims` of a [verify-only](../federation/eudi-wallet.md#verify-only-step-up) connection now carry the IDA value `"assurance_level": "high"` instead of the LoA URI. `acr` is unchanged (`http://eidas.europa.eu/LoA/high`). A relying party that compared `assurance_level` with the URI must accept `high`.
- **Verify-only and a verified-claims policy.** A client with an enabled [verified-claims policy](../integration/verified-claims.md) no longer gets the verify-only connection's `verify.releasedClaims` ID-token release; its policy governs. Clients without a policy are unchanged.
- **Trusted lists: no automatic integrity reset.** A source whose stored trust state fails its integrity check now stays failed closed until an administrator runs **Reset and reload**; the automatic reset (`TRUSTED_LIST_INTEGRITY_RESET`) is gone. Removing a pinned signer needs `resetFloors: true` (the console asks). Sources stored by rc.13 keep their old integrity codes until their next successful load. See [Trusted lists](../federation/trusted-lists.md#tampering-and-reset-and-reload).
- **Trusted lists: failing closed with a clear code.** A presentation refused because a trusted list gives no anchors is audited as `TRUST_LIST_UNAVAILABLE`, no longer `ISSUER_UNTRUSTED`. Update SIEM rules that match on the old reason.
- **Trusted lists: retry backoff.** A failed refresh now waits 15, 30, 60, … minutes, up to `helix.wallet.trusted-lists.max-retry-interval-minutes` (360), instead of a fixed interval.
- **PID mapping.** The PID mapping and the wallet subject read only the PID's credential queries.
- **Wallet mapper behaviour.** See [item 2](#2-wallet-connections-now-run-their-typed-mappers): typed mappers on wallet connections now run, and a credential from an own issuer can never grant a role with an admin permission.

## See also

- [Upgrades & migrations](upgrades.md) — the general procedure
- [Upgrading from rc.12 to rc.13](upgrade-rc12-rc13.md)
