Skip to content

feat(issuer2): configure mdoc MSO validity via msoData - #2169

Open
JakeFernandes98 wants to merge 5 commits into
mainfrom
feature/wal-1365
Open

feat(issuer2): configure mdoc MSO validity via msoData#2169
JakeFernandes98 wants to merge 5 commits into
mainfrom
feature/wal-1365

Conversation

@JakeFernandes98

@JakeFernandes98 JakeFernandes98 commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Summary

This adds Issuer2 msoData so mDoc issuance can set ISO 18013-5 MSO ValidityInfo (validFrom, validUntil, optional expectedUpdate) at claim time. Operators can now choose a validity window other than the hardcoded ~365-day default, and timestamp data functions work for MSO dates the same way they already do for W3C mapping.

W3C mapping.validFrom / validUntil and mDL namespace issue_date / expiry_date are still not MSO fields. That mismatch is what WAL-1365 and WAL-1015 reported.

Related PRs:

What Changed

Public API

  • New optional msoData on Issuer2 profiles, runtimeOverrides, and issuance sessions. Accepted only for mso_mdoc; rejected on other formats.
  • Each of validFrom, validUntil, and expectedUpdate is a static ISO-8601 timestamp or a timestamp data function, resolved at claim time. signed is not configurable.
  • Offer overrides field-merge onto the profile (validFrom, validUntil, and expectedUpdate independently).
  • Authorization-code requests without issuer_state (including offerless) copy profile msoData onto the session.
  • Defaults are unchanged: validFrom equals the MSO signed time, validUntil is 365 days after claim, expectedUpdate is omitted.
  • Window rules are checked after ISO tdate second-normalization: validUntil must be after validFrom; validFrom cannot be before signed time; if set, expectedUpdate must fall between them.
  • Issuer/session policy is authoritative. Holder requestForm["validUntil"] does not change the signed MSO window.

Shared issuance

  • MsoData and claim-time MsoValidityResolver live in openid4vci so OSS and Enterprise share one resolution path.
  • Resolver order for validUntil: explicit msoData.validUntil → optional fallbackValidUntil → 365-day default. Enterprise uses the fallback for persisted IssuanceRequest.validUntil.
  • expectedUpdate is threaded through OAuth2Provider.createCredentialResponse, MdocCredentialSigner.generateMdocCredential, MdocIssuer, and both credential-handler sign overloads. W3C and SD-JWT handlers accept the argument and ignore it.
  • MsoMdocCredentialHandler.issueMdoc now receives the resolved instants instead of hardcoding validityDays = 365.
  • ValidityInfo.precheck() requires validUntil > validFrom and checks the expectedUpdate window. If a provided validFrom falls a moment behind the sign timestamp (claim-time resolve vs. signing), it is raised to signed so ISO validFrom >= signed still holds; a future validFrom is kept.

Issuer2 wiring

  • Profile load rejects msoData unless metadata format is mso_mdoc.
  • Offer creation stores the merged msoData on the session.
  • Offerless / no-issuer_state authorization sessions copy profile msoData.
  • The mDoc claim path resolves session msoData and passes the three instants into createCredentialResponse. Non-mDoc sessions that still carry msoData fail closed.

Tests

  • Resolver coverage for merge, defaults, static ISO-8601, timestamp functions, invalid windows, sub-second tdate collapse, and fallbackValidUntil.
  • Issued-MSO expectedUpdate on the crypto2 mDoc issuer path.
  • Handler coverage that holder requestForm["validUntil"] cannot extend a configured window, and that MsoMdocCredentialHandler forwards the resolved instants.
  • Profile mapping/rejection plus Issuer2 wallet flows for pre-authorized issuance, profile-level msoData, offerless scope and authorization_details sessions, and authorization-code with and without issuer_state.

Architecture Notes

  • msoData is nested, not top-level validFrom / validUntil, so it cannot be confused with W3C mapping or namespace claims.
  • Resolution runs at claim, not offer creation, matching existing data-function timing.
  • The library change is the contract Enterprise [PRO-954] include build statements in docker-compose.yaml #650 consumes; land or pin this PR first.

Caveats and Follow-Ups

  • Legacy Issuer (waltid-issuer-api) is unchanged.
  • signed remains issuer-generated.
  • Static validFrom must still be at or after claim/sign time; a timestamp captured at offer creation and claimed later is rejected.

Breaking

  • CredentialEndpointHandler / Crypto2CredentialEndpointHandler sign now require expectedUpdate: Instant?. Fun-interface implementors outside this repo must add the parameter.
  • OAuth2Provider.createCredentialResponse inserts expectedUpdate: Instant? = null before proofValidationContext. Named-argument callers are source-compatible; positional callers that passed proofValidationContext after validUntil must be updated.
  • MdocCredentialSigner.generateMdocCredential and MdocIssuer overloads add expectedUpdate: Instant?.
  • MsoMdocCredentialHandler.issueMdoc now takes validFrom, validUntil, and expectedUpdate (with validityDays as a fallback default). External subclasses must update their override.
  • Existing mDoc issuance without msoData keeps the previous defaults. No issued-credential format change when msoData is omitted.

Allow profile and offer msoData to set MSO validFrom, validUntil, and expectedUpdate at claim time, including timestamp data functions.
@linear-code

linear-code Bot commented Aug 31, 2026

Copy link
Copy Markdown

WAL-1365

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Team

Run ID: eeb1f750-d123-489d-9f99-de1129a0b323

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@szijpeter szijpeter left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The core MsoData/resolver design is sensible, but two supported issuance paths bypass or lose the configured policy and two public validity contracts remain incomplete; please also confirm the release decision for the binary-breaking expectedUpdate insertions in OAuth2Provider, MdocCredentialSigner, and MdocIssuer, which are only partially covered by the PR's Breaking section.

Keep issuer-configured MSO validity authoritative, copy profile msoData
into offerless auth-code sessions, and reject tdate windows that collapse
to equal seconds.
@JakeFernandes98

Copy link
Copy Markdown
Contributor Author

@szijpeter Thanks — all four inline items are addressed on 3616f1114.

On the binary-breaking expectedUpdate insertions: they stay. Named-argument callers remain source-compatible; positional callers and fun-interface / abstract issueMdoc implementors need the new parameter. The Breaking section now lists OAuth2Provider.createCredentialResponse, MdocCredentialSigner.generateMdocCredential, MdocIssuer, and MsoMdocCredentialHandler.issueMdoc in addition to the handler sign overloads.

@sonarqubecloud

sonarqubecloud Bot commented Sep 4, 2026

Copy link
Copy Markdown

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.

2 participants