[java-idp-plugin-vci] branch main updated: Nonce endpoint, refactoring profile configurations

Codeberg noreply at shibboleth.net
Wed Nov 19 14:38:24 UTC 2025


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/804055fb70ea19d83bd6b68c51dde8e3a85010b4

The following commit(s) were added to refs/heads/main by this push:
     new 804055f  Nonce endpoint, refactoring profile configurations
804055f is described below

commit 804055fb70ea19d83bd6b68c51dde8e3a85010b4
Author: jlauros <janne.lauros at csc.fi>
AuthorDate: Wed Nov 19 16:38:13 2025 +0200

    Nonce endpoint, refactoring profile configurations
---
 .../openidvci/config/OpenIDVCIConfiguration.java   |  24 ++++-
 ...on.java => AbstractOpenIDVCIConfiguration.java} |  13 ++-
 ...faultOpenIDVCICredentialOfferConfiguration.java |  11 +++
 .../DefaultOpenIDVCICredentialsConfiguration.java  |  11 +++
 .../impl/DefaultOpenIDVCINonceConfiguration.java   |  11 +++
 .../impl/DefaultOpenIDVCITokenConfiguration.java   |  11 +++
 .../messaging/impl/CredentialSuccessResponse.java  |  14 +++
 ...cessResponse.java => NonceSuccessResponse.java} |  66 +++++--------
 .../FormOutboundCredentialsResponseMessage.java    |  46 ++++++++-
 .../impl/FormOutboundNonceResponseMessage.java     | 109 +++++++++++++++++++++
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  22 +----
 .../openid/vci/abstract-api/abstract-api-beans.xml |   2 +-
 .../flows/openid/vci/abstract/abstract-beans.xml   |   4 +-
 .../credential-offer/credential-offer-beans.xml    |   2 +
 .../openid/vci/credentials/credentials-beans.xml   |  16 ++-
 .../idp/flows/openid/vci/nonce/nonce-beans.xml     |  38 +++++++
 .../idp/flows/openid/vci/nonce/nonce-flow.xml      |  21 ++++
 .../idp/flows/openid/vci/token/token-beans.xml     |  16 ++-
 .../idp/service/relying-party}/postconfig.xml      |  55 +++++++----
 .../impl/FormOutboundTokenResponseMessageTest.java |   4 +-
 20 files changed, 391 insertions(+), 105 deletions(-)

diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java
index ee922f4..461095d 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/OpenIDVCIConfiguration.java
@@ -29,7 +29,7 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.annotation.constraint.Positive;
 
 /**
- * Profile configuration for the OpenID VCI.
+ * Profile configuration shared by all OpenID VCI endpointsß.
  */
 public interface OpenIDVCIConfiguration extends ConditionalProfileConfiguration {
 
@@ -38,10 +38,30 @@ public interface OpenIDVCIConfiguration extends ConditionalProfileConfiguration
     @NotEmpty
     public static final String PROTOCOL_URI = "https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html";
 
-    /** ID for this profile configuration. */
+    /** Main id for this profile configuration. */
     @Nonnull
     @NotEmpty
     public static final String PROFILE_ID = "http://geant.org/ns/profiles/openid/vci";
+    
+    /** ID for credential offer profile configuration. */
+    @Nonnull
+    @NotEmpty
+    public static final String PROFILE_ID_CREDENTIAL_OFFER = "http://geant.org/ns/profiles/openid/vci/credential-offer";
+    
+    /** ID for token configuration. */
+    @Nonnull
+    @NotEmpty
+    public static final String PROFILE_ID_TOKEN = "http://geant.org/ns/profiles/openid/vci/token";
+    
+    /** ID for credentials configuration. */
+    @Nonnull
+    @NotEmpty
+    public static final String PROFILE_ID_CREDENTIALS = "http://geant.org/ns/profiles/openid/vci/credentials";
+    
+    /** ID for nonce configuration. */
+    @Nonnull
+    @NotEmpty
+    public static final String PROFILE_ID_NONCE = "http://geant.org/ns/profiles/openid/vci/nonce";
 
     /**
      * Get pre-authorized code length. Length of zero means there is no requirement
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/AbstractOpenIDVCIConfiguration.java
similarity index 96%
rename from openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java
rename to openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/AbstractOpenIDVCIConfiguration.java
index 4438f2a..9869b43 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCIConfiguration.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/AbstractOpenIDVCIConfiguration.java
@@ -30,7 +30,6 @@ import javax.annotation.Nullable;
 import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
 import org.geant.shibboleth.plugin.openidvci.config.impl.stolen.AbstractOAuth2ClientAuthenticableProfileConfiguration;
 import org.opensaml.profile.context.ProfileRequestContext;
-import org.opensaml.security.config.SecurityConfiguration;
 
 import net.shibboleth.oidc.profile.config.OIDCSSOProfileConfiguration;
 import net.shibboleth.profile.config.OverriddenIssuerProfileConfiguration;
@@ -41,7 +40,7 @@ import net.shibboleth.shared.logic.FunctionSupport;
 import net.shibboleth.shared.logic.PredicateSupport;
 import net.shibboleth.shared.primitive.StringSupport;
 
-public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthenticableProfileConfiguration
+public abstract class AbstractOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthenticableProfileConfiguration
         implements OpenIDVCIConfiguration, OverriddenIssuerProfileConfiguration, OIDCSSOProfileConfiguration {
 
     /** Lookup function to override issuer value. */
@@ -56,7 +55,6 @@ public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthentic
     @Nonnull
     private Function<ProfileRequestContext, String> accessTokenTypeLookupStrategy;
 
-    // TODO: property not applied. Remove or apply.
     /**
      * Lookup function to supply strategy bi-function for manipulating access token
      * claims set.
@@ -83,8 +81,8 @@ public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthentic
     /**
      * Constructor.
      */
-    public DefaultOpenIDVCIConfiguration() {
-        super(OpenIDVCIConfiguration.PROFILE_ID);
+    protected AbstractOpenIDVCIConfiguration(@Nonnull @NotEmpty final String profileId) {
+        super(profileId);
         issuerLookupStrategy = FunctionSupport.constant(null);
         accessTokenLifetimeLookupStrategy = FunctionSupport.constant(Duration.ofMinutes(10));
         accessTokenTypeLookupStrategy = FunctionSupport.constant(null);
@@ -211,8 +209,9 @@ public class DefaultOpenIDVCIConfiguration extends AbstractOAuth2ClientAuthentic
     }
 
     /**
-     * Set a lookup strategy for the pre-authorized code length. Length of zero means
-     * there is no requirement and code does not require storage configuration.
+     * Set a lookup strategy for the pre-authorized code length. Length of zero
+     * means there is no requirement and code does not require storage
+     * configuration.
      *
      * @param strategy lookup strategy
      */
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialOfferConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialOfferConfiguration.java
new file mode 100644
index 0000000..ce80a74
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialOfferConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCICredentialOfferConfiguration extends AbstractOpenIDVCIConfiguration{
+
+    public DefaultOpenIDVCICredentialOfferConfiguration() {
+        super(OpenIDVCIConfiguration.PROFILE_ID_CREDENTIAL_OFFER);
+    }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialsConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialsConfiguration.java
new file mode 100644
index 0000000..b379bc7
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCICredentialsConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCICredentialsConfiguration extends AbstractOpenIDVCIConfiguration{
+
+    public DefaultOpenIDVCICredentialsConfiguration() {
+        super(OpenIDVCIConfiguration.PROFILE_ID_CREDENTIALS);
+    }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCINonceConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCINonceConfiguration.java
new file mode 100644
index 0000000..7df9b97
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCINonceConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCINonceConfiguration extends AbstractOpenIDVCIConfiguration{
+
+    public DefaultOpenIDVCINonceConfiguration() {
+        super(OpenIDVCIConfiguration.PROFILE_ID_NONCE);
+    }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCITokenConfiguration.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCITokenConfiguration.java
new file mode 100644
index 0000000..5e51cdf
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/config/impl/DefaultOpenIDVCITokenConfiguration.java
@@ -0,0 +1,11 @@
+package org.geant.shibboleth.plugin.openidvci.config.impl;
+
+import org.geant.shibboleth.plugin.openidvci.config.OpenIDVCIConfiguration;
+
+public class DefaultOpenIDVCITokenConfiguration extends AbstractOpenIDVCIConfiguration{
+
+    public DefaultOpenIDVCITokenConfiguration() {
+        super(OpenIDVCIConfiguration.PROFILE_ID_TOKEN);
+    }
+
+}
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
index 6f4ebe1..4544a7c 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
@@ -16,9 +16,21 @@
 
 package org.geant.shibboleth.plugin.openidvci.messaging.impl;
 
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAccessor;
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Locale;
 import java.util.Map;
 
 import javax.annotation.Nullable;
@@ -87,6 +99,8 @@ public class CredentialSuccessResponse implements SuccessResponse {
         httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
         httpResponse.setCacheControl("no-store");
         httpResponse.setPragma("no-cache");
+
+        httpResponse.setHeader("Date", DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now()));
         try {
             httpResponse.setContent(toOffer());
         } catch (JsonProcessingException e) {
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/NonceSuccessResponse.java
similarity index 50%
copy from openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
copy to openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/NonceSuccessResponse.java
index 6f4ebe1..87328f4 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/NonceSuccessResponse.java
@@ -16,12 +16,10 @@
 
 package org.geant.shibboleth.plugin.openidvci.messaging.impl;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import javax.annotation.Nonnull;
 
-import javax.annotation.Nullable;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -30,48 +28,30 @@ import com.nimbusds.common.contenttype.ContentType;
 import com.nimbusds.oauth2.sdk.SuccessResponse;
 import com.nimbusds.oauth2.sdk.http.HTTPResponse;
 
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+
 /**
- * https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-credential-response
+ * hhttps://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html#name-nonce-response
  * 
- * Forms a credential response. Now a mix of specifications v14 and v15.
+ * Forms a nonce response.
  *
  */
-public class CredentialSuccessResponse implements SuccessResponse {
-
-    /** v15 credentials parameter. */
-    @JsonProperty("credentials")
-    private final List<Map<String, String>> credentials = new ArrayList<Map<String, String>>();
+public class NonceSuccessResponse implements SuccessResponse {
+    
+    /** Class logger. */
+    @Nonnull
+    private Logger log = LoggerFactory.getLogger(NonceSuccessResponse.class);
 
-    /**
-     * Get v15 credentials parameter.
-     * 
-     * @return v15 credentials parameter
-     */
-    public List<Map<String, String>> getCredentials() {
-        return credentials;
-    }
-
-    /**
-     * Constructor. TODO: No safeguards in place. Add when finalized.
-     * 
-     * @param credentialv15 v15 credentials parameter
-     * @param credentialv14 v14 credential parameter
-     */
-    public CredentialSuccessResponse(@Nullable List<String> credentialv15) {
-        Map<String, String> cred = new HashMap<String, String>();
-        credentialv15.forEach(credential -> cred.put("credential", credential));
-        credentials.add(cred);
-    }
+    /** c_nonce. */
+    @Nonnull
+    @NotEmpty
+    @JsonProperty("c_nonce")
+    private final String cNonce;
 
-    /**
-     * Response content as JSON.
-     * 
-     * @return
-     * @throws JsonProcessingException
-     */
-    public String toOffer() throws JsonProcessingException {
-        ObjectMapper objectMapper = new ObjectMapper();
-        return objectMapper.writeValueAsString(this);
+    public NonceSuccessResponse(@Nonnull @NotEmpty String cNonce) {
+        assert cNonce != null;
+        assert !cNonce.isEmpty();
+        this.cNonce = cNonce;
     }
 
     /** {@inheritDoc} */
@@ -85,10 +65,10 @@ public class CredentialSuccessResponse implements SuccessResponse {
     public HTTPResponse toHTTPResponse() {
         HTTPResponse httpResponse = new HTTPResponse(HTTPResponse.SC_OK);
         httpResponse.setEntityContentType(ContentType.APPLICATION_JSON);
-        httpResponse.setCacheControl("no-store");
+        //httpResponse.setCacheControl("no-store");
         httpResponse.setPragma("no-cache");
         try {
-            httpResponse.setContent(toOffer());
+            httpResponse.setContent(new ObjectMapper().writeValueAsString(this));
         } catch (JsonProcessingException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java
index 8b729ab..7a2f893 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundCredentialsResponseMessage.java
@@ -27,6 +27,7 @@ import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 import java.security.interfaces.ECPrivateKey;
+import java.time.Instant;
 
 import org.geant.shibboleth.plugin.openidvci.messaging.context.CredentialsContext;
 import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferRequestedCredential;
@@ -48,11 +49,13 @@ import net.shibboleth.profile.context.navigate.IssuerLookupFunction;
 import net.shibboleth.shared.logic.Constraint;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JOSEObjectType;
 import com.nimbusds.jose.JWSAlgorithm;
 import com.nimbusds.jose.JWSHeader;
 import com.nimbusds.jose.crypto.ECDSASigner;
+import com.nimbusds.jose.util.Base64;
 import com.nimbusds.jwt.JWTClaimsSet;
 import com.nimbusds.jwt.JWTClaimsSet.Builder;
 import com.nimbusds.jwt.SignedJWT;
@@ -182,17 +185,37 @@ public class FormOutboundCredentialsResponseMessage extends AbstractOIDCResponse
             // Map<String, String> cnfKid = null;
             if (ctx.getProofs() != null && !ctx.getProofs().isEmpty()) {
                 ctx.getProofs().forEach(proof -> {
-                    Map<String, String> cnfKid = new HashMap<>();
-                    cnfKid.put("jwk", proof.getHeader().getJWK().toJSONString());
+                    Map<String, Object> cnfKid = new HashMap<>();
+                    try {
+                        cnfKid.put("jwk", new ObjectMapper().readValue(proof.getHeader().getJWK().toJSONString(), Object.class));
+                    } catch (JsonProcessingException e1) {
+                        // TODO Auto-generated catch block
+                        e1.printStackTrace();
+                    }
                     // TODO: vct is the credential configuration id in SD JWT. Here we use however "instance" specific
                     // identifier that happes to be in our case derived from it. We need to get the real configuration id here.
                     Builder build = new JWTClaimsSet.Builder().claim("vct", ctx.getCredentialIdentifier().split("_")[0])
                             .claim("iss", issuerLookupStrategy.apply(profileRequestContext))
+                            // Just to pass happy path test.
+                            .claim("exp", Instant.now().getEpochSecond()+3600)
                             .claim("_sd", sdClaims.get_sd()).claim("_sd_alg", sdClaims.get_alg()).claim("cnf", cnfKid)
                             .issueTime(new Date());
                     JWTClaimsSet claimsSet = build.build();
+                    //Now we pretend setting a certificate chain here.
+                    List<Base64> chain= new ArrayList<>();
+                    chain.add(new Base64("MIIB4DCCAYWgAwIBAgIUaVbPKGSv6mVnyNbTOo1E9AWr+r4wCgYIKoZIzj0EAwIw\n"
+                            + "RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu\n"
+                            + "dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTA1MDkwOTI4MTVaFw0zNTA1MDcw\n"
+                            + "OTI4MTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD\n"
+                            + "VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO\n"
+                            + "PQMBBwNCAASpD0RJ4itDfomKNYz7zF1yNfBjjpFben1gO0/QxVouceclWUasKdbX\n"
+                            + "XvwpyguutsFvlxUIRDqxgD4tC0xuDqSPo1MwUTAdBgNVHQ4EFgQUTC/h0/AgKp/3\n"
+                            + "FVZJBJoJBcX/hQMwHwYDVR0jBBgwFoAUTC/h0/AgKp/3FVZJBJoJBcX/hQMwDwYD\n"
+                            + "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA87tC4qr0HJIMZylNO3Xv\n"
+                            + "FhSb/DHZt3Pp/WVTCRpby7YCIQCbvW/6IEk1hNxpX49zLyoQpSF8DW1a/cTMr2Te\n"
+                            + "Aa1KHw=="));
                     SignedJWT signedJWT = new SignedJWT(
-                            new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm()))
+                            new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm())).x509CertChain(chain)
                                     .type(new JOSEObjectType("dc+sd-jwt")).keyID("signing").build(),
                             claimsSet);
                     try {
@@ -209,11 +232,26 @@ public class FormOutboundCredentialsResponseMessage extends AbstractOIDCResponse
                 });
             } else {
                 Builder build = new JWTClaimsSet.Builder().claim("vct", ctx.getCredentialIdentifier())
+                         // Just to pass happy path test.
+                        .claim("exp", Instant.now().getEpochSecond()+3600)
                         .claim("iss", issuerLookupStrategy.apply(profileRequestContext)).claim("_sd", sdClaims.get_sd())
                         .claim("_sd_alg", sdClaims.get_alg()).issueTime(new Date());
                 JWTClaimsSet claimsSet = build.build();
+                //Now we pretend setting a certificate chain here.
+                List<Base64> chain= new ArrayList<>();
+                chain.add(new Base64("MIIB4DCCAYWgAwIBAgIUaVbPKGSv6mVnyNbTOo1E9AWr+r4wCgYIKoZIzj0EAwIw\n"
+                        + "RTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGElu\n"
+                        + "dGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTA1MDkwOTI4MTVaFw0zNTA1MDcw\n"
+                        + "OTI4MTVaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYD\n"
+                        + "VQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwWTATBgcqhkjOPQIBBggqhkjO\n"
+                        + "PQMBBwNCAASpD0RJ4itDfomKNYz7zF1yNfBjjpFben1gO0/QxVouceclWUasKdbX\n"
+                        + "XvwpyguutsFvlxUIRDqxgD4tC0xuDqSPo1MwUTAdBgNVHQ4EFgQUTC/h0/AgKp/3\n"
+                        + "FVZJBJoJBcX/hQMwHwYDVR0jBBgwFoAUTC/h0/AgKp/3FVZJBJoJBcX/hQMwDwYD\n"
+                        + "VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNJADBGAiEA87tC4qr0HJIMZylNO3Xv\n"
+                        + "FhSb/DHZt3Pp/WVTCRpby7YCIQCbvW/6IEk1hNxpX49zLyoQpSF8DW1a/cTMr2Te\n"
+                        + "Aa1KHw=="));
                 SignedJWT signedJWT = new SignedJWT(
-                        new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm()))
+                        new JWSHeader.Builder(new JWSAlgorithm(signatureSigningParameters.getSignatureAlgorithm())).x509CertChain(chain)
                                 .type(new JOSEObjectType("dc+sd-jwt")).keyID("signing").build(),
                         claimsSet);
                 try {
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java
new file mode 100644
index 0000000..5d17c06
--- /dev/null
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundNonceResponseMessage.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2025, GÉANT
+ *
+ * Licensed under the Apache License, Version 2.0 (the “License”); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an “AS IS” BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.geant.shibboleth.plugin.openidvci.profile.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+
+import org.geant.shibboleth.plugin.openidvci.messaging.impl.NonceSuccessResponse;
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.oidc.profile.oauth2.config.OAuth2DPoPProofValidatingProfileConfiguration;
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Action forming {@link NonceSuccessResponse}
+ */
+public class FormOutboundNonceResponseMessage extends AbstractProfileAction {
+
+    /** Class logger. */
+    @Nonnull
+    private Logger log = LoggerFactory.getLogger(FormOutboundNonceResponseMessage.class);
+
+    @NonnullAfterInit
+    private Function<ProfileRequestContext, String> generator;
+
+    /**
+     * Strategy used to locate the {@link RelyingPartyContext} associated with a
+     * given {@link ProfileRequestContext}.
+     */
+    @Nonnull
+    private Function<ProfileRequestContext, RelyingPartyContext> relyingPartyContextLookupStrategy;
+
+    /** Relying party context. */
+    private RelyingPartyContext rpCtx;
+
+    public FormOutboundNonceResponseMessage() {
+        relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+    }
+
+    /**
+     * Set the strategy used to locate the {@link RelyingPartyContext} associated
+     * with a given {@link ProfileRequestContext}.
+     * 
+     * @param strategy strategy used to locate the {@link RelyingPartyContext}
+     *                 associated with a given {@link ProfileRequestContext}
+     */
+    public void setRelyingPartyContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext, RelyingPartyContext> strategy) {
+        checkSetterPreconditions();
+
+        relyingPartyContextLookupStrategy = Constraint.isNotNull(strategy,
+                "RelyingPartyContext lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        rpCtx = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+        if (rpCtx == null) {
+            log.error("{} No relying party context associated with this profile request", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
+        }
+        final ProfileConfiguration pc = rpCtx.getProfileConfig();
+        if (pc instanceof OAuth2DPoPProofValidatingProfileConfiguration configuration) {
+            generator = configuration.getDpopProofNonceGenerator(profileRequestContext);
+        } else {
+            log.error("{} No OpenID VCI profile configuration associated with this profile request", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
+        }
+        if (generator == null) {
+            log.error("{} No nonce generator available for this profile request", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
+        }
+        return super.doPreExecute(profileRequestContext);
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        profileRequestContext.ensureOutboundMessageContext()
+                .setMessage(new NonceSuccessResponse(generator.apply(profileRequestContext)));
+    }
+}
\ No newline at end of file
diff --git a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index c7f2ea7..2775a71 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -15,35 +15,17 @@
     <bean id="shibboleth.PropertySourcesPlaceholderConfigurer"
         class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
         p:placeholderPrefix="%{" p:placeholderSuffix="}" />
-
-    
-    <bean id="AbstractVCIProfile" abstract="true" 
-        p:issuer="#{getObject('shibboleth.oidc.issuer')}"        
-        p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
-        p:forcePKCE="%{idp.oidc.forcePKCE:false}"
-        p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
-        p:accessTokenType="%{idp.oauth2.accessToken.type:}"
-        p:accessTokenLifetime="%{idp.oidc.accessToken.defaultLifetime:PT10M}"
-        p:tokenEndpointAuthMethod="%{idp.authn.oidc.rp.client.authenticationMethod:client_secret_basic}"
-        p:securityConfiguration-ref="%{idp.security.oidc.config:shibboleth.oidc.DefaultSecurityConfiguration}"
-        p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}" />
-        
-    <bean id="OpenID.VCI" parent="AbstractVCIProfile" lazy-init="true"
-        class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration"
-        p:issuer="#{getObject('shibboleth.oidc.issuer')}"
-        p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
-        p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
-        p:accessTokenLifetime="%{openidvci.accessToken.defaultLifetime:PT5M}"/>
         
     <!-- Property-based definition of login flows for OAuth endpoints. -->
     <bean id="openidvci.PotentialFlows"
         class="org.springframework.beans.factory.config.ListFactoryBean"
         p:sourceList="#{getObject('shibboleth.AuthenticationFlowDescriptorManager').getComponents().?[id matches 'authn/(' + '%{openidvci.authn.flows:OAuth2Client}'.trim() + ')']}" />
-        
+
     <bean id="openidvci.PublicClientValidator"
         class="org.geant.shibboleth.plugin.openidvci.authn.impl.WalletCredentialValidator" />
         
     <bean id="openidvci.AuthzCodeManipulationStrategy"
         class="org.geant.shibboleth.plugin.openidvci.profile.logic.AuthorizationCodeManipulationStrategy" />
+    
 
 </beans>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml
index 71345ee..e4e4c05 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract-api/abstract-api-beans.xml
@@ -11,7 +11,7 @@
                            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.oidc.browserProfile" class="java.lang.Boolean" c:_0="false"/>
+ <bean id="shibboleth.openidvci.browserProfile" class="java.lang.Boolean" c:_0="false"/>
  
  <bean id="InitializeRelyingPartyContext" class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeRelyingPartyContext"
     scope="prototype" p:clientIDLookupStrategy-ref="shibboleth.ClientIDLookupStrategy"/>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml
index cc1ab97..db210c7 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/abstract/abstract-beans.xml
@@ -10,8 +10,8 @@
   <import resource="classpath*:/META-INF/net/shibboleth/idp/flows/oidc/abstract/oidc-abstract-beans.xml"/>
 
   <bean id="InitializeProfileRequestContext" class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext"
-    scope="prototype" p:profileId="http://geant.org/ns/profiles/openid/vci" p:loggingId="%{idp.service.logging.saml2sso:SSO}"
-    p:browserProfile-ref="shibboleth.oidc.browserProfile"/>
+    scope="prototype" p:profileId-ref="shibboleth.openidvci.profileId" p:loggingId="%{idp.service.logging.saml2sso:SSO}"
+    p:browserProfile-ref="shibboleth.openidvci.browserProfile"/>
 
   <bean id="openidvci.CredentialOfferCache" class="org.geant.shibboleth.plugin.openidvci.storage.CredentialOfferCache"
     depends-on="shibboleth.LoggingService" p:storage-ref="#{'%{openidvci.StorageService:shibboleth.StorageService}'.trim()}"/>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml
index 3ceda55..ae555cf 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credential-offer/credential-offer-beans.xml
@@ -11,6 +11,8 @@
                            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.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/credential-offer"/>
+ 
  <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
   <constructor-arg>
    <bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.CredentialOfferRequestDecoder"
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml
index 2888a0d..dd4fd65 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/credentials/credentials-beans.xml
@@ -1,6 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" 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://ww [...]
-
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ 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.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/credentials"/>
+  
   <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
     <constructor-arg>
       <bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCICredentialsRequestDecoder" 
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-beans.xml
new file mode 100644
index 0000000..57870b7
--- /dev/null
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-beans.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ 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.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/nonce"/>
+  
+  <bean id="InitializeUnverifiedRelyingPartyContext"
+        class="net.shibboleth.idp.plugin.oidc.op.profile.impl.InitializeUnverifiedRelyingPartyContext" scope="prototype" />
+    
+  <bean id="FormOutboundMessage" class="org.geant.shibboleth.plugin.openidvci.profile.impl.FormOutboundNonceResponseMessage"
+        scope="prototype" />
+ 
+  <bean id="BuildErrorResponseFromEvent" class="net.shibboleth.oidc.profile.impl.BuildJSONErrorResponseFromEvent" 
+        scope="prototype" p:defaultStatusCode="400" p:defaultCode="invalid_request"
+        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier">
+    <property name="eventContextLookupStrategy">
+      <bean class="net.shibboleth.idp.profile.context.navigate.WebFlowCurrentEventLookupFunction" />
+    </property>
+    <property name="mappedErrors">
+      <map value-type="com.nimbusds.oauth2.sdk.ErrorObject">
+      <!--  
+        ADD SOME
+        -->
+      </map>
+    </property>
+  </bean>
+
+  
+</beans>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml
new file mode 100644
index 0000000..69ebc74
--- /dev/null
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/nonce/nonce-flow.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<flow xmlns="http://www.springframework.org/schema/webflow" 
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
+      xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd" 
+      parent="openid/vci/abstract-api">
+
+  <action-state id="InitializeMandatoryContexts">
+    <evaluate expression="InitializeProfileRequestContext"/>
+    <evaluate expression="PopulateMetricContext"/>
+    <evaluate expression="FlowStartPopulateAuditContext"/>
+    <evaluate expression="InitializeOutboundMessageContext"/>
+    <evaluate expression="InitializeUnverifiedRelyingPartyContext" />
+    <evaluate expression="SelectRelyingPartyConfiguration" />
+    <evaluate expression="SelectProfileConfiguration" />
+    <evaluate expression="'proceed'"/>
+    <transition on="proceed" to="BuildResponse"/>
+  </action-state>
+
+  <bean-import resource="nonce-beans.xml"/>
+
+</flow>
diff --git a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml
index f5a8eab..6210619 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/openid/vci/token/token-beans.xml
@@ -1,6 +1,18 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans" xmlns:c="http://www.springframework.org/schema/c" xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" 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://ww [...]
-
+<beans
+ xmlns="http://www.springframework.org/schema/beans"
+ xmlns:c="http://www.springframework.org/schema/c"
+ xmlns:context="http://www.springframework.org/schema/context"
+ xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
+ 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.openidvci.profileId" class="java.lang.String" c:_0="http://geant.org/ns/profiles/openid/vci/token"/>
+  
   <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
     <constructor-arg>
       <bean class="org.geant.shibboleth.plugin.openidvci.decoding.impl.OpenIDVCITokenRequestDecoder" 
diff --git a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
similarity index 54%
copy from openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
copy to openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
index c7f2ea7..7e77d6c 100644
--- a/openid-vci-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/openid-vci-impl/src/main/resources/META-INF/net/shibboleth/idp/service/relying-party/postconfig.xml
@@ -17,8 +17,10 @@
         p:placeholderPrefix="%{" p:placeholderSuffix="}" />
 
     
-    <bean id="AbstractVCIProfile" abstract="true" 
-        p:issuer="#{getObject('shibboleth.oidc.issuer')}"        
+    <bean id="AbstractVCIProfile" abstract="true"
+        p:issuer="#{getObject('shibboleth.oidc.issuer')}"
+        p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
+        p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"        
         p:tokenEndpointAuthMethods="%{idp.oidc.tokenEndpointAuthMethods:client_secret_basic,client_secret_post,client_secret_jwt,private_key_jwt}"
         p:forcePKCE="%{idp.oidc.forcePKCE:false}"
         p:allowPKCEPlain="%{idp.oidc.allowPKCEPlain:false}"
@@ -26,24 +28,37 @@
         p:accessTokenLifetime="%{idp.oidc.accessToken.defaultLifetime:PT10M}"
         p:tokenEndpointAuthMethod="%{idp.authn.oidc.rp.client.authenticationMethod:client_secret_basic}"
         p:securityConfiguration-ref="%{idp.security.oidc.config:shibboleth.oidc.DefaultSecurityConfiguration}"
-        p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}" />
-        
-    <bean id="OpenID.VCI" parent="AbstractVCIProfile" lazy-init="true"
-        class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration"
-        p:issuer="#{getObject('shibboleth.oidc.issuer')}"
-        p:preauthorizedCodeLifetime="%{openidvci.preauthorizedCode:PT10M}"
-        p:preauthorizedCodeLength="%{openidvci.preauthorizedCode.defaultLength:0}"
-        p:accessTokenLifetime="%{openidvci.accessToken.defaultLifetime:PT5M}"/>
-        
-    <!-- Property-based definition of login flows for OAuth endpoints. -->
-    <bean id="openidvci.PotentialFlows"
-        class="org.springframework.beans.factory.config.ListFactoryBean"
-        p:sourceList="#{getObject('shibboleth.AuthenticationFlowDescriptorManager').getComponents().?[id matches 'authn/(' + '%{openidvci.authn.flows:OAuth2Client}'.trim() + ')']}" />
-        
-    <bean id="openidvci.PublicClientValidator"
-        class="org.geant.shibboleth.plugin.openidvci.authn.impl.WalletCredentialValidator" />
+        p:claimsValidator="#{getObject('DefaultJWTClaimsValidator')}"
+        p:dpopProofClaimsValidator="#{getObject('DefaultDPoPProofClaimsValidator')}"
+        p:dpopProofSignatureValidationConfiguration="#{getObject('DPoPSignatureValidationConfiguration')}"
+        p:dpopProofNonceGenerator="#{getObject('DefaultOAuth2DPoPNonceGenerator')}" />
+    
         
-    <bean id="openidvci.AuthzCodeManipulationStrategy"
-        class="org.geant.shibboleth.plugin.openidvci.profile.logic.AuthorizationCodeManipulationStrategy" />
+    <bean id="OpenID.VCI.CredentialOffer" parent="AbstractVCIProfile" lazy-init="true"
+        class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCICredentialOfferConfiguration" />
+
+    <bean id="OpenID.VCI.Token" parent="AbstractVCIProfile" lazy-init="true"
+        class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCITokenConfiguration" />
+
+    <bean id="OpenID.VCI.Credentials" parent="AbstractVCIProfile" lazy-init="true"
+        class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCICredentialsConfiguration" />
+
+    <bean id="OpenID.VCI.Nonce" parent="AbstractVCIProfile" lazy-init="true"
+        class="org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCINonceConfiguration"
+        p:dpopProofNonceGenerator="#{getObject('DefaultOpenIDVCINonceGenerator')}" />
+    
+    
+    <!-- We use special DPoP Nonce generator for Nonce endpoint. -->
+    <!-- The generator does not tie client id to nonce to accomodate unprotected Nonce endpoint. -->    
+    <bean id="DefaultOpenIDVCINonceGenerator" parent="DefaultOAuth2DPoPNonceGenerator" lazy-init="true"
+        p:relyingPartyIdLookupStrategy-ref="openidvci.RelyingPartyForNonce">
+    </bean>
+
+    <!-- Mock relying party for Nonce generation. -->
+    <bean id="openidvci.RelyingPartyForNonce" parent="shibboleth.Functions.Constant">
+        <constructor-arg>
+            <bean class="java.lang.String" c:_0="mockRelyingParty" />
+         </constructor-arg>
+    </bean>
 
 </beans>
diff --git a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java
index c18d615..7720558 100644
--- a/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java
+++ b/openid-vci-impl/src/test/java/org/geant/shibboleth/plugin/openidvci/profile/impl/FormOutboundTokenResponseMessageTest.java
@@ -22,7 +22,7 @@ import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.Arrays;
 
-import org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCIConfiguration;
+import org.geant.shibboleth.plugin.openidvci.config.impl.DefaultOpenIDVCITokenConfiguration;
 import org.geant.shibboleth.plugin.openidvci.messaging.context.TokenContext;
 import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferRequest;
 import org.geant.shibboleth.plugin.openidvci.messaging.impl.CredentialOfferTxCode;
@@ -76,7 +76,7 @@ public class FormOutboundTokenResponseMessageTest {
                 .addSubcontext(new TokenContext());
 
         RelyingPartyContext rpCtx = ((RelyingPartyContext) profileRequestCtx.addSubcontext(new RelyingPartyContext(),
-                true)).setProfileConfig(new DefaultOpenIDVCIConfiguration());
+                true)).setProfileConfig(new DefaultOpenIDVCITokenConfiguration());
         rpCtx.setRelyingPartyId("clientID");
         BasicRelyingPartyConfiguration rpConf = new BasicRelyingPartyConfiguration();
         rpConf.setId("mock");

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


More information about the commits mailing list