Skip to content

[forge-iterating] AB#3677516: Add internal DPoP crypto key storage and cache helpers#8708

Open
hectormmg wants to merge 38 commits into
copilot/ab-3677516-dpop-proof-foundationfrom
copilot/ab-3674407-add-browser-es256-key-lifecycle
Open

[forge-iterating] AB#3677516: Add internal DPoP crypto key storage and cache helpers#8708
hectormmg wants to merge 38 commits into
copilot/ab-3677516-dpop-proof-foundationfrom
copilot/ab-3674407-add-browser-es256-key-lifecycle

Conversation

@hectormmg

@hectormmg hectormmg commented Jul 14, 2026

Copy link
Copy Markdown
Member

Summary

Adds internal DPoP crypto, browser key lifecycle, and token-binding helper primitives for L1 DPoP while keeping app-facing DPoP acquisition disabled until the public PCA enablement work item.

Implements

  • AB#3677516 - WI-2: Add internal DPoP crypto key storage and cache helpers

Scope

  • Adds browser token-binding key lifecycle support for scoped ES256/P-256 DPoP keys.
  • Preserves existing RSA/SHR PoP behavior while moving legacy PoP signing onto token-binding primitives.
  • Splits token-binding responsibilities so ICrypto owns crypto/signing and ITokenBindingKeyManager owns key provisioning, removal, and public JWK lookup.
  • Shares a controller-owned browser TokenBindingKeyManager through interaction/custom-auth clients so scoped provisioning dedupe is not lost across per-request clients.
  • Adds internal DPoP proof/key helper seams and metadata needed by later PCA wiring.
  • Keeps runtime DPoP acquisition fail-closed; this PR does not export AuthenticationScheme.DPOP or enable app-facing DPoP flows.
  • Splits TokenBindingKeyManager lifecycle coverage into a focused spec while keeping CryptoOps proof/signing integration coverage in CryptoOps.spec.ts.

Feature flag / waiver

  • Feature flag waiver: No runtime feature flag is required because this PR is internal scaffolding and is not wired into public token acquisition flows or enabled by user-facing configuration.
  • Default state: No user-visible DPoP behavior is enabled by default in this PR.
  • Release-safety posture: The branch is merge-safe before full L1 DPoP wiring because the public feature remains disabled until AB#3677517.

Rollout / rollback

  • Owner: MSAL.js team.
  • Rollout stages: Merge internal primitives first, monitor CI/package validation, then enable public L1 PCA DPoP acquisition in a separate PR/work item.
  • Success criteria: Existing Bearer/PoP/SHR/SSH behavior remains unchanged, DPoP internal key/proof tests pass, and telemetry records token-binding key metadata without logging proof or key material.
  • Rollback path: Revert PR [forge-iterating] AB#3677516: Add internal DPoP crypto key storage and cache helpers #8708 if the internal primitives cause regressions. No flag flip is needed because public DPoP behavior is not enabled here.

How to validate

  • npm test --workspace=@azure/msal-common -- JoseHeader.spec.ts JoseHeaderError.spec.ts DpopProofGenerator.spec.ts
  • npm test --workspace=@azure/msal-common -- --runTestsByPath test/crypto/PopTokenGenerator.spec.ts --runInBand
  • npm test --workspace=@azure/msal-browser -- CryptoOps.spec.ts TokenBindingKeyManager.spec.ts
  • npm run build:all, npm run lint, npm run format:check, and npm run apiExtractor -- --local in affected 3P packages
  • For browser/node API reports after common API changes, run package build:all before apiExtractor -- --local.

Notes

This PR previously referenced removed work item AB#3674407. The active WI-2 tracking item is AB#3677516.

