[java-idp-plugin-vci] 01/01: Exampe files shown in README

Codeberg noreply at shibboleth.net
Fri Oct 2 05:14:15 UTC 2026


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

codeberg pushed a commit to branch dev/READMEDOCS
in repository java-idp-plugin-vci.

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

commit 4dc4c18a0f6ca35ac9941942845e2a2e6f1101e7
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Fri Oct 2 08:13:55 2026 +0300

    Exampe files shown in README
---
 README.md                                          | 217 +++++++++++++--------
 docs/example/step-1/conf/attribute-filter.xml      |  15 ++
 docs/example/step-1/conf/relying-party.xml         |  92 +++++++++
 docs/example/step-1/etc/jetty-rewrite-rules.xml    |  50 +++++
 docs/example/step-1/metadata/oidc-client.json      |  29 +++
 .../step-1/metadata/verifiable-credentials.json    |  69 +++++++
 .../step-1/static/oauth-authorization-server.json  |  37 ++++
 .../credentials/GeantIncubatorDiploma_W3C.json     |  10 +
 docs/example/step-2/conf/attribute-filter.xml      |  15 ++
 .../example/step-2/conf/openid-vci-credentials.xml |  18 ++
 docs/example/step-2/conf/relying-party.xml         |  94 +++++++++
 docs/example/step-2/etc/jetty-rewrite-rules.xml    |  59 ++++++
 docs/example/step-2/metadata/oidc-client.json      |  29 +++
 .../step-2/metadata/verifiable-credentials.json    |  96 +++++++++
 .../step-2/static/oauth-authorization-server.json  |  38 ++++
 .../credentials/GeantIncubatorDiploma_W3C.json     |  10 +
 16 files changed, 800 insertions(+), 78 deletions(-)

diff --git a/README.md b/README.md
index 18c5d8e..d61ac64 100644
--- a/README.md
+++ b/README.md
@@ -1071,47 +1071,47 @@ What is new:
 - the Status List url of the credential ends with `~did-web`
 - the plugin gets a signing key list of its own, with the EC key of the OP only
 
-The credential goes next to the two of Step 1 in *metadata/verifiable-credentials.json*:
+The changes per file, each with a link to the whole file after this step:
 
 <details>
