[java-idp-plugin-vci] branch main updated: Improve readability of examples

Codeberg noreply at shibboleth.net
Thu Sep 24 18:08:29 UTC 2026


This is an automated email from the git hooks/post-receive script.

codeberg pushed a commit to branch main
in repository java-idp-plugin-vci.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/4257210d3da264e21409dfb9d735beeff279a593

The following commit(s) were added to refs/heads/main by this push:
     new 4257210  Improve readability of examples
4257210 is described below

commit 4257210d3da264e21409dfb9d735beeff279a593
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Thu Sep 24 21:08:11 2026 +0300

    Improve readability of examples
---
 README.md | 161 +++++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 111 insertions(+), 50 deletions(-)

diff --git a/README.md b/README.md
index ca0f72c..3d12a8a 100644
--- a/README.md
+++ b/README.md
@@ -217,7 +217,7 @@ but it is not guaranteed that they work for you as such.
 1. A did:jwk credential with both flows and the Status List. Signed with the key of the OP.
 2. A second credential, did:web.
 3. A third credential, the issuer is the plain url.
-4. The third credential is made an OpenID Federation credential. Own signing key is taken into use.
+4. The third credential is made an OpenID Federation credential.
 5. A fourth credential, for a HAIP wallet. Signing key gets a certificate chain. The wallet is
    the OpenID Foundation conformance suite.
 6. Rolling the signing key to the next one.
@@ -484,11 +484,15 @@ OP. One thing you need to add is the credential scopes in `scopes_supported` of
 *static/oauth-authorization-server.json*, a wallet of the code flow asks a credential by scope:
 
 ```json
+{
+   ...
    "scopes_supported":[
       "openid",
       "GeantIncubatorDiploma_SDJWT",
       "GeantIncubatorDiploma_W3C"
    ],
+   ...
+}
 ```
 
 The `/.well-known/` locations are not IdP paths, you wire them in Jetty. For this step you need
@@ -499,6 +503,8 @@ file is in [Discovery documents](#discovery-documents).
 <summary>Example snippet of etc/jetty-rewrite-rules.xml</summary>
 
 ```xml
+<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
+  ...
   <Call name="addRule">
     <Arg>
       <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
@@ -531,6 +537,7 @@ file is in [Discovery documents](#discovery-documents).
       </New>
     </Arg>
   </Call>
+</Configure>
 ```
 
 </details>
@@ -698,6 +705,8 @@ in the same *metadata/oidc-client.json* as the clients above:
 <summary>Example snippet of metadata/oidc-client.json</summary>
 
 ```json
+[
+  ...
   {
     "client_id": "id.animo.paradym",
     "client_name": "Paradym Wallet",
@@ -714,6 +723,7 @@ in the same *metadata/oidc-client.json* as the clients above:
       "urn:ietf:params:oauth:grant-type:pre-authorized_code"
     ]
   }
+]
 ```
 
 </details>
@@ -1026,6 +1036,11 @@ The credential goes next to the two of Step 1 in *metadata/verifiable-credential
 <summary>Example snippet of metadata/verifiable-credentials.json</summary>
 
 ```json
+{
+  "credential_configurations_supported": {
+    "GeantIncubatorDiploma_SDJWT": { "...": "..." },
+    "GeantIncubatorDiploma_W3C": { "...": "..." },
+    ...
     "GeantIncubatorDiploma_DIDWEB": {
       "format": "dc+sd-jwt",
       "vct": "GeantIncubatorDiploma_DIDWEB",
@@ -1053,6 +1068,8 @@ The credential goes next to the two of Step 1 in *metadata/verifiable-credential
         ]
       }
     }
+  }
+}
 ```
 
 </details>
@@ -1064,13 +1081,22 @@ and state it per credential.
 Add **DID.Document** to the anonymous relying party in *conf/relying-party.xml*:
 
 ```xml
-                <!-- A verifier resolves the did:web identifier from this -->
-                <ref bean="DID.Document" />
+<bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
+    <property name="profileConfigurations">
+        <list>
+            ...
+            <!-- A verifier resolves the did:web identifier from this -->
+            <ref bean="DID.Document" />
+        </list>
+    </property>
+</bean>
 ```
 
 and wire it in *etc/jetty-rewrite-rules.xml*:
 
 ```xml
+<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
+  ...
   <Call name="addRule">
     <Arg>
       <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
@@ -1079,6 +1105,7 @@ and wire it in *etc/jetty-rewrite-rules.xml*:
       </New>
     </Arg>
   </Call>
+</Configure>
 ```
 
 The document has no file behind it. It is formed from the keys that sign credentials and Status
@@ -1162,9 +1189,21 @@ The credential in *metadata/verifiable-credentials.json* is like the one of Step
 `GeantIncubatorDiploma_URL` and:
 
 ```json
+{
+  "credential_configurations_supported": {
+    ...
+    "GeantIncubatorDiploma_URL": {
+      "format": "dc+sd-jwt",
+      "vct": "GeantIncubatorDiploma_URL",
+      "scope": "GeantIncubatorDiploma_URL",
+      ...
       "_issuance_configuration": {
         "issuer": "url"
       },
+      "credential_metadata": { "...": "..." }
+    }
+  }
+}
 ```
 
 `url` is a keyword for the issuer of the OP. You may also write the url itself.
@@ -1172,13 +1211,22 @@ The credential in *metadata/verifiable-credentials.json* is like the one of Step
 Add **OAuth.JWTVCIssuer** to the anonymous relying party:
 
 ```xml
-                <!-- A verifier finds the key of a url issuer through this -->
-                <ref bean="OAuth.JWTVCIssuer" />
+<bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
+    <property name="profileConfigurations">
+        <list>
+            ...
+            <!-- A verifier finds the key of a url issuer through this -->
+            <ref bean="OAuth.JWTVCIssuer" />
+        </list>
+    </property>
+</bean>
 ```
 
 and wire it in *etc/jetty-rewrite-rules.xml*:
 
 ```xml
+<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
+  ...
   <Call name="addRule">
     <Arg>
       <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
@@ -1187,6 +1235,7 @@ and wire it in *etc/jetty-rewrite-rules.xml*:
       </New>
     </Arg>
   </Call>
+</Configure>
 ```
 
 *static/jwt-vc-issuer.json* as it comes with the plugin is fine. Its `jwks_uri` is the keyset of
@@ -1205,42 +1254,29 @@ authority hints and so on, is configured in the plugins of [Dependencies](#depen
 
 What is new:
 
-- an own signing key replaces the keys of the OP in credential signing
 - the Entity Configuration at `/.well-known/openid-federation` has `openid_credential_issuer`
   metadata and the credential signing keys
 - the url credential carries `"fed": "https://issuer.example.org"`, the other credentials not
 
-#### Own signing key
+#### Signing key
 
-The federation part reads the signing keys of the credentials from
-**openidvci.SigningCredentials**, so that list has to be defined now. Generate an EC key the
-same way as the keys of the OP:
+The Entity Configuration publishes the keys credentials are signed with, and it reads them from
+**openidvci.SigningCredentials**. The keys of the OP are not visible to it, so the list has to
+be defined even if the signing key stays the same. The IdP does not start with the federation
+import and without the list.
 
-```bash
-bin/jwtgen.sh -t EC -c P-256 -u sig -i signingvci | tail -n +2 > credentials/openid-vci-signing-es.jwk
-```
-
-Uncomment the key and the list in *conf/openid-vci-credentials.xml*. Keep the EC key of the OP
-in the list after the new one. It is defined here again from the same file, as the bean of the
-OP is not visible where this file is imported:
+In *conf/openid-vci-credentials.xml* the EC key of the OP is defined again from the same file and
+put in the list. Nothing changes in signing:
 
 ```xml
-<bean id="openidvci.DefaultESSigningCredential" parent="shibboleth.JWKCredential"
-    p:resource="%{openidvci.signing.es.key}" />
-
-<bean id="openidvci.PreviousESSigningCredential" parent="shibboleth.JWKCredential"
+<bean id="openidvci.OPESSigningCredential" parent="shibboleth.JWKCredential"
     p:resource="%{idp.signing.oidc.es.key}" />
 
 <util:list id="openidvci.SigningCredentials">
-    <ref bean="openidvci.DefaultESSigningCredential" />
-    <ref bean="openidvci.PreviousESSigningCredential" />
+    <ref bean="openidvci.OPESSigningCredential" />
 </util:list>
 ```
 
-The first key that fits the algorithm signs, the others are there only to be published. This
-is a key rollover from the key of the OP to the own key. [Step 6](#step-6-rolling-the-signing-key)
-tells why the old key stays.
-
 Import the file into *conf/global.xml*. Normally it would go to *conf/credentials.xml*, but the
 Entity Configuration is published from the root context and it does not see beans of
 *conf/credentials.xml*:
@@ -1249,22 +1285,6 @@ Entity Configuration is published from the root context and it does not see bean
 <import resource="openid-vci-credentials.xml"/>
 ```
 
-The url credential names its key through the keyset of the OP, and the new key is not in that
-keyset. Publish it in *conf/oidc-credentials.xml*. The list replaces what is published, so
-the keys of the OP are listed too. If that file has an `alias` named
-`shibboleth.oidc.SigningCredentialsToPublish`, remove it:
-
-```xml
-<util:list id="shibboleth.oidc.SigningCredentialsToPublish">
-    <ref bean="shibboleth.oidc.DefaultRSSigningCredential" />
-    <ref bean="shibboleth.oidc.DefaultESSigningCredential" />
-    <ref bean="openidvci.DefaultESSigningCredential" />
-</util:list>
-```
-
-Publish the key before you start signing with it. A verifier that fetched the keyset earlier
-may have the old one in cache.
-
 #### Federation
 
 The Entity Identifier and `credential_issuer` of the Credential Issuer metadata have to be the
@@ -1291,13 +1311,38 @@ Once the import is there every credential states the Entity Identifier, unless i
 `"oidfed": false`. We want only the url credential in the federation, so the three others get:
 
 ```json
+{
+  "credential_configurations_supported": {
+    "GeantIncubatorDiploma_SDJWT": {
+      ...
       "_issuance_configuration": {
         "oidfed": false
-      },
+      }
+    },
+    "GeantIncubatorDiploma_W3C": {
+      ...
+      "_issuance_configuration": {
+        "oidfed": false
+      }
+    },
+    "GeantIncubatorDiploma_DIDWEB": {
+      ...
+      "_issuance_configuration": {
+        "issuer": "did:web",
+        "oidfed": false
+      }
+    },
+    "GeantIncubatorDiploma_URL": {
+      ...
+      "_issuance_configuration": {
+        "issuer": "url"
+      }
+    }
+  }
+}
 ```
 
-`GeantIncubatorDiploma_DIDWEB` has `"issuer": "did:web"` there already, the two members go
-side by side. The url credential then carries:
+The url credential then carries:
 
 ```json
 {
@@ -1360,8 +1405,7 @@ put **first** in the list. The key needs a name, `p:keyNames`, for the did:web d
 
 <util:list id="openidvci.SigningCredentials">
     <ref bean="openidvci.X509ESSigningCredential" />
-    <ref bean="openidvci.DefaultESSigningCredential" />
-    <ref bean="openidvci.PreviousESSigningCredential" />
+    <ref bean="openidvci.OPESSigningCredential" />
 </util:list>
 
 <util:list id="openidvci.issuerMetadata.SigningCredentials">
@@ -1372,7 +1416,7 @@ put **first** in the list. The key needs a name, `p:keyNames`, for the did:web d
 The chain is emitted whenever the issuer of the signed thing is an https url, there is no
 switch for it. That means the url credential of Steps 3 and 4 now carries `x5c` too, and no
 `kid`. A verifier of it moves from `/.well-known/jwt-vc-issuer` to the chain. The did:jwk and
-did:web credentials do not carry a chain, their identifier resolves the key. This is again a key
+did:web credentials do not carry a chain, their identifier resolves the key. This is a key
 rollover, see [Step 6](#step-6-rolling-the-signing-key).
 
 #### The credential
@@ -1384,6 +1428,11 @@ attestation required:
 <summary>Example snippet of metadata/verifiable-credentials.json</summary>
 
 ```json
+{
+  "credential_configurations_supported": {
+    "GeantIncubatorDiploma_SDJWT": { "...": "..." },
+    "GeantIncubatorDiploma_W3C": { "...": "..." },
+    ...
     "GeantIncubatorDiploma_HAIP": {
       "format": "dc+sd-jwt",
       "vct": "GeantIncubatorDiploma_HAIP",
@@ -1416,6 +1465,8 @@ attestation required:
         ]
       }
     }
+  }
+}
 ```
 
 </details>
@@ -1476,6 +1527,8 @@ being the alias of your test plan:
 <summary>Example snippet of metadata/oidc-client.json</summary>
 
 ```json
+[
+  ...
   {
     "client_id": "conformance_client_1",
     "client_name": "OpenID Conformance Suite",
@@ -1496,6 +1549,7 @@ being the alias of your test plan:
     "response_types": ["code"],
     "grant_types": ["authorization_code", "urn:ietf:params:oauth:grant-type:pre-authorized_code"]
   }
+]
 ```
 
 </details>
@@ -1507,6 +1561,8 @@ response and both token and PAR endpoints take the Wallet Attestation:
 <summary>Example snippet of conf/relying-party.xml</summary>
 
 ```xml
+<util:list id="shibboleth.RelyingPartyOverrides">
+    ...
         <bean parent="RelyingPartyByName"
               c:relyingPartyIds="#{{'conformance_client_1','conformance_client_2'}}">
           <property name="profileConfigurations">
@@ -1523,6 +1579,7 @@ response and both token and PAR endpoints take the Wallet Attestation:
               </list>
           </property>
         </bean>
+</util:list>
 ```
 
 </details>
@@ -1537,6 +1594,8 @@ Advertise the rest in *static/oauth-authorization-server.json*. `GeantIncubatorD
 `scopes_supported` as before and these are added:
 
 ```json
+{
+   ...
    "token_endpoint_auth_methods_supported":[
       "none",
       "client_secret_basic",
@@ -1547,6 +1606,8 @@ Advertise the rest in *static/oauth-authorization-server.json*. `GeantIncubatorD
    "client_attestation_signing_alg_values_supported":[ "ES256" ],
    "client_attestation_pop_signing_alg_values_supported":[ "ES256" ],
    "authorization_response_iss_parameter_supported":true,
+   ...
+}
 ```
 
 #### Suite configuration
@@ -1577,7 +1638,7 @@ above.
 
 ### Step 6: Rolling the signing key
 
-Steps 4 and 5 changed the signing key. What a key change means depends on the issuer
+Step 5 changed the signing key. What a key change means depends on the issuer
 identifier of the credential. The configuration is the same for all:
 
 1. The new key goes **first** in **openidvci.SigningCredentials**. The first key that fits the

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list