[java-idp-plugin-vci] 01/01: Percent encode the credential offer
Codeberg
noreply at shibboleth.net
Mon Sep 21 10:30:30 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch bugs/LowHanging
in repository java-idp-plugin-vci.
View the commit online:
https://codeberg.org/Shibboleth/java-idp-plugin-vci/commit/0d2799d243c752fe912d01ecb4351abddff9933e
commit 0d2799d243c752fe912d01ecb4351abddff9933e
Author: Janne Lauros <janne.lauros at csc.fi>
AuthorDate: Mon Sep 21 13:29:54 2026 +0300
Percent encode the credential offer
---
README.md | 9 +++++----
.../messaging/impl/CredentialOfferSuccessResponse.java | 12 +++++++++++-
2 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/README.md b/README.md
index 0c7477b..0a7d6dd 100644
--- a/README.md
+++ b/README.md
@@ -604,11 +604,12 @@ curl -u 'offer-caller:CHANGE-ME' \
}'
```
-The response is the Credential Offer as a deep link, in one line and with no whitespace. This
-is what you put in the QR code. The `value` of the transaction code is not in it:
+The response is the Credential Offer as a deep link, in one line and with no whitespace. The
+offer JSON travels as a query parameter, so it is percent-encoded. This is what you put in
+the QR code. The `value` of the transaction code is not in it:
```
-openid-credential-offer://?credential_offer={"credential_issuer":"https://issuer.example.org","credential_configuration_ids":["GeantIncubatorDiploma_SDJWT","GeantIncubatorDiploma_W3C"],"grants":{"urn:ietf:params:oauth:grant-type:pre-authorized_code":{"pre-authorized_code":"AAdzZWNyZXQxWKPQ...","tx_code":{"input_mode":"numeric","length":6,"description":"The code we sent to your phone"}}}}
+openid-credential-offer://?credential_offer=%7B%22credential_issuer%22:%22https://issuer.example.org%22,%22credential_configuration_ids%22:%5B%22GeantIncubatorDiploma_SDJWT%22,%22GeantIncubatorDiploma_W3C%22%5D,%22grants%22:%7B%22urn:ietf:params:oauth:grant-type:pre-authorized_code%22:%7B%22pre-authorized_code%22:%22AAdzZWNyZXQxWKPQ...%22,%22tx_code%22:%7B%22input_mode%22:%22numeric%22,%22length%22:6,%22description%22:%22The%20code%20we%20sent%20to%20your%20phone%22%7D%7D%7D%7D
```
</details>
@@ -639,7 +640,7 @@ Nothing in the offer is per user here, so you write it by hand. The same url ser
and you may print it once as a QR code:
```
-openid-credential-offer://?credential_offer={"credential_issuer":"https://issuer.example.org","credential_configuration_ids":["GeantIncubatorDiploma_SDJWT"],"grants":{"authorization_code":{}}}
+openid-credential-offer://?credential_offer=%7B%22credential_issuer%22:%22https://issuer.example.org%22,%22credential_configuration_ids%22:%5B%22GeantIncubatorDiploma_SDJWT%22%5D,%22grants%22:%7B%22authorization_code%22:%7B%7D%7D%7D
```
The `authorization_code` grant is what tells the wallet to run this flow. What is issued comes
diff --git a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java
index 6e11489..78cee42 100644
--- a/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java
+++ b/openid-vci-impl/src/main/java/org/geant/shibboleth/plugin/openidvci/messaging/impl/CredentialOfferSuccessResponse.java
@@ -29,6 +29,7 @@ import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.net.PercentEscaper;
import com.nimbusds.common.contenttype.ContentType;
import com.nimbusds.oauth2.sdk.SuccessResponse;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
@@ -46,6 +47,14 @@ public class CredentialOfferSuccessResponse implements SuccessResponse {
@Nonnull
private Logger log = LoggerFactory.getLogger(CredentialOfferSuccessResponse.class);
+ /**
+ * Percent-encoder for the Credential Offer query parameter value.
+ *
+ * RFC 3986 unreserved set plus ":", "/" and ",".
+ */
+ @Nonnull
+ private static final PercentEscaper OFFER_ESCAPER = new PercentEscaper("-._~:/,", false);
+
/** credential_issuer parameter. */
@JsonProperty("credential_issuer")
private final String credentialIssuer;
@@ -116,7 +125,8 @@ public class CredentialOfferSuccessResponse implements SuccessResponse {
*/
private String toOffer() throws JsonProcessingException {
final ObjectMapper objectMapper = new ObjectMapper();
- return "openid-credential-offer://?credential_offer=" + objectMapper.writeValueAsString(this);
+ return "openid-credential-offer://?credential_offer="
+ + OFFER_ESCAPER.escape(objectMapper.writeValueAsString(this));
}
/** {@inheritDoc} */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list