-<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",
-      "scope": "GeantIncubatorDiploma_DIDWEB",
-      "cryptographic_binding_methods_supported": ["did:jwk"],
-      "proof_types_supported": {
-        "jwt": {
-          "proof_signing_alg_values_supported": ["ES256"]
-        }
-      },
-      "_issuance_configuration": {
-        "issuer": "did:web"
-      },
-      "credential_metadata": {
-        "display": [
-          { "name": "Incubator Diploma, did:web", "locale": "en" }
-        ],
-        "claims": [
-          { "path": ["diploma"],     "display": [{ "name": "Diploma",        "locale": "en" }] },
-          { "path": ["mail"],        "display": [{ "name": "Email",          "locale": "en" }] },
-          { "path": ["eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
-          { "path": ["givenName"],   "display": [{ "name": "Given names",    "locale": "en" }] },
-          { "path": ["familyName"],  "display": [{ "name": "Family name",    "locale": "en" }] },
-          { "path": ["affiliation"], "display": [{ "name": "Affiliation",    "locale": "en" }] }
-        ]
-      }
-    }
-  }
-}
-```
+<summary>metadata/verifiable-credentials.json</summary>
+
+```diff
+ ...
+         ]
+       }
++    },
++    "GeantIncubatorDiploma_DIDWEB": {
++      "format": "dc+sd-jwt",
++      "vct": "GeantIncubatorDiploma_DIDWEB",
++      "scope": "GeantIncubatorDiploma_DIDWEB",
++      "cryptographic_binding_methods_supported": ["did:jwk"],
++      "proof_types_supported": {
++        "jwt": {
++          "proof_signing_alg_values_supported": ["ES256"]
++        }
++      },
++      "_issuance_configuration": {
++        "issuer": "did:web"
++      },
++      "credential_metadata": {
++        "display": [
++          { "name": "Incubator Diploma, did:web", "locale": "en" }
++        ],
++        "claims": [
++          { "path": ["diploma"],     "display": [{ "name": "Diploma",        "locale": "en" }] },
++          { "path": ["mail"],        "display": [{ "name": "Email",          "locale": "en" }] },
++          { "path": ["eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
++          { "path": ["givenName"],   "display": [{ "name": "Given names",    "locale": "en" }] },
++          { "path": ["familyName"],  "display": [{ "name": "Family name",    "locale": "en" }] },
++          { "path": ["affiliation"], "display": [{ "name": "Affiliation",    "locale": "en" }] }
++        ]
++      }
+     }
+   }
+```
+
+Full file: [metadata/verifiable-credentials.json](docs/example/step-2/metadata/verifiable-credentials.json)
 
 </details>
 
@@ -1119,50 +1119,117 @@ Setting `openidvci.issuer = did:web` in *conf/openid-vci.properties* would do th
 credential that states no `issuer` of its own. Here we keep the deployment default as did:jwk
 and state it per credential.
 
-Add **DID.Document** to the anonymous relying party in *conf/relying-party.xml*:
+<details>
+<summary>conf/relying-party.xml</summary>
 
-```xml
-<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>
+```diff
+ ...
+                 <!-- Of the OP plugin. Needed for the audience values of the wallet -->
+                 <ref bean="OAUTH2.TokenAudience" />
++                <!-- A verifier resolves the did:web identifier from this -->
++                <ref bean="DID.Document" />
+             </list>
+         </property>
 ```
 
-and wire it in *etc/jetty-rewrite-rules.xml*:
+Full file: [conf/relying-party.xml](docs/example/step-2/conf/relying-party.xml)
 
-```xml
-<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
-  ...
-  <Call name="addRule">
-    <Arg>
-      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
-        <Set name="pattern">/.well-known/did.json</Set>
-        <Set name="replacement">/idp/profile/did/document</Set>
-      </New>
-    </Arg>
-  </Call>
-</Configure>
+</details>
+
+<details>
+<summary>etc/jetty-rewrite-rules.xml</summary>
+
+```diff
+ ...
+     </Arg>
+   </Call>
++  <!-- The did:web document -->
++  <Call name="addRule">
++    <Arg>
++      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
++        <Set name="pattern">/.well-known/did.json</Set>
++        <Set name="replacement">/idp/profile/did/document</Set>
++      </New>
++    </Arg>
++  </Call>
+   <!-- Wallets running in a browser need this -->
+   <Call name="addRule">
+```
+
+Full file: [etc/jetty-rewrite-rules.xml](docs/example/step-2/etc/jetty-rewrite-rules.xml)
+
+</details>
+
+<details>
+<summary>metadata/oidc-client.json</summary>
+
+```diff
+ ...
+     "client_name": "Paradym Wallet",
+     "redirect_uris": ["https://paradym.id/invitation/redirect"],
+-    "scope": "openid GeantIncubatorDiploma_SDJWT GeantIncubatorDiploma_W3C",
++    "scope": "openid GeantIncubatorDiploma_SDJWT GeantIncubatorDiploma_W3C GeantIncubatorDiploma_DIDWEB",
+     "audience": [
+       "credentials",
 ```
 
-The document has no file behind it. It is formed from the keys of
+Full file: [metadata/oidc-client.json](docs/example/step-2/metadata/oidc-client.json)
+
+</details>
+
+<details>
+<summary>static/oauth-authorization-server.json</summary>
+
+```diff
+ ...
+       "openid",
+       "GeantIncubatorDiploma_SDJWT",
+-      "GeantIncubatorDiploma_W3C"
++      "GeantIncubatorDiploma_W3C",
++      "GeantIncubatorDiploma_DIDWEB"
+    ],
+    "authorization_details_types_supported":[
+```
+
+Full file: [static/oauth-authorization-server.json](docs/example/step-2/static/oauth-authorization-server.json)
+
+</details>
+
+The did:web document has no file behind it. It is formed from the keys of
 **openidvci.SigningCredentials**. Without that list it would have all the signing keys of the OP,
 also the RSA key. 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:
 
+<details>
+<summary>conf/openid-vci-credentials.xml</summary>
+
 ```xml
-<bean id="openidvci.OPESSigningCredential" parent="shibboleth.JWKCredential"
-    p:resource="%{idp.signing.oidc.es.key}" />
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean id="openidvci.OPESSigningCredential" parent="shibboleth.JWKCredential"
+        p:resource="%{idp.signing.oidc.es.key}" />
+
+    <util:list id="openidvci.SigningCredentials">
+        <ref bean="openidvci.OPESSigningCredential" />
+    </util:list>
 
-<util:list id="openidvci.SigningCredentials">
-    <ref bean="openidvci.OPESSigningCredential" />
-</util:list>
+</beans>
 ```
 
+Full file: [conf/openid-vci-credentials.xml](docs/example/step-2/conf/openid-vci-credentials.xml)
+
+</details>
+
+A key needs a name to be listed, the `kid` of a JWK key. The EC key of the OP has one.
+
 Import the file into *conf/global.xml*. The Entity Configuration of
 [Step 4](#step-4-make-the-url-credential-an-openid-federation-credential) does not see beans of
 *conf/credentials.xml*:
@@ -1171,6 +1238,9 @@ Import the file into *conf/global.xml*. The Entity Configuration of
 <import resource="openid-vci-credentials.xml"/>
 ```
 
+Add `<AttributeEncoder xsi:type="oidc:OIDCString" name="GeantIncubatorDiploma_DIDWEB" />` to the
+attribute definition of Step 1. The claims are the same, so the script does not change.
+
 <details>
 <summary>Example of the document at /.well-known/did.json</summary>
 
@@ -1203,15 +1273,6 @@ Import the file into *conf/global.xml*. The Entity Configuration of
 
 </details>
 
-A key needs a name to be listed, the `kid` of a JWK key. The EC key of the OP has one.
-
-To make the credential requestable, the same small additions for both flows:
-
-- `GeantIncubatorDiploma_DIDWEB` to `scope` of `id.animo.paradym` in *metadata/oidc-client.json*
-- the same to `scopes_supported` of *static/oauth-authorization-server.json*
-- `<AttributeEncoder xsi:type="oidc:OIDCString" name="GeantIncubatorDiploma_DIDWEB" />` to the
-  attribute definition of Step 1. The claims are the same, so the script does not change.
-
 And the offer of the pre-authorized code flow has the new id:
 
 ```bash
diff --git a/docs/example/step-1/conf/attribute-filter.xml b/docs/example/step-1/conf/attribute-filter.xml
new file mode 100644
index 0000000..b10fb12
--- /dev/null
+++ b/docs/example/step-1/conf/attribute-filter.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AttributeFilterPolicyGroup id="ShibbolethFilterPolicy"
+        xmlns="urn:mace:shibboleth:2.0:afp"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="urn:mace:shibboleth:2.0:afp http://shibboleth.net/schema/idp/shibboleth-afp.xsd">
+
+    <AttributeFilterPolicy id="GeantIncubatorDiplomaToWallets">
+        <PolicyRequirementRule xsi:type="Requester"
+            value="id.animo.paradym" />
+        <AttributeRule attributeID="GeantIncubatorDiploma">
+            <PermitValueRule xsi:type="ANY" />
+        </AttributeRule>
+    </AttributeFilterPolicy>
+
+</AttributeFilterPolicyGroup>
diff --git a/docs/example/step-1/conf/relying-party.xml b/docs/example/step-1/conf/relying-party.xml
new file mode 100644
index 0000000..87e6a74
--- /dev/null
+++ b/docs/example/step-1/conf/relying-party.xml
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
+        <property name="profileConfigurations">
+            <list>
+                <!-- The wallet reads the Credential Issuer metadata -->
+                <ref bean="OpenID.VCI.IssuerMetadata" />
+                <!-- The wallet finds the token endpoint through this one -->
+                <ref bean="OAuth.AuthorizationServer" />
+                <!-- The wallet asks for the nonce its key proof has to carry -->
+                <ref bean="OpenID.VCI.Nonce" />
+                <!-- A verifier reads the Status List -->
+                <ref bean="OAuth.StatusList" />
+                <!-- Of the OP plugin. Publishes the keys of the OP as a keyset -->
+                <ref bean="OIDC.Keyset" />
+                <!-- Of the OP plugin. Serves /.well-known/openid-configuration -->
+                <ref bean="OIDC.Configuration" />
+                <!-- Of the OP plugin. Needed for the audience values of the wallet -->
+                <ref bean="OAUTH2.TokenAudience" />
+            </list>
+        </property>
+    </bean>
+
+    <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
+        <property name="profileConfigurations">
+            <list>
+                <ref bean="SAML2.SSO" />
+                <ref bean="SAML2.ECP" />
+                <ref bean="SAML2.Logout" />
+                <ref bean="SAML2.ArtifactResolution" />
+            </list>
+        </property>
+    </bean>
+
+    <util:list id="shibboleth.RelyingPartyOverrides">
+
+        <bean parent="RelyingPartyByName" c:relyingPartyIds="offer-caller">
+          <property name="profileConfigurations">
+              <list>
+                  <bean parent="OpenID.VCI.CredentialOffer"
+                        p:tokenEndpointAuthMethods="#{{'client_secret_basic'}}" />
+                  <bean parent="OAuth.StatusList.Revoke"
+                        p:tokenEndpointAuthMethods="#{{'client_secret_basic'}}" />
+                  <bean parent="OAuth.StatusList.Assignments"
+                        p:tokenEndpointAuthMethods="#{{'client_secret_basic'}}" />
+              </list>
+          </property>
+        </bean>
+
+        <bean parent="RelyingPartyByName" c:relyingPartyIds="offer-caller/wallet">
+          <property name="profileConfigurations">
+              <list>
+                  <bean parent="OpenID.VCI.Token"
+                        p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy"
+                        p:tokenEndpointAuthMethods="#{{'none'}}" />
+                  <bean parent="OpenID.VCI.Credentials" />
+              </list>
+          </property>
+        </bean>
+
+        <bean parent="RelyingPartyByName"
+              c:relyingPartyIds="#{{'id.animo.paradym'}}">
+          <property name="profileConfigurations">
+              <list>
+                  <bean parent="OIDC.SSO"
+                        p:authorizationCodeClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy"
+                        p:forcePKCE="true"
+                        p:requirePushedAuthorizationRequest="true" />
+                  <bean parent="OpenID.VCI.Token"
+                        p:tokenEndpointAuthMethods="#{{'none'}}"
+                        p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy" />
+                  <bean parent="OpenID.VCI.Credentials" />
+                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'none'}}"
+                        p:requestUriClaimsSetManipulationStrategy-ref="openidvci.PushedAuthorizationDPoPJktManipulationStrategy" />
+              </list>
+          </property>
+        </bean>
+
+    </util:list>
+
+</beans>
diff --git a/docs/example/step-1/etc/jetty-rewrite-rules.xml b/docs/example/step-1/etc/jetty-rewrite-rules.xml
new file mode 100644
index 0000000..d7017ac
--- /dev/null
+++ b/docs/example/step-1/etc/jetty-rewrite-rules.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">
+<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
+  <!-- Credential Issuer metadata -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/openid-credential-issuer</Set>
+        <Set name="replacement">/idp/profile/openid/vci/issuer-metadata</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- Authorization server metadata -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/oauth-authorization-server</Set>
+        <Set name="replacement">/idp/profile/oauth/authorization-server</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- OP metadata, of the OP plugin -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/openid-configuration</Set>
+        <Set name="replacement">/idp/profile/oidc/configuration</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- The JSON-LD context of the vc+sd-jwt credential is a static file of Jetty -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/credentials/GeantIncubatorDiploma_W3C</Set>
+        <Set name="replacement">/credentials/GeantIncubatorDiploma_W3C.json</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- Wallets running in a browser need this -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+        <Set name="pattern">/*</Set>
+        <Set name="headerName">Access-Control-Allow-Origin</Set>
+        <Set name="headerValue">*</Set>
+      </New>
+    </Arg>
+  </Call>
+</Configure>
diff --git a/docs/example/step-1/metadata/oidc-client.json b/docs/example/step-1/metadata/oidc-client.json
new file mode 100644
index 0000000..a95e4a5
--- /dev/null
+++ b/docs/example/step-1/metadata/oidc-client.json
@@ -0,0 +1,29 @@
+[
+  {
+    "client_id": "offer-caller",
+    "client_name": "Credential offer caller",
+    "client_secret": "CHANGE-ME"
+  },
+  {
+    "client_id": "offer-caller/wallet",
+    "client_name": "Wallets redeeming a pre-authorized code minted by offer-caller",
+    "token_endpoint_auth_method": "none",
+    "grant_types": ["urn:ietf:params:oauth:grant-type:pre-authorized_code"]
+  },
+  {
+    "client_id": "id.animo.paradym",
+    "client_name": "Paradym Wallet",
+    "redirect_uris": ["https://paradym.id/invitation/redirect"],
+    "scope": "openid GeantIncubatorDiploma_SDJWT GeantIncubatorDiploma_W3C",
+    "audience": [
+      "credentials",
+      "urn:shibboleth.oidc.op.resource:https://issuer.example.org"
+    ],
+    "token_endpoint_auth_method": "none",
+    "response_types": ["code"],
+    "grant_types": [
+      "authorization_code",
+      "urn:ietf:params:oauth:grant-type:pre-authorized_code"
+    ]
+  }
+]
diff --git a/docs/example/step-1/metadata/verifiable-credentials.json b/docs/example/step-1/metadata/verifiable-credentials.json
new file mode 100644
index 0000000..f1df0c1
--- /dev/null
+++ b/docs/example/step-1/metadata/verifiable-credentials.json
@@ -0,0 +1,69 @@
+{
+  "credential_configurations_supported": {
+    "GeantIncubatorDiploma_SDJWT": {
+      "format": "dc+sd-jwt",
+      "vct": "GeantIncubatorDiploma_SDJWT",
+      "scope": "GeantIncubatorDiploma_SDJWT",
+      "cryptographic_binding_methods_supported": ["did:jwk"],
+      "proof_types_supported": {
+        "jwt": {
+          "proof_signing_alg_values_supported": ["ES256"]
+        }
+      },
+      "credential_metadata": {
+        "display": [
+          {
+            "name": "Incubator Diploma",
+            "locale": "en",
+            "description": "Diploma issued by the Trust and Identity Incubator"
+          }
+        ],
+        "claims": [
+          { "path": ["diploma"],     "display": [{ "name": "Diploma",      "locale": "en" }] },
+          { "path": ["mail"],        "display": [{ "name": "Email",        "locale": "en" }] },
+          { "path": ["eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
+          { "path": ["givenName"],   "display": [{ "name": "Given names",  "locale": "en" }] },
+          { "path": ["familyName"],  "display": [{ "name": "Family name",  "locale": "en" }] },
+          { "path": ["affiliation"], "display": [{ "name": "Affiliation",  "locale": "en" }] }
+        ]
+      }
+    },
+    "GeantIncubatorDiploma_W3C": {
+      "format": "vc+sd-jwt",
+      "scope": "GeantIncubatorDiploma_W3C",
+      "cryptographic_binding_methods_supported": ["did:jwk"],
+      "proof_types_supported": {
+        "jwt": {
+          "proof_signing_alg_values_supported": ["ES256"]
+        }
+      },
+      "credential_definition": {
+        "@context": [
+          "https://www.w3.org/ns/credentials/v2",
+          "https://issuer.example.org/credentials/GeantIncubatorDiploma_W3C"
+        ],
+        "type": [
+          "VerifiableCredential",
+          "GeantIncubatorDiploma_W3C"
+        ]
+      },
+      "credential_metadata": {
+        "display": [
+          {
+            "name": "Incubator Diploma, W3C",
+            "locale": "en",
+            "description": "Diploma issued by the Trust and Identity Incubator"
+          }
+        ],
+        "claims": [
+          { "path": ["credentialSubject","diploma"],     "display": [{ "name": "Diploma",        "locale": "en" }] },
+          { "path": ["credentialSubject","mail"],        "display": [{ "name": "Email",          "locale": "en" }] },
+          { "path": ["credentialSubject","eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
+          { "path": ["credentialSubject","givenName"],   "display": [{ "name": "Given names",    "locale": "en" }] },
+          { "path": ["credentialSubject","familyName"],  "display": [{ "name": "Family name",    "locale": "en" }] },
+          { "path": ["credentialSubject","affiliation"], "display": [{ "name": "Affiliation",    "locale": "en" }] }
+        ]
+      }
+    }
+  }
+}
diff --git a/docs/example/step-1/static/oauth-authorization-server.json b/docs/example/step-1/static/oauth-authorization-server.json
new file mode 100644
index 0000000..fd7ac81
--- /dev/null
+++ b/docs/example/step-1/static/oauth-authorization-server.json
@@ -0,0 +1,37 @@
+{
+   "issuer":"$issuer",
+   "authorization_endpoint":"$baseUrl/idp/profile/oidc/authorize",
+   "pushed_authorization_request_endpoint":"$baseUrl/idp/profile/oauth2/pushed-authorization",
+   "require_pushed_authorization_requests":true,
+   "token_endpoint":"$baseUrl/idp/profile/openid/vci/token",
+   "jwks_uri":"$baseUrl/idp/profile/oidc/keyset",
+   "token_endpoint_auth_methods_supported":[
+      "none"
+   ],
+   "response_types_supported":[
+      "code"
+   ],
+   "grant_types_supported":[
+      "authorization_code",
+      "urn:ietf:params:oauth:grant-type:pre-authorized_code"
+   ],
+   "code_challenge_methods_supported":[
+      "S256"
+   ],
+   "dpop_signing_alg_values_supported":[
+      "ES256",
+      "ES384",
+      "ES512",
+      "PS256",
+      "PS384",
+      "PS512"
+   ],
+   "scopes_supported":[
+      "openid",
+      "GeantIncubatorDiploma_SDJWT",
+      "GeantIncubatorDiploma_W3C"
+   ],
+   "authorization_details_types_supported":[
+      "openid_credential"
+   ]
+}
diff --git a/docs/example/step-1/webapps/root/credentials/GeantIncubatorDiploma_W3C.json b/docs/example/step-1/webapps/root/credentials/GeantIncubatorDiploma_W3C.json
new file mode 100644
index 0000000..3f2fb9a
--- /dev/null
+++ b/docs/example/step-1/webapps/root/credentials/GeantIncubatorDiploma_W3C.json
@@ -0,0 +1,10 @@
+{
+  "@context": {
+    "diploma": "https://vocabulary.example.org/terms#diploma",
+    "mail": "https://vocabulary.example.org/terms#mail",
+    "eppn": "https://vocabulary.example.org/terms#eppn",
+    "givenName": "https://vocabulary.example.org/terms#givenName",
+    "familyName": "https://vocabulary.example.org/terms#familyName",
+    "affiliation": "https://vocabulary.example.org/terms#affiliation"
+  }
+}
diff --git a/docs/example/step-2/conf/attribute-filter.xml b/docs/example/step-2/conf/attribute-filter.xml
new file mode 100644
index 0000000..b10fb12
--- /dev/null
+++ b/docs/example/step-2/conf/attribute-filter.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<AttributeFilterPolicyGroup id="ShibbolethFilterPolicy"
+        xmlns="urn:mace:shibboleth:2.0:afp"
+        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        xsi:schemaLocation="urn:mace:shibboleth:2.0:afp http://shibboleth.net/schema/idp/shibboleth-afp.xsd">
+
+    <AttributeFilterPolicy id="GeantIncubatorDiplomaToWallets">
+        <PolicyRequirementRule xsi:type="Requester"
+            value="id.animo.paradym" />
+        <AttributeRule attributeID="GeantIncubatorDiploma">
+            <PermitValueRule xsi:type="ANY" />
+        </AttributeRule>
+    </AttributeFilterPolicy>
+
+</AttributeFilterPolicyGroup>
diff --git a/docs/example/step-2/conf/openid-vci-credentials.xml b/docs/example/step-2/conf/openid-vci-credentials.xml
new file mode 100644
index 0000000..09dbf29
--- /dev/null
+++ b/docs/example/step-2/conf/openid-vci-credentials.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean id="openidvci.OPESSigningCredential" parent="shibboleth.JWKCredential"
+        p:resource="%{idp.signing.oidc.es.key}" />
+
+    <util:list id="openidvci.SigningCredentials">
+        <ref bean="openidvci.OPESSigningCredential" />
+    </util:list>
+
+</beans>
diff --git a/docs/example/step-2/conf/relying-party.xml b/docs/example/step-2/conf/relying-party.xml
new file mode 100644
index 0000000..c042fdb
--- /dev/null
+++ b/docs/example/step-2/conf/relying-party.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:util="http://www.springframework.org/schema/util"
+       xmlns:p="http://www.springframework.org/schema/p"
+       xmlns:c="http://www.springframework.org/schema/c"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+       default-init-method="initialize"
+       default-destroy-method="destroy">
+
+    <bean id="shibboleth.UnverifiedRelyingParty" parent="RelyingParty">
+        <property name="profileConfigurations">
+            <list>
+                <!-- The wallet reads the Credential Issuer metadata -->
+                <ref bean="OpenID.VCI.IssuerMetadata" />
+                <!-- The wallet finds the token endpoint through this one -->
+                <ref bean="OAuth.AuthorizationServer" />
+                <!-- The wallet asks for the nonce its key proof has to carry -->
+                <ref bean="OpenID.VCI.Nonce" />
+                <!-- A verifier reads the Status List -->
+                <ref bean="OAuth.StatusList" />
+                <!-- Of the OP plugin. Publishes the keys of the OP as a keyset -->
+                <ref bean="OIDC.Keyset" />
+                <!-- Of the OP plugin. Serves /.well-known/openid-configuration -->
+                <ref bean="OIDC.Configuration" />
+                <!-- Of the OP plugin. Needed for the audience values of the wallet -->
+                <ref bean="OAUTH2.TokenAudience" />
+                <!-- A verifier resolves the did:web identifier from this -->
+                <ref bean="DID.Document" />
+            </list>
+        </property>
+    </bean>
+
+    <bean id="shibboleth.DefaultRelyingParty" parent="RelyingParty">
+        <property name="profileConfigurations">
+            <list>
+                <ref bean="SAML2.SSO" />
+                <ref bean="SAML2.ECP" />
+                <ref bean="SAML2.Logout" />
+                <ref bean="SAML2.ArtifactResolution" />
+            </list>
+        </property>
+    </bean>
+
+    <util:list id="shibboleth.RelyingPartyOverrides">
+
+        <bean parent="RelyingPartyByName" c:relyingPartyIds="offer-caller">
+          <property name="profileConfigurations">
+              <list>
+                  <bean parent="OpenID.VCI.CredentialOffer"
+                        p:tokenEndpointAuthMethods="#{{'client_secret_basic'}}" />
+                  <bean parent="OAuth.StatusList.Revoke"
+                        p:tokenEndpointAuthMethods="#{{'client_secret_basic'}}" />
+                  <bean parent="OAuth.StatusList.Assignments"
+                        p:tokenEndpointAuthMethods="#{{'client_secret_basic'}}" />
+              </list>
+          </property>
+        </bean>
+
+        <bean parent="RelyingPartyByName" c:relyingPartyIds="offer-caller/wallet">
+          <property name="profileConfigurations">
+              <list>
+                  <bean parent="OpenID.VCI.Token"
+                        p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy"
+                        p:tokenEndpointAuthMethods="#{{'none'}}" />
+                  <bean parent="OpenID.VCI.Credentials" />
+              </list>
+          </property>
+        </bean>
+
+        <bean parent="RelyingPartyByName"
+              c:relyingPartyIds="#{{'id.animo.paradym'}}">
+          <property name="profileConfigurations">
+              <list>
+                  <bean parent="OIDC.SSO"
+                        p:authorizationCodeClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy"
+                        p:forcePKCE="true"
+                        p:requirePushedAuthorizationRequest="true" />
+                  <bean parent="OpenID.VCI.Token"
+                        p:tokenEndpointAuthMethods="#{{'none'}}"
+                        p:accessTokenClaimsSetManipulationStrategy-ref="openidvci.TokenManipulationStrategy" />
+                  <bean parent="OpenID.VCI.Credentials" />
+                  <bean parent="OAUTH2.PAR" p:tokenEndpointAuthMethods="#{{'none'}}"
+                        p:requestUriClaimsSetManipulationStrategy-ref="openidvci.PushedAuthorizationDPoPJktManipulationStrategy" />
+              </list>
+          </property>
+        </bean>
+
+    </util:list>
+
+</beans>
diff --git a/docs/example/step-2/etc/jetty-rewrite-rules.xml b/docs/example/step-2/etc/jetty-rewrite-rules.xml
new file mode 100644
index 0000000..ef1ffe6
--- /dev/null
+++ b/docs/example/step-2/etc/jetty-rewrite-rules.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0"?>
+<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "https://jetty.org/configure_10_0.dtd">
+<Configure id="Rewrite" class="org.eclipse.jetty.rewrite.handler.RuleContainer">
+  <!-- Credential Issuer metadata -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/openid-credential-issuer</Set>
+        <Set name="replacement">/idp/profile/openid/vci/issuer-metadata</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- Authorization server metadata -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/oauth-authorization-server</Set>
+        <Set name="replacement">/idp/profile/oauth/authorization-server</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- OP metadata, of the OP plugin -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/openid-configuration</Set>
+        <Set name="replacement">/idp/profile/oidc/configuration</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- The JSON-LD context of the vc+sd-jwt credential is a static file of Jetty -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/credentials/GeantIncubatorDiploma_W3C</Set>
+        <Set name="replacement">/credentials/GeantIncubatorDiploma_W3C.json</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- The did:web document -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.RewritePatternRule">
+        <Set name="pattern">/.well-known/did.json</Set>
+        <Set name="replacement">/idp/profile/did/document</Set>
+      </New>
+    </Arg>
+  </Call>
+  <!-- Wallets running in a browser need this -->
+  <Call name="addRule">
+    <Arg>
+      <New class="org.eclipse.jetty.rewrite.handler.HeaderPatternRule">
+        <Set name="pattern">/*</Set>
+        <Set name="headerName">Access-Control-Allow-Origin</Set>
+        <Set name="headerValue">*</Set>
+      </New>
+    </Arg>
+  </Call>
+</Configure>
diff --git a/docs/example/step-2/metadata/oidc-client.json b/docs/example/step-2/metadata/oidc-client.json
new file mode 100644
index 0000000..0d835e3
--- /dev/null
+++ b/docs/example/step-2/metadata/oidc-client.json
@@ -0,0 +1,29 @@
+[
+  {
+    "client_id": "offer-caller",
+    "client_name": "Credential offer caller",
+    "client_secret": "CHANGE-ME"
+  },
+  {
+    "client_id": "offer-caller/wallet",
+    "client_name": "Wallets redeeming a pre-authorized code minted by offer-caller",
+    "token_endpoint_auth_method": "none",
+    "grant_types": ["urn:ietf:params:oauth:grant-type:pre-authorized_code"]
+  },
+  {
+    "client_id": "id.animo.paradym",
+    "client_name": "Paradym Wallet",
+    "redirect_uris": ["https://paradym.id/invitation/redirect"],
+    "scope": "openid GeantIncubatorDiploma_SDJWT GeantIncubatorDiploma_W3C GeantIncubatorDiploma_DIDWEB",
+    "audience": [
+      "credentials",
+      "urn:shibboleth.oidc.op.resource:https://issuer.example.org"
+    ],
+    "token_endpoint_auth_method": "none",
+    "response_types": ["code"],
+    "grant_types": [
+      "authorization_code",
+      "urn:ietf:params:oauth:grant-type:pre-authorized_code"
+    ]
+  }
+]
diff --git a/docs/example/step-2/metadata/verifiable-credentials.json b/docs/example/step-2/metadata/verifiable-credentials.json
new file mode 100644
index 0000000..ab0a926
--- /dev/null
+++ b/docs/example/step-2/metadata/verifiable-credentials.json
@@ -0,0 +1,96 @@
+{
+  "credential_configurations_supported": {
+    "GeantIncubatorDiploma_SDJWT": {
+      "format": "dc+sd-jwt",
+      "vct": "GeantIncubatorDiploma_SDJWT",
+      "scope": "GeantIncubatorDiploma_SDJWT",
+      "cryptographic_binding_methods_supported": ["did:jwk"],
+      "proof_types_supported": {
+        "jwt": {
+          "proof_signing_alg_values_supported": ["ES256"]
+        }
+      },
+      "credential_metadata": {
+        "display": [
+          {
+            "name": "Incubator Diploma",
+            "locale": "en",
+            "description": "Diploma issued by the Trust and Identity Incubator"
+          }
+        ],
+        "claims": [
+          { "path": ["diploma"],     "display": [{ "name": "Diploma",      "locale": "en" }] },
+          { "path": ["mail"],        "display": [{ "name": "Email",        "locale": "en" }] },
+          { "path": ["eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
+          { "path": ["givenName"],   "display": [{ "name": "Given names",  "locale": "en" }] },
+          { "path": ["familyName"],  "display": [{ "name": "Family name",  "locale": "en" }] },
+          { "path": ["affiliation"], "display": [{ "name": "Affiliation",  "locale": "en" }] }
+        ]
+      }
+    },
+    "GeantIncubatorDiploma_W3C": {
+      "format": "vc+sd-jwt",
+      "scope": "GeantIncubatorDiploma_W3C",
+      "cryptographic_binding_methods_supported": ["did:jwk"],
+      "proof_types_supported": {
+        "jwt": {
+          "proof_signing_alg_values_supported": ["ES256"]
+        }
+      },
+      "credential_definition": {
+        "@context": [
+          "https://www.w3.org/ns/credentials/v2",
+          "https://issuer.example.org/credentials/GeantIncubatorDiploma_W3C"
+        ],
+        "type": [
+          "VerifiableCredential",
+          "GeantIncubatorDiploma_W3C"
+        ]
+      },
+      "credential_metadata": {
+        "display": [
+          {
+            "name": "Incubator Diploma, W3C",
+            "locale": "en",
+            "description": "Diploma issued by the Trust and Identity Incubator"
+          }
+        ],
+        "claims": [
+          { "path": ["credentialSubject","diploma"],     "display": [{ "name": "Diploma",        "locale": "en" }] },
+          { "path": ["credentialSubject","mail"],        "display": [{ "name": "Email",          "locale": "en" }] },
+          { "path": ["credentialSubject","eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
+          { "path": ["credentialSubject","givenName"],   "display": [{ "name": "Given names",    "locale": "en" }] },
+          { "path": ["credentialSubject","familyName"],  "display": [{ "name": "Family name",    "locale": "en" }] },
+          { "path": ["credentialSubject","affiliation"], "display": [{ "name": "Affiliation",    "locale": "en" }] }
+        ]
+      }
+    },
+    "GeantIncubatorDiploma_DIDWEB": {
+      "format": "dc+sd-jwt",
+      "vct": "GeantIncubatorDiploma_DIDWEB",
+      "scope": "GeantIncubatorDiploma_DIDWEB",
+      "cryptographic_binding_methods_supported": ["did:jwk"],
+      "proof_types_supported": {
+        "jwt": {
+          "proof_signing_alg_values_supported": ["ES256"]
+        }
+      },
+      "_issuance_configuration": {
+        "issuer": "did:web"
+      },
+      "credential_metadata": {
+        "display": [
+          { "name": "Incubator Diploma, did:web", "locale": "en" }
+        ],
+        "claims": [
+          { "path": ["diploma"],     "display": [{ "name": "Diploma",        "locale": "en" }] },
+          { "path": ["mail"],        "display": [{ "name": "Email",          "locale": "en" }] },
+          { "path": ["eppn"],        "display": [{ "name": "Principal name", "locale": "en" }] },
+          { "path": ["givenName"],   "display": [{ "name": "Given names",    "locale": "en" }] },
+          { "path": ["familyName"],  "display": [{ "name": "Family name",    "locale": "en" }] },
+          { "path": ["affiliation"], "display": [{ "name": "Affiliation",    "locale": "en" }] }
+        ]
+      }
+    }
+  }
+}
diff --git a/docs/example/step-2/static/oauth-authorization-server.json b/docs/example/step-2/static/oauth-authorization-server.json
new file mode 100644
index 0000000..25684d1
--- /dev/null
+++ b/docs/example/step-2/static/oauth-authorization-server.json
@@ -0,0 +1,38 @@
+{
+   "issuer":"$issuer",
+   "authorization_endpoint":"$baseUrl/idp/profile/oidc/authorize",
+   "pushed_authorization_request_endpoint":"$baseUrl/idp/profile/oauth2/pushed-authorization",
+   "require_pushed_authorization_requests":true,
+   "token_endpoint":"$baseUrl/idp/profile/openid/vci/token",
+   "jwks_uri":"$baseUrl/idp/profile/oidc/keyset",
+   "token_endpoint_auth_methods_supported":[
+      "none"
+   ],
+   "response_types_supported":[
+      "code"
+   ],
+   "grant_types_supported":[
+      "authorization_code",
+      "urn:ietf:params:oauth:grant-type:pre-authorized_code"
+   ],
+   "code_challenge_methods_supported":[
+      "S256"
+   ],
+   "dpop_signing_alg_values_supported":[
+      "ES256",
+      "ES384",
+      "ES512",
+      "PS256",
+      "PS384",
+      "PS512"
+   ],
+   "scopes_supported":[
+      "openid",
+      "GeantIncubatorDiploma_SDJWT",
+      "GeantIncubatorDiploma_W3C",
+      "GeantIncubatorDiploma_DIDWEB"
+   ],
+   "authorization_details_types_supported":[
+      "openid_credential"
+   ]
+}
diff --git a/docs/example/step-2/webapps/root/credentials/GeantIncubatorDiploma_W3C.json b/docs/example/step-2/webapps/root/credentials/GeantIncubatorDiploma_W3C.json
new file mode 100644
index 0000000..3f2fb9a
--- /dev/null
+++ b/docs/example/step-2/webapps/root/credentials/GeantIncubatorDiploma_W3C.json
@@ -0,0 +1,10 @@
+{
+  "@context": {
+    "diploma": "https://vocabulary.example.org/terms#diploma",
+    "mail": "https://vocabulary.example.org/terms#mail",
+    "eppn": "https://vocabulary.example.org/terms#eppn",
+    "givenName": "https://vocabulary.example.org/terms#givenName",
+    "familyName": "https://vocabulary.example.org/terms#familyName",
+    "affiliation": "https://vocabulary.example.org/terms#affiliation"
+  }
+}

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


More information about the commits mailing list