feat(be): add ICRC-3 attribute sharing API with nonce support#3726
Merged
feat(be): add ICRC-3 attribute sharing API with nonce support#3726
Conversation
…ions Add two new ICRC-3 attribute sharing endpoints that produce a single canister signature over a Candid-encoded ICRC-3 Value map of all attributes, instead of per-attribute signatures. - prepare_icrc3_attributes: validates caller-provided attribute values against stored OpenID credentials, Candid-encodes them as an ICRC-3 Map, and signs the encoded bytes - get_icrc3_attributes: retrieves the single signature for the message blob returned by prepare Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new ICRC-3-flavored attribute sharing flow to Internet Identity, adding endpoints that sign a single Candid-encoded ICRC-3 Value map containing all requested attribute key/value pairs, rather than per-attribute signatures.
Changes:
- Added
prepare_icrc3_attributes(update) andget_icrc3_attributes(query) canister APIs, including new request/response/error types. - Implemented ICRC-3 message construction (Candid-encoded map) and canister-signature issuance/lookup for the message blob.
- Added test plumbing: PocketIC API helpers, signature verification helper, and a new integration test covering the prepare → get → verify flow.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
src/internet_identity/src/main.rs |
Exposes the new prepare_icrc3_attributes / get_icrc3_attributes canister methods and wires validation/auth/account lookup. |
src/internet_identity/src/attributes.rs |
Implements ICRC-3 message building, validation against stored OpenID credential claims, and signature issuance/lookup. |
src/internet_identity/internet_identity.did |
Adds Candid types and service methods for the new ICRC-3 attribute sharing API. |
src/internet_identity_interface/src/internet_identity/types/attributes.rs |
Adds public interface types + validation logic for ICRC-3 prepare/get requests. |
src/internet_identity_interface/src/internet_identity/types/icrc3.rs |
Introduces the Icrc3Value enum used to build the signed message. |
src/internet_identity_interface/src/internet_identity/types.rs |
Exports the new icrc3 module. |
src/canister_tests/src/api/internet_identity.rs |
Adds PocketIC API wrappers to call the new endpoints. |
src/canister_tests/src/framework.rs |
Adds a helper to verify ICRC-3 attribute signatures in tests. |
src/internet_identity/tests/integration/attributes.rs |
Adds an integration test for the new ICRC-3 attribute sharing flow. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Import `candid::Encode` macro explicitly - Remove unreachable wildcard pattern in scope match Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aterga
commented
Apr 2, 2026
Introduce `AttributeSpec` type for `prepare_icrc3_attributes` with: - `key`: full attribute key with scope - `value: opt blob`: optional value matching against stored credentials - `omit_scope: bool`: strip scope prefix from certified key for privacy When `value` is None, the stored value is used without validation. When `omit_scope` is true, the certified key is just the attribute name (e.g., "email" instead of "openid:https://...:email"). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tests - Return typed NoSuchSignature error from get_icrc3_attributes instead of trapping - Fix ICRC3_MESSAGE_MAX_BYTES to include key sizes and Candid overhead - Add unit tests for ValidatedPrepareIcrc3AttributeRequest and ValidatedGetIcrc3AttributeRequest - Add 9 integration tests covering value set/unset, omit_scope true/false corner cases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Drop should_certify_icrc3_attributes_without_value_check and should_certify_icrc3_attributes_with_omit_scope since the mixed_omit_scope test already covers composability of omit_scope true/false. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The should_reject_icrc3_attributes_with_correct_and_wrong_value test already covers the wrong-value case while also testing partial mismatch. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Tests that don't rely on certification (value mismatch, unknown issuer, scopeless attribute, message encoding) are now unit tests on the core logic directly, keeping only certification-dependent tests as PocketIc integration tests. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
aterga
commented
Apr 2, 2026
aterga
commented
Apr 2, 2026
aterga
commented
Apr 2, 2026
5 tasks
The nonce is a 32-byte value generated by the relying party to prevent replay attacks and enable attribute expiration per flow. It is included in the signed ICRC-3 message as `implicit:nonce`. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The nonce field is now included in the certified pairs, so the ICRC-3 message map has 3 entries (email, name, implicit:nonce) instead of 2. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
sea-snake
approved these changes
Apr 2, 2026
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…validation Extend should_certify_icrc3_attributes_mixed_omit_scope to use a specific nonce, verify the canister signature, and assert that the nonce value in the certified message map matches the provided bytes. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
prepare_icrc3_attributes and get_icrc3_attributes API
prepare_icrc3_attributes and get_icrc3_attributes API…e bound
- Detect duplicate certified attribute keys in prepare_icrc3_attributes:
if two specs resolve to the same key (e.g., two issuers with
omit_scope=true both become "email"), return an error instead of
silently overwriting.
- Fix ICRC3_ATTRIBUTE_KEY_MAX_BYTES to account for the full scoped key
format ("openid:" + issuer + ":" + attribute_name) rather than just
the issuer length, ensuring ICRC3_MESSAGE_MAX_BYTES is a sound bound.
- Add unit test for duplicate key detection.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3 tasks
github-merge-queue bot
pushed a commit
that referenced
this pull request
Apr 2, 2026
## Summary - Add `list_available_attributes` query endpoint that lists attribute key/value pairs stored on an identity's OpenID credentials - Supports optional filtering via `attributes: opt vec text`: - `None` → returns all available attributes across all credentials - Scoped keys (e.g., `"openid:https://accounts.google.com:email"`) → exact match - Unscoped keys (e.g., `"email"`) → wildcard match across all scopes - Response always uses fully-scoped keys (e.g., `"openid:https://accounts.google.com:email"`) - Authenticated the same way as `prepare_icrc3_attributes` (via `check_authorization`) - No origin/account_number needed since no signing is performed ## Test plan - [x] Unit tests for `ValidatedListAvailableAttributesRequest` validation (valid/invalid inputs) - [x] Unit tests for `Anchor::list_available_attributes` (all attributes, scoped filter, unscoped wildcard, missing attributes, no credentials, wrong issuer) - [x] Integration test `should_list_all_available_attributes` — full flow with real credential storage - [x] All 203 binary unit tests pass - [x] All 30 interface unit tests pass < [Previous PR](#3726) | [Next PR](#3730) > --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
prepare_icrc3_attributes(update) andget_icrc3_attributes(query)prepare_attributes/get_attributesflow, the ICRC-3 variant produces a single canister signature over a Candid-encoded ICRC-3 Value map containing all requested attribute key-value pairsAttributeSpecwith optional value matching, scope control, and a relying-party nonce:value: opt blob— if set, validates against stored credential; if unset, uses stored value directlyomit_scope: bool— if true, certified key is just the attribute name (e.g.,"email"); if false, full scoped key (e.g.,"openid:https://...:email")nonce: blob— 32-byte value from the relying party, included as"implicit:nonce"in the signed ICRC-3 message map to prevent replay attacks"ic-request-auth-info"(used for canister signature computation)get_icrc3_attributesreturns a typedNoSuchSignatureerror instead of trapping when the signature is not foundIcrc3Value,AttributeSpec,PrepareIcrc3AttributeRequest/Response/Error,GetIcrc3AttributeRequest/Response/Errorprepare_attributes/get_attributesimplementation is not modifiedTest plan
ValidatedPrepareIcrc3AttributeRequestvalidation (attribute count, nonce length, key parsing, scope requirement)ValidatedGetIcrc3AttributeRequestvalidationAnchor::prepare_icrc3_attributeserror paths (value mismatch, unknown issuer, scopeless attribute)icrc3_attribute_messageencoding (determinism, decodability, scoped vs unscoped keys)omit_scopeand nonce value assertionNoSuchSignatureerror for unknown messagecargo checkpasses for all affected crates| Next PR >