Summary
Signature5VerifierService.CreateFromRequest() (called via Signature5Verifier.Verify()) performs three steps internally:
Parse() — decrypt and unpack the signature.
Verify() — check the binding against the caller-supplied IP/User-Agent.
Signature5ResponseMapper.MapToResponse() — map the result to the response.
As per the V5 documentation, decryption itself does not depend on IP or User-Agent, the verdict is fully present in the decrypted payload before the binding check runs.
However, if Verify() finds that the caller supplied IP or User-Agent does not match what is embedded in the signature, it throws an ArgumentException ("Signature IP mismatch" / "Signature user agent mismatch"). The caller therefore has no way to retrieve the verdict that was already successfully decrypted.
In real-world server-side deployments, requests redeeming a signature can pass through infrastructure such as load balancers, proxies, and CDNs that legitimately alter the observed IP or User-Agent header between signature creation and verification.
In that situation, an integrator has no way to distinguish between:
- A signature that is invalid or corrupt.
- A signature that is valid and whose verdict is known, but whose binding check failed.
Both cases are thrown as an exception, and the already decrypted verdict is discarded.
Current behavior
- Any IP/User-Agent mismatch causes
Verify() to throw before the verdict can be read.
- The only way to access the verdict in that situation would be to reimplement
Parse() using the SDK's public building blocks and skip Verify() entirely.
- However, the decryption primitives (
CryptFactory, CryptParser) are internal, so even that workaround is not possible without overriding private implementation details of the dotnet-common library.
Requested behavior
Either of the following approaches would resolve the issue:
1. Return the decrypted result alongside binding status
Provide a method that returns the decrypted verdict result regardless of IP/User-Agent binding, alongside a boolean or enum indicating whether the binding check passed.
For example:
Signature5VerificationResult CreateFromRequest(
string signature,
string userAgent,
string key,
List<string> ipAddresses,
bool enforceBinding = true);
Alternatively, provide a separate TryCreateFromRequest(...) method that does not throw on binding mismatch and instead exposes a BindingMatched property on the result.
This would allow integrators to decide how much to trust a binding mismatch based on their deployment environment, rather than having the SDK make that decision by throwing.
2. Expose the low-level decrypt/parse operation
Alternatively, expose the low-level decrypt/parse step (Parse() equivalent) as public or protected.
This would allow integrators who need to implement their own binding policy to do so using the supported API surface, without relying on reflection or overriding internal classes.
Summary
Signature5VerifierService.CreateFromRequest()(called viaSignature5Verifier.Verify()) performs three steps internally:Parse()— decrypt and unpack the signature.Verify()— check the binding against the caller-supplied IP/User-Agent.Signature5ResponseMapper.MapToResponse()— map the result to the response.As per the V5 documentation, decryption itself does not depend on IP or User-Agent, the verdict is fully present in the decrypted payload before the binding check runs.
However, if
Verify()finds that the caller supplied IP or User-Agent does not match what is embedded in the signature, it throws anArgumentException("Signature IP mismatch"/"Signature user agent mismatch"). The caller therefore has no way to retrieve the verdict that was already successfully decrypted.In real-world server-side deployments, requests redeeming a signature can pass through infrastructure such as load balancers, proxies, and CDNs that legitimately alter the observed IP or User-Agent header between signature creation and verification.
In that situation, an integrator has no way to distinguish between:
Both cases are thrown as an exception, and the already decrypted verdict is discarded.
Current behavior
Verify()to throw before the verdict can be read.Parse()using the SDK's public building blocks and skipVerify()entirely.CryptFactory,CryptParser) are internal, so even that workaround is not possible without overriding private implementation details of thedotnet-commonlibrary.Requested behavior
Either of the following approaches would resolve the issue:
1. Return the decrypted result alongside binding status
Provide a method that returns the decrypted verdict result regardless of IP/User-Agent binding, alongside a boolean or enum indicating whether the binding check passed.
For example:
Alternatively, provide a separate
TryCreateFromRequest(...)method that does not throw on binding mismatch and instead exposes aBindingMatchedproperty on the result.This would allow integrators to decide how much to trust a binding mismatch based on their deployment environment, rather than having the SDK make that decision by throwing.
2. Expose the low-level decrypt/parse operation
Alternatively, expose the low-level decrypt/parse step (
Parse()equivalent) aspublicorprotected.This would allow integrators who need to implement their own binding policy to do so using the supported API surface, without relying on reflection or overriding internal classes.