Add browser ES256 token-binding key provisioning, scoped DPoP key reuse, token-binding JWT signing seams, and supporting tests/docs/API review updates.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 14, 2026 22:40
@hectormmg
hectormmg requested review from a team as code owners July 14, 2026 22:40
@hectormmg
hectormmg marked this pull request as draft July 14, 2026 22:41
@hectormmg
hectormmg marked this pull request as ready for review July 14, 2026 22:42
Add beachball changefiles for browser, common, and node package changes in the DPoP key lifecycle PR.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds browser-side ES256 DPoP token-binding key lifecycle support (provision/reuse, public JWK lookup, compact JWT signing), and refactors SHR/PoP signing to use the same token-binding seams, with new telemetry fields and updated tests/docs/API reviews across msal-common, msal-browser, and msal-node.

Changes:

  • Extend ICrypto with token-binding key provisioning/lookup/signing APIs and add JOSE header helpers for SHR + DPoP.
  • Implement browser token-binding key caching/scoping + signing in CryptoOps, and update PoP/DPoP generators/tests to use the new seams.
  • Add new error codes/docs and enrich performance telemetry with token-binding key metadata.

Reviewed changes

Copilot reviewed 25 out of 25 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
lib/msal-node/test/utils/TestConstants.ts Extends node test crypto stub with new token-binding crypto surface (not implemented).
lib/msal-node/src/crypto/CryptoProvider.ts Adds unimplemented node placeholders for token-binding provisioning/lookup/signing; deprecates signJwt.
lib/msal-node/apiReview/msal-node.api.md Updates msal-node API review to include new ICrypto members and deprecation markers.
lib/msal-common/test/crypto/PopTokenGenerator.spec.ts Updates SHR/PoP generator tests to validate token-binding provisioning and signing seams.
lib/msal-common/test/crypto/JoseHeader.spec.ts Adds correlationId assertions for JOSE header error cases; adds DPoP header test coverage.
lib/msal-common/test/crypto/DpopProofGenerator.spec.ts Refactors DPoP tests to use signTokenBindingJwt + key context instead of a custom signer.
lib/msal-common/test/client/ClientTestUtils.ts Extends common test crypto mock with token-binding provisioning/lookup/signing methods.
lib/msal-common/src/utils/Constants.ts Adds JsonWebTokenTypes.Dpop constant for DPoP JOSE headers.
lib/msal-common/src/telemetry/performance/PerformanceEvent.ts Adds token-binding key telemetry metadata fields to performance events.
lib/msal-common/src/exports-common.ts Exposes new crypto types/constants via common exports.
lib/msal-common/src/error/JoseHeaderErrorCodes.ts Adds missing_jwk_error code for DPoP header validation.
lib/msal-common/src/crypto/PopTokenGenerator.ts Updates SHR signing flow to provision token-binding key + use token-binding JWK/signing seams.
lib/msal-common/src/crypto/JoseHeader.ts Adds jwk support and introduces typed builders for SHR and DPoP headers with correlationId propagation.
lib/msal-common/src/crypto/ICrypto.ts Adds token-binding key provisioning/context types + new crypto interface methods; marks legacy helpers deprecated.
lib/msal-common/src/crypto/DpopProofGenerator.ts Adds DPoP key scope + JKT generation and routes proof signing through signTokenBindingJwt.
lib/msal-common/apiReview/msal-common.api.md Updates public API review snapshot for new crypto APIs, constants, and telemetry fields.
lib/msal-browser/test/crypto/CryptoOps.spec.ts Adds/updates tests for scoped key reuse, signing behaviors, and token-binding telemetry emission.
lib/msal-browser/src/error/BrowserAuthErrorCodes.ts Adds new browser error codes for token-binding JWT algorithm validation.
lib/msal-browser/src/crypto/CryptoOps.ts Implements browser token-binding key lifecycle (scoped caching, signing, public JWK lookup) and telemetry.
lib/msal-browser/src/crypto/BrowserCrypto.ts Broadens sign input type to BufferSource for WebCrypto API compatibility.
lib/msal-browser/apiReview/msal-browser.api.md Updates browser API review snapshot for new error codes and JsonWebTokenTypes.Dpop.
docs/errors.md Documents new JOSE header and browser token-binding-related error codes.

