Skip to main content

Who decides when a credential has been replaced?

· 16 min read
Wouter Ensink
Developer @ Yivi

A new credential cannot tell a wallet whether an older one has become obsolete. During ordinary issuance, revocation must provide that signal. A retained link makes automatic background refresh the exception.

A new credential can mean two things

You transfer from Finance to Legal. Your employer issues a fresh employee credential with your new department. That is exactly what should happen.

Your wallet now holds two employee credentials. One says Finance; the other says Legal. The old credential is still signed, unexpired, and not revoked.

The next time a verifier asks for your department, the wallet may offer both. Your employer has left Finance valid, so the wallet has no authoritative reason to suppress it.

Two employee credentials in the wallet after a department transfer. Both have the same type and employer and are signed, unexpired and not revoked, so either can be offered.

Now change one fact. You did not leave Finance; you joined Legal as a second department. In that case, both credentials should remain valid.

You join a second department
Type
same as one you hold
Issuer
same as one you hold
Attributes
differ from the stored credential
Issuer action: keep both valid
You transfer departments
Type
same as one you hold
Issuer
same as one you hold
Attributes
differ from the stored credential
Issuer action: revoke the old credential

The wallet sees the same pattern in both cases: same type, same issuer, different attributes. Yet one case keeps both credentials valid, while the other makes the old one obsolete.

Attribute names do not resolve the ambiguity. A field describes its value, not whether an older statement remains true.

The employer knows what happened; the wallet does not. During ordinary issuance, the issuer must express that the old credential is obsolete by revoking it.

Replacement hides two mechanisms

Here, a logical credential is the unit shown to the user as one card: one credential type from one provider with one set of attribute values.

Behind that card, the wallet may store several signed technical copies. Their salts, keys, signatures, and validity timestamps may differ, but each makes the same statement.

In other words, one logical credential consists of a batch of one or more technical credentials.

One logical credential shown as a card, backed by four signed technical copies. Type, issuer and attribute values are identical across the copies and are the three inputs Yivi hashes; salts, digests, holder keys, signatures and validity timestamps differ per copy and are omitted.

When attribute values change, the result is a new logical credential. The issuer decides whether the older credential remains valid by leaving it valid, letting it expire, or revoking it.

The word replacement therefore covers two mechanisms:

  1. Content identity groups new technical copies with the same logical credential during refresh.
  2. Revocation status tells wallets and verifiers that an old logical credential is no longer valid.

Content identity is calculated from the credential. Revocation is an issuer action on a credential it previously issued.

These mechanisms answer different questions: “Are these new copies of the same statement?” and “Is the former statement still valid?”

What content matching can decide

Yivi treats an arriving credential as another copy of a stored logical credential when three things match:

  1. the type (vct for SD-JWT VC, docType for mdoc),
  2. the issuer,
  3. the attribute values.

The wallet hashes those inputs. A matching hash lets the new batch refresh the stored batch. A different hash represents a different logical credential.

The hash omits salts, digests, holder keys, signatures, and validity timestamps. Those values change between issuances, even when the logical credential does not.

The ARF describes the same rule in a note attached to PAD_02:

Physical PIDs or attestations correspond to a logical one if they have not only the same attestation type and Provider, but also the same attribute values.

This works well for routine refresh. Credentials expire, and batches of single-use copies run out. The wallet can fetch fresh copies with new keys and timestamps but unchanged attributes.

An age credential, for example, keeps saying age_over_18: true. Its hash still matches, so fresh copies update the batch and the wallet shows one card rather than twelve.

Content matching may also group exact duplicates during ordinary issuance. It cannot decide that a different logical credential has made an older one obsolete.

OpenID4VCI describes the alternative plainly: a wallet may hold several credentials of the same type “without knowing which one is the latest”.

View the complete content-matching comparison
What really happenedTypeIssuerAttributesRequired handling
PID renewed, nothing changedSameSameSameRefresh copies
Email credential re-issued unchangedSameSameSameRefresh copies
You transfer departmentsSameSameDifferRevoke old
You join a second departmentSameSameDifferKeep both valid
A second diploma from the same universitySameSameDifferKeep both valid
Age credential from the state and from a shopSameDifferSameKeep both valid
Email attested by your employer and by the stateSameDifferSameKeep both valid

Revocation is the replacement signal

When changed values make an old credential obsolete, the provider should issue the updated credential and revoke the old one.

Replacement starts with the issuer

VCR_03 makes the PID or attestation provider the only ecosystem party responsible for executing revocation.

Under VCR_09, that provider revokes an applicable credential after its attributes change. Under VCR_19, the wallet should regularly check status.

Four steps after a department transfer. The employer issues the updated credential and revokes the old copies under VCR_09; the wallet checks status under VCR_19, then stops presenting the obsolete credential under ISSU_62.

The provider controls the status of the credentials it issued. It can invalidate the exact old technical copies without asking the wallet to reconstruct a relationship from new contents.

After revocation, the old copies are no longer valid. Under VCR_19, the wallet should regularly check their status and notify the user.

Under ISSU_62, the wallet stops presenting the obsolete credential and should delete it. A verifier that checks status can reject any surviving copy.

Revocation does not name the replacement. It solves the safety problem: the former statement is invalid, while the newly issued statement is valid.

The VCR_09 mandate applies when the credential is revocable and would otherwise remain valid for at least 24 hours. Otherwise, expiry limits the overlap.

The wallet still cannot declare the credential invalid on the issuer's behalf.

Background refresh is the exception

The relationship missing from an ordinary issuance can exist in the wallet's local refresh context.

If an automatic refresh starts from a stored credential, Yivi can retain that association throughout the issuance session: “this issuance updates credential X”.

That is not an inference from credential contents. The wallet knows which stored credential initiated the refresh.

Yivi can start a refresh from a stored credential, but lose that local association before the new copies reach storage.

Today, Yivi discards the association and later tries to reconstruct it from the content hash. Content comparison cannot recover context after it has been discarded.

OpenID4VCI lets a wallet obtain an updated credential with a valid access token, or use a refresh token to obtain one.

For a device-bound PID or attestation, ARF ISSU_65 requires the provider to verify that the re-issued credential goes to the same Wallet Unit.

Neither mechanism identifies a particular stored credential as the predecessor. A refresh token is not, by itself, a stable pointer to one logical credential.

ISSU_59 requires the wallet to compare old and new values during re-issuance and notify the user. Retaining the local association gives Yivi the context needed for that comparison.

User-initiated issuance is different. A universal link, QR code, or link in an email starts an authorization with no stored credential attached.

The result carries no more context than a first-time issuance. The provider must revoke any obsolete credential; Yivi should store the new one and follow the status of the old one.

Technical details

The following details explain why Yivi hashes type, issuer, and attributes, and why the issuer input must remain stable. They support the rule; they do not determine validity.

Why type and issuer both matter

The type says what kind of credential this is. In SD-JWT VC it is the vct claim; in mdoc it is the docType. It identifies neither the subject nor the issuer.

The issuer says who stands behind the claims. Yivi derives that identity differently by format:

  • SD-JWT VC uses the iss claim when present. Otherwise, it uses the identity in the certificate that signed the credential.
  • mdoc has no issuer field in the document. Its issuer identity comes from the certificate chain used to sign it.
  • If neither yields a usable name, Yivi falls back to the credential issuer URL used during issuance.

Consider two age_verification credentials that say age_over_18: true. One comes from the Dutch state and the other from a supermarket loyalty programme.

They make the same statement, but at different trust levels. A verifier may accept one issuer and reject the other, as the trust levels post explains.

Why issuers are fragile

The hash assumes that Yivi derives the same identity every time the same provider issues a credential. That assumption is more fragile than it looks.

For SD-JWT VC, a changed iss value changes the issuer input. For mdoc, a changed name in the signing certificate can do the same.

When the credential issuer URL is the fallback, a new domain, path, or trailing slash can also produce a different issuer identity.

If the type and attributes stay the same but the derived issuer identity changes, the complete hash changes. Yivi then treats the new technical credentials as a different logical credential.

The new credential may still be valid and verifiable. The failure is local continuity: the incoming batch no longer replaces the existing card, so the wallet keeps both.

Rotating keys or certificates is harmless to grouping only when the issuer identity that Yivi derives remains unchanged.

Today, issuers must keep that identity stable across renewals. Supporting intentional changes would require an explicit migration or alias mechanism; content hashing alone cannot connect the old and new identities.

If you issue credentials

Credential replacement starts with the issuer:

  1. Issue the updated credential.
  2. Revoke the obsolete technical copies when their claims are no longer true.
  3. Support automatic refresh so the wallet can update its local record without interrupting the user.
  4. Keep the issuer identity stable across renewals as much as possible.

Do not rely on matching type, issuer, or attributes to make a wallet invalidate an old credential. Those fields cannot distinguish a department transfer from an additional department.

During ordinary issuance, Yivi should follow revocation status. Only an automatic refresh may use a retained local association to replace the credential that initiated it.

If a credential cannot be revoked, its validity period determines how long an obsolete value remains usable. That is part of the issuer's credential design.

If you run an issuer and want to discuss your re-issuance flow, or think we have this wrong, we would like to hear from you: support@yivi.app.

Sources