Skip to content

Commit cb7f1ca

Browse files
committed
Initial VCDM 2.0 VC-SD-JWT
1 parent 8e0a5fb commit cb7f1ca

File tree

2 files changed

+147
-2
lines changed

2 files changed

+147
-2
lines changed

config/module_oidc.php.dist

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,6 +966,101 @@ $config = [
966966
// REQUIRED
967967
ClaimsEnum::Vct->value => 'ResearchAndScholarshipCredentialDcSdJwt',
968968
],
969+
970+
'ResearchAndScholarshipCredentialVcSdJwt' => [
971+
ClaimsEnum::Format->value => CredentialFormatIdentifiersEnum::VcSdJwt->value,
972+
ClaimsEnum::Scope->value => 'ResearchAndScholarshipCredentialVcSdJwt',
973+
ClaimsEnum::Display->value => [
974+
[
975+
ClaimsEnum::Name->value => 'ResearchAndScholarshipCredentialVcSdJwt',
976+
ClaimsEnum::Locale->value => 'en-US',
977+
ClaimsEnum::Description->value => 'Research and Scholarship Credential',
978+
],
979+
],
980+
ClaimsEnum::Claims->value => [
981+
[
982+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'eduPersonPrincipalName'],
983+
ClaimsEnum::Mandatory->value => true,
984+
ClaimsEnum::Display->value => [
985+
[
986+
ClaimsEnum::Name->value => 'Principal Name',
987+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
988+
],
989+
],
990+
],
991+
[
992+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'eduPersonTargetedID'],
993+
ClaimsEnum::Mandatory->value => false,
994+
ClaimsEnum::Display->value => [
995+
[
996+
ClaimsEnum::Name->value => 'Targeted ID',
997+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
998+
],
999+
],
1000+
],
1001+
[
1002+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'displayName'],
1003+
ClaimsEnum::Mandatory->value => false,
1004+
ClaimsEnum::Display->value => [
1005+
[
1006+
ClaimsEnum::Name->value => 'Display Name',
1007+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
1008+
],
1009+
],
1010+
],
1011+
[
1012+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'givenName'],
1013+
ClaimsEnum::Mandatory->value => false,
1014+
ClaimsEnum::Display->value => [
1015+
[
1016+
ClaimsEnum::Name->value => 'Given Name',
1017+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
1018+
],
1019+
],
1020+
],
1021+
[
1022+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'sn'],
1023+
ClaimsEnum::Display->value => [
1024+
[
1025+
ClaimsEnum::Name->value => 'Last Name',
1026+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
1027+
],
1028+
],
1029+
],
1030+
[
1031+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'mail'],
1032+
ClaimsEnum::Display->value => [
1033+
[
1034+
ClaimsEnum::Name->value => 'Email Address',
1035+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
1036+
],
1037+
],
1038+
],
1039+
[
1040+
ClaimsEnum::Path->value => [ClaimsEnum::Credential_Subject->value, 'eduPersonScopedAffiliation'],
1041+
ClaimsEnum::Display->value => [
1042+
[
1043+
ClaimsEnum::Name->value => 'Scoped Affiliation',
1044+
ClaimsEnum::Locale->value => LanguageTagsEnum::EnUs->value,
1045+
],
1046+
],
1047+
],
1048+
],
1049+
1050+
/**
1051+
* VCDM 2.0 context is REQUIRED for 'vc+sd-jwt' format.
1052+
*/
1053+
ClaimsEnum::AtContext->value => [
1054+
AtContextsEnum::W3OrgNsCredentialsV2->value,
1055+
],
1056+
1057+
// REQUIRED
1058+
/** @see https://www.w3.org/TR/vc-data-model-2.0/#types */
1059+
ClaimsEnum::Type->value => [
1060+
CredentialTypesEnum::VerifiableCredential->value,
1061+
'ResearchAndScholarshipCredentialVcSdJwt',
1062+
],
1063+
],
9691064
],
9701065

9711066
/**
@@ -999,6 +1094,15 @@ $config = [
9991094
['mail' => ['mail']],
10001095
['eduPersonScopedAffiliation' => ['eduPersonScopedAffiliation']],
10011096
],
1097+
'ResearchAndScholarshipCredentialVcSdJwt' => [
1098+
['eduPersonPrincipalName' => [ClaimsEnum::Credential_Subject->value, 'eduPersonPrincipalName']],
1099+
['eduPersonTargetedID' => [ClaimsEnum::Credential_Subject->value, 'eduPersonTargetedID']],
1100+
['displayName' => [ClaimsEnum::Credential_Subject->value, 'displayName']],
1101+
['givenName' => [ClaimsEnum::Credential_Subject->value, 'givenName']],
1102+
['sn' => [ClaimsEnum::Credential_Subject->value, 'sn']],
1103+
['mail' => [ClaimsEnum::Credential_Subject->value, 'mail']],
1104+
['eduPersonScopedAffiliation' => [ClaimsEnum::Credential_Subject->value, 'eduPersonScopedAffiliation']],
1105+
],
10021106
],
10031107

10041108
/**

src/Controllers/VerifiableCredentials/CredentialIssuerCredentialController.php

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -612,6 +612,10 @@ public function credential(Request $request): Response
612612
continue;
613613
}
614614

615+
if ($credentialFormatId === CredentialFormatIdentifiersEnum::VcSdJwt->value) {
616+
array_unshift($credentialClaimPath, ClaimsEnum::Credential_Subject->value);
617+
}
618+
615619
/** @psalm-suppress ArgumentTypeCoercion */
616620
$disclosure = $this->verifiableCredentials->disclosureFactory()->build(
617621
value: $attributeValue,
@@ -688,7 +692,7 @@ public function credential(Request $request): Response
688692
);
689693
}
690694

691-
if (in_array($credentialFormatId, self::SD_JWT_FORMAT_IDS, true)) {
695+
if ($credentialFormatId === CredentialFormatIdentifiersEnum::DcSdJwt->value) {
692696
$sdJwtPayload = [
693697
ClaimsEnum::Iss->value => $issuerDid,
694698
ClaimsEnum::Iat->value => $issuedAt->getTimestamp(),
@@ -712,7 +716,44 @@ public function credential(Request $request): Response
712716
ClaimsEnum::Kid->value => $issuerDid . '#0',
713717
],
714718
disclosureBag: $disclosureBag,
715-
jwtTypesEnum: JwtTypesEnum::VcSdJwt,
719+
jwtTypesEnum: JwtTypesEnum::DcSdJwt,
720+
);
721+
}
722+
723+
if ($credentialFormatId === CredentialFormatIdentifiersEnum::VcSdJwt->value) {
724+
$sdJwtPayload = [
725+
ClaimsEnum::AtContext->value => [
726+
AtContextsEnum::W3OrgNsCredentialsV2->value,
727+
],
728+
ClaimsEnum::Id->value => $vcId,
729+
ClaimsEnum::Type->value => [
730+
CredentialTypesEnum::VerifiableCredential->value,
731+
$resolvedCredentialIdentifier,
732+
],
733+
ClaimsEnum::Issuer->value => $issuerDid,
734+
ClaimsEnum::ValidFrom->value => $issuedAt->format(\DateTimeInterface::RFC3339),
735+
ClaimsEnum::Credential_Subject->value =>
736+
$credentialSubject[ClaimsEnum::Credential_Subject->value] ?? [],
737+
ClaimsEnum::Iss->value => $issuerDid,
738+
ClaimsEnum::Iat->value => $issuedAt->getTimestamp(),
739+
ClaimsEnum::Nbf->value => $issuedAt->getTimestamp(),
740+
ClaimsEnum::Sub->value => $sub,
741+
ClaimsEnum::Jti->value => $vcId,
742+
];
743+
744+
if ($proof instanceof OpenId4VciProof) {
745+
$sdJwtPayload[ClaimsEnum::Cnf->value] = [
746+
ClaimsEnum::Kid->value => $proof->getKeyId(),
747+
];
748+
}
749+
750+
$verifiableCredential = $this->verifiableCredentials->vcSdJwtFactory()->fromData(
751+
$signingKey,
752+
$signatureAlgorithm,
753+
$sdJwtPayload,
754+
[
755+
ClaimsEnum::Kid->value => $issuerDid . '#0',
756+
],
716757
);
717758
}
718759

0 commit comments

Comments
 (0)