Comment thread lib/msal-common/src/crypto/PopTokenGenerator.ts Outdated
Comment thread lib/msal-browser/src/crypto/CryptoOps.ts Outdated
Comment thread docs/errors.md
hectormmg and others added 8 commits July 14, 2026 15:46
Resolve the DPoP proof public JWK from the token-binding key used for signing instead of accepting caller-provided header key material.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move browser token-binding key provisioning, scoped lookup, public JWK export, removal, and key telemetry shaping into an internal TokenBindingKeyManager. Keep JWT signing in CryptoOps while removing new token-binding lifecycle methods from the public ICrypto contract.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add a distinct browser error for supported JWT alg values that do not match the stored token-binding key material. Preserve caller-provided SHR alg values and fall back to RS256 when exported JWK alg metadata is missing.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Ensure scoped DPoP provisioning can reuse persisted keys when memory contains unrelated entries, validates cached key metadata before reuse, and coalesces concurrent scoped provisioning requests.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clarify that legacy ICrypto and implementation signing/thumbprint helpers are SHR compatibility wrappers for MSAL-internal token-binding flows.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Treat an empty DPoP JOSE header JWK as an internal invariant failure while keeping algorithm-specific key policy outside the generic JOSE header helper.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add the PR link required by changefile guidance to the DPoP key lifecycle changefiles.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Document DPoP IndexedDB compatibility and add TSDoc for token-binding key manager surfaces.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@hectormmg hectormmg changed the title AB#3674407: Add browser ES256 DPoP key lifecycle [forge-iterating] AB#3677516: Add internal DPoP crypto key storage and cache helpers Jul 15, 2026
hectormmg and others added 5 commits July 16, 2026 13:11
Use request-context DPoP key metadata for cache partitioning, keep runtime DPoP requests fail-closed, and share token-binding fallback storage across manager instances.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reject token-binding JWT headers whose embedded JWK thumbprint does not match the signing key identifier.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Move TokenBindingKeyManager lifecycle coverage into a focused spec while keeping CryptoOps proof/signing integration tests in CryptoOps.spec.ts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Coder
@hectormmg

Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Comment thread lib/msal-browser/src/crypto/CryptoOps.ts Outdated
peterzenz
peterzenz previously approved these changes Jul 17, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 60 out of 60 changed files in this pull request and generated 4 comments.

Comments suppressed due to low confidence (1)

lib/msal-common/src/crypto/ITokenBindingKeyManager.ts:83

  • DEFAULT_TOKEN_BINDING_KEY_MANAGER always throws with an empty correlationId and omits the interface parameters, which drops the caller’s correlationId from the resulting ClientAuthError. Since these methods are invoked with a correlationId, the default implementation should accept/forward it so errors are properly correlated.

Comment thread change/@azure-msal-common-dpop-key-lifecycle.json Outdated
Comment thread change/@azure-msal-node-dpop-key-lifecycle.json Outdated
Comment thread change/@azure-msal-browser-dpop-key-lifecycle.json Outdated
Comment on lines +266 to +270
idTokenClaims,
undefined,
undefined,
undefined,
this.config.tokenBindingKeyManager
Use msal-common token-binding key manager types directly from browser and propagate correlation IDs through the default token-binding key manager.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 21, 2026 22:42

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated 2 comments.

Comment on lines 98 to 112
/**
* Get all the keys from the in-memory cache as an iterable array of strings. If no keys are found, query the keys in the
* asynchronous storage object.
* Get all keys from both in-memory and persistent storage.
* @param correlationId
*/
async getKeys(correlationId: string): Promise<string[]> {
const cacheKeys = this.inMemoryCache.getKeys();
if (cacheKeys.length === 0) {
try {
this.logger.verbose(
"In-memory cache is empty, now querying persistent storage.",
correlationId
);
return await this.indexedDBCache.getKeys();
} catch (e) {
this.handleDatabaseAccessError(e, correlationId);
}
try {
const persistentCacheKeys = await this.indexedDBCache.getKeys();
return Array.from(new Set([...cacheKeys, ...persistentCacheKeys]));
} catch (e) {
this.handleDatabaseAccessError(e, correlationId);
}

return cacheKeys;
}
Comment on lines +317 to +321
throw createBrowserAuthError(
BrowserAuthErrorCodes.invalidPublicJwk,
correlationId,
BrowserAuthErrorCodes.tokenBindingKeyJwkThumbprintMismatch
);
Promote DPoP lifecycle changefiles to minor because ICrypto now exposes token binding hooks, add discoverable docs for new token-binding suberrors, and commit formatting updates from validation.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 21, 2026 23:00

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 61 out of 61 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (3)

lib/msal-common/src/crypto/ICrypto.ts:148

  • DEFAULT_CRYPTO_IMPLEMENTATION.removeTokenBindingKey throws a methodNotImplemented error with an empty correlationId. Since ICrypto now requires correlationId and callers rely on it for diagnostics, the default stub should accept the correlationId parameter (and optional context) and pass it through to createClientAuthError.
    lib/msal-common/src/crypto/ICrypto.ts:160
  • DEFAULT_CRYPTO_IMPLEMENTATION.signTokenBindingJwt throws methodNotImplemented with an empty correlationId and doesn't accept the required parameters. Update the stub signature to match ICrypto and pass the provided correlationId through to createClientAuthError for better diagnostics.
    lib/msal-node/src/crypto/CryptoProvider.ts:81
  • CryptoProvider.removeTokenBindingKey stub no longer matches the ICrypto signature (kid, correlationId, optional context). Because CryptoProvider is a public class, consumers calling it directly will see the wrong type signature. Align the method signature with ICrypto even if the node implementation remains unimplemented.

Comment on lines 150 to 154
async clearKeystore(): Promise<boolean> {
throw createClientAuthError(
ClientAuthErrorCodes.methodNotImplemented,
""
);
Comment on lines 83 to 88
/**
* Removes all cryptographic keys from Keystore
*/
clearKeystore(): Promise<boolean> {
throw new Error("Method not implemented.");
}
Comment on lines 90 to 95
/**
* Signs the given object as a jwt payload with private key retrieved by given kid - currently not implemented for node
* Signs a compact JWT with a token-binding key - not yet implemented for node
*/
signJwt(): Promise<string> {
signTokenBindingJwt(): Promise<string> {
throw new Error("Method not implemented.");
}
Pass the configured token binding key manager into node ResponseHandler paths so PoP signing does not accidentally fall back to the default unsupported manager. Update the common PoP regression test to provide the mock token binding manager for signing.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 21, 2026 23:55

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 67 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

lib/msal-browser/src/cache/AsyncMemoryStorage.ts:106

  • AsyncMemoryStorage.getKeys now always queries IndexedDB even when in-memory keys exist. DatabaseStorage.getKeys() can reject with a raw Event (transaction error), and handleDatabaseAccessError will rethrow non-databaseUnavailable errors, meaning getKeys can now throw instead of falling back to in-memory keys. This undermines the intended "persistent storage backed by memory" behavior and can cause unexpected failures in callers that only need the in-memory keys (e.g., key-scope lookups).
    async getKeys(correlationId: string): Promise<string[]> {
        const cacheKeys = this.inMemoryCache.getKeys();
        try {
            const persistentCacheKeys = await this.indexedDBCache.getKeys();
            return Array.from(new Set([...cacheKeys, ...persistentCacheKeys]));

lib/msal-common/src/crypto/ICrypto.ts:101

  • ICrypto is exported as part of the public @azure/msal-common surface, and this change removes/renames existing members (getPublicKeyThumbprint, signJwt) into signTokenBindingJwt with a different signature. Any external consumer providing a custom cryptoInterface implementation (or calling these methods on an ICrypto-typed object) will experience a compile-time break, which is semver-major. Consider keeping the old members as deprecated (with a compatibility shim/fallback in internal call sites) for at least one major version before removing them, or otherwise ensure this lands under an intentional major-version plan.

Preserve caller correlation when DPoP header public JWK validation fails and when scoped token-binding key requests join an active provisioning operation.

Accepted review context: JWK sanitization is intentionally not added because browser exports public JWKs from WebCrypto public keys, node token-binding is not implemented, and L1 does not support a custom key-manager surface. Static key storage using the first logger is accepted because operation-specific storage calls still receive the current correlation id.

Co-authored-by: Forge <forge-bot@entra.github.io>

Forge-Agent: Developer

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 05:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 67 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

lib/msal-browser/src/crypto/CryptoOps.ts:322

  • When the token-binding JWT header includes a jwk property but it is not an object, this throws invalidPublicJwk with subError token_binding_key_jwk_thumbprint_mismatch. That subError is misleading here (no thumbprint comparison occurred) and makes diagnostics harder. Prefer throwing invalidPublicJwk without the thumbprint-mismatch subError for this malformed-header case; keep the mismatch subError only for the actual kid vs JWK-thumbprint mismatch path in validateTokenBindingJwtHeaderKey.
    throw createBrowserAuthError(
        BrowserAuthErrorCodes.invalidPublicJwk,
        correlationId,
        BrowserAuthErrorCodes.tokenBindingKeyJwkThumbprintMismatch
    );

lib/msal-common/src/crypto/ICrypto.ts:161

  • DEFAULT_CRYPTO_IMPLEMENTATION.signTokenBindingJwt always throws methodNotImplemented with an empty correlationId (""), even though callers now must provide a correlationId to signTokenBindingJwt. This drops useful diagnostics. Update the default stub to accept the method parameters and pass the provided correlationId through to createClientAuthError.

hectormmg and others added 2 commits July 22, 2026 13:47
Use the normalized token-binding JWT header as the protected header input instead of reserializing the caller-owned object after async validation. Add regression coverage that mutates the original DPoP header during validation and verifies the signed header remains normalized.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Preserve in-memory cache keys when IndexedDB key enumeration fails unexpectedly and memory fallback contains entries. Unexpected persistent failures still surface when there is no memory fallback.

Co-authored-by: Forge <forge-bot@entra.github.io>
Forge-Agent: Developer
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 22, 2026 23:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 67 changed files in this pull request and generated 2 comments.

Comment on lines +303 to +307
const tokenBindingJwtHeader: TokenBindingSigningHeader = {
alg: header.alg,
};

return signedJwt;
if (!("jwk" in header) || typeof header.jwk === "undefined") {
Comment on lines +907 to +910
expect(proofHeader).toEqual({
alg: "ES256",
jwk: publicJwk,
});
hectormmg and others added 2 commits July 22, 2026 16:52
Replace ResponseHandler.generateAuthenticationResult optional positional parameters with a named options object so token-binding manager wiring does not rely on placeholder undefined arguments.

Forge-Agent: Developer

Co-authored-by: Forge <forge-bot@entra.github.io>

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 23, 2026 00:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 67 out of 67 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (1)

lib/msal-browser/src/crypto/CryptoOps.ts:322

  • When header.jwk is present but not an object, validateTokenBindingSigningHeader throws invalid_public_jwk with subError token_binding_key_jwk_thumbprint_mismatch. That subError is misleading here (no thumbprint comparison happened), and will complicate diagnosing malformed headers.
    throw createBrowserAuthError(
        BrowserAuthErrorCodes.invalidPublicJwk,
        correlationId,
        BrowserAuthErrorCodes.tokenBindingKeyJwkThumbprintMismatch
    );

Comment on lines +283 to +299
const keyPair: CryptoKeyPair = await BrowserCrypto.generateKeyPair(
false,
usages,
keyGenAlgorithm
);
const publicJwk: JsonWebKey = await BrowserCrypto.exportJwk(
keyPair.publicKey
);
const keyId = await BrowserCrypto.computeJwkThumbprint(
publicJwk,
correlationId
);
return {
publicKey: keyPair.publicKey,
privateKey: keyPair.privateKey,
keyId,
};
@hectormmg
hectormmg changed the base branch from dev to copilot/ab-3677516-dpop-proof-foundation July 23, 2026 01:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants