Skip to content

SdJwtVcCredential.getClaimsImpl returns JWT envelope claims (iss, cnf, vct, exp, _sd_alg) as document claims #1946

Description

@mc1100

Version: observed on 0.99.0; re-checked against main @ 145e9e1a — unchanged.

What happens

getClaimsImpl iterates the entire verified SD-JWT payload and emits a JsonClaim for every top-level entry:

// By design, we only include the top-level claims.
val dt = documentTypeRepository?.getDocumentTypeForJson(vct)
for ((claimName, claimValue) in processedJwt) {
val attribute = dt?.jsonDocumentType?.claims?.get(claimName)
ret.add(
JsonClaim(
displayName = dt?.jsonDocumentType?.claims?.get(claimName)?.displayName ?: claimName,
attribute = attribute,
vct = vct,
claimPath = buildJsonArray { add(claimName) },
value = claimValue
)
)
}

The comment above the loop reads "By design, we only include the top-level claims" — which is precisely the problem: the JWT's own registered claims are top-level too. So a PID from the EU reference issuer comes back as

iss, iat, exp, vct, cnf, _sd_alg, family_name, given_name, birth_date, …

On first run, our document detail screen showed vct, iss and cnf as if they were attributes of the person — cnf being the holder key confirmation, i.e. a JSON object containing a public key rendered as a user-facing value.

Why it matters

Every consumer of this API has to know which JWT registered names to filter, and get that list right, or leak protocol internals into the UI. It is also inconsistent with the mdoc path, where the namespace structure keeps envelope data out of the claim set for free.

Suggested fix

Filter the SD-JWT VC envelope claims out of the returned list — at minimum iss, sub, aud, exp, nbf, iat, jti, cnf, vct, vct#integrity, status, _sd, _sd_alg (SD-JWT VC, draft/RFC registered claims). They remain available through the typed accessors on the credential (vct, validity, status) where a caller genuinely needs them.

Related

Workaround we ship

Our document reader filters the envelope names before displaying claims. The filter is load-bearing, not tidiness.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions