Skip to content

feat(IT-Wallet): [SIW-4149] Credential offer from third channel#8047

Open
riccardosacco99 wants to merge 50 commits into
masterfrom
SIW-4149-third-channel-credential-offer
Open

feat(IT-Wallet): [SIW-4149] Credential offer from third channel#8047
riccardosacco99 wants to merge 50 commits into
masterfrom
SIW-4149-third-channel-credential-offer

Conversation

@riccardosacco99

@riccardosacco99 riccardosacco99 commented Apr 20, 2026

Copy link
Copy Markdown
Collaborator

This PR adds the credential offer issuance channel, allowing the user to start an IT-Wallet credential issuance by scanning a credential offer QR code or opening a credential offer deep link / universal link. The incoming URI is
validated, resolved through the IT-Wallet SDK, and then fed into the existing itwCredentialIssuanceMachine, which drives the user to the new intro screen before continuing with the standard issuance flow.

List of changes proposed in this pull request

Credential machine:

  • Added CredentialOfferValidation and CredentialOfferResolved states to itwCredentialIssuanceMachine
  • Added processCredentialOffer actor that resolves the offer URI and extracts grant details via @pagopa/io-react-native-wallet
  • Added credentialOfferUri and resolvedCredentialOffer to the machine context, plus selectResolvedCredentialOfferOption
  • Added start-credential-offer and confirm-credential-offer events
  • Realigned the waitForSessionRefresh stub to fromCallback to match the shared createCommonActorsImplementation contract (unblocks the typecheck broken by the test-side provider)

Screens:

  • Added ItwIssuanceCredentialOfferIntroScreen — on focus it dispatches start-credential-offer to the machine, shows a loading state while the offer is resolved, and on user confirmation dispatches confirm-credential-offer to
    continue into the standard issuance flow

Barcode:

  • Added ITW_CREDENTIAL_OFFER barcode type and decodeItwCredentialOfferBarcode in barcode/types/decoders.ts
  • Added isPotentialCredentialOfferInvocation utility that detects the three supported formats (openid-credential-offer://, haip-vci://, and https:// with credential_offer / credential_offer_uri query params)
  • Wired BarcodeScanScreen to route decoded offers to the new intro screen

Navigation:

  • Registered ITW_ISSUANCE_CREDENTIAL_OFFER_INTRO route in ItwParamsList, ItwStackNavigator, and navigation/routes.ts
  • Hid the default header on the intro screen (options={hiddenHeader}), aligning it with the rest of the ITW stack and preventing a flash of the raw route name before useHeaderSecondLevel mounts the custom header

Deep link support:

  • Registered openid-credential-offer:// and haip-vci:// custom URL schemes natively (ios/IO/Info.plist CFBundleURLTypes, android/app/src/main/AndroidManifest.xml intent-filters)
  • Added the credential-offer path to useItwLinkingOptions, so universal links like https://continua.io.pagopa.it/itw/credential-offer?itwCredentialOfferUri=… are routed to the intro screen
  • Extended getInternalRoute to rewrite credential offer custom schemes — which carry the full payload in the query string and have no real path — into ioit://itw/credential-offer?itwCredentialOfferUri=<encoded>, reusing
    isPotentialCredentialOfferInvocation so QR, custom scheme and universal link share a single validation source of truth
  • Wired the normalizer into both deeplink entry points: linkingSubscription (warm start — app in background) and a custom getInitialURL in AppStackNavigator (cold start — app killed, which React Navigation would otherwise ignore
    because the custom scheme doesn't match its configured prefixes)

Tests:

  • New cases in internalLink.test.ts covering the three credential offer URI shapes plus a non-regression case for unrelated URLs
  • New cases in linkingSubscription.test.ts verifying that both the React Navigation listener and storeLinkingUrl (post-login replay) receive the normalized URL when a credential offer is received

How to test

⚠️ Important — this feature consumes IoWallet.CredentialsOffer.resolveCredentialOffer, available in @pagopa/io-react-native-wallet only from IT-Wallet specs v1.3.3 onwards. On lower versions the flow intentionally returns an UNEXPECTED error with "Missing v1.x.x compatible implementation for resolveCredentialOffer". This is the intended behaviour until the prod specs version is upgraded.

QR code — main flow:
Scan the following QR code to verify the credential offer start flow reaches ItwIssuanceCredentialOfferIntroScreen, resolves the offer, and — on confirmation — continues into the standard issuance flow:

image

QR code — decoding validation:
To verify that non-offer barcodes are correctly ignored, scan a QR code whose payload does not match any supported scheme or query parameter (e.g. a plain URL like https://example.com). Expected: the scanner falls back to its default
handling — no navigation to the intro screen.

Deep link — from external camera app:
Scan the QR code above from the default camera app of your smartphone. Expected: the OS opens IO and routes to ItwIssuanceCredentialOfferIntroScreen (after login if not authenticated), the offer is resolved and shown.

Deep link — custom scheme (cold start):
With IO killed, trigger the URL directly:

# iOS
xcrun simctl openurl booted "openid-credential-offer://?credential_offer=<payload>"
# Android
adb shell am start -W -a android.intent.action.VIEW -d "openid-credential-offer://?credential_offer=<payload>"

Expected: IO launches and lands on the intro screen with the offer resolved.

Deep link — custom scheme (warm start):
With IO in the background, trigger the same commands. Expected: IO returns to foreground on the intro screen.

Universal link:

xcrun simctl openurl booted "https://continua.io.pagopa.it/itw/credential-offer?itwCredentialOfferUri=openid-credential-offer%3A%2F%2F%3F..."

Expected: same as above. Requires the universal link /itw/credential-offer path to be handled by the Apple App Site Association / Android Digital Asset Links config on continua.io.pagopa.it (backend coordination).

2026-04-23_scrcpy_002200.mp4

@github-actions

github-actions Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Jira Pull Request Link

This Pull Request refers to Jira issues:

@github-actions

Copy link
Copy Markdown
Contributor

PR Title Validation for conventional commit type

All good! PR title follows the conventional commit type.

@codecov

codecov Bot commented Apr 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 68.96552% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 62.39%. Comparing base (b71fcee) to head (a244796).

Files with missing lines Patch % Lines
.../offer/screens/ItwIssuanceCredentialOfferIntro.tsx 55.55% 10 Missing and 6 partials ⚠️
.../ts/features/itwallet/machine/credential/actors.ts 22.22% 7 Missing ⚠️
...main-app/ts/features/itwallet/offer/utils/index.ts 78.78% 4 Missing and 3 partials ⚠️
.../ts/features/barcode/screens/BarcodeScanScreen.tsx 0.00% 2 Missing ⚠️
...twallet/common/utils/itwCredentialIssuanceUtils.ts 77.77% 0 Missing and 2 partials ⚠️
.../features/itwallet/machine/credential/selectors.ts 50.00% 1 Missing ⚠️
apps/main-app/ts/navigation/AppStackNavigator.tsx 0.00% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #8047      +/-   ##
==========================================
+ Coverage   62.32%   62.39%   +0.06%     
==========================================
  Files        1954     1956       +2     
  Lines       36943    37054     +111     
  Branches     6166     6192      +26     
==========================================
+ Hits        23026    23119      +93     
- Misses      12553    12558       +5     
- Partials     1364     1377      +13     
Files with missing lines Coverage Δ
...pps/main-app/ts/features/barcode/types/decoders.ts 97.87% <100.00%> (+0.31%) ⬆️
...ts/features/itwallet/common/utils/itwTypesUtils.ts 25.00% <ø> (ø)
...ts/features/itwallet/machine/credential/context.ts 100.00% <ø> (ø)
...ts/features/itwallet/machine/credential/machine.ts 95.65% <100.00%> (+1.53%) ⬆️
...features/itwallet/navigation/ItwStackNavigator.tsx 25.00% <ø> (ø)
...main-app/ts/features/itwallet/navigation/routes.ts 100.00% <ø> (ø)
...tures/itwallet/navigation/useItwLinkingOptions.tsx 100.00% <100.00%> (ø)
apps/main-app/ts/features/linking/sagas/index.ts 68.75% <100.00%> (+14.20%) ⬆️
apps/main-app/ts/navigation/linkingSubscription.ts 92.30% <100.00%> (+1.00%) ⬆️
.../features/itwallet/machine/credential/selectors.ts 52.38% <50.00%> (-0.26%) ⬇️
... and 6 more

... and 3 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update b71fcee...a244796. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@riccardosacco99 riccardosacco99 marked this pull request as ready for review April 21, 2026 07:55
@riccardosacco99 riccardosacco99 marked this pull request as draft April 21, 2026 12:50
# Conflicts:
#	apps/main-app/ts/features/itwallet/machine/credential/__tests__/actors.test.ts
#	apps/main-app/ts/utils/__tests__/internalLink.test.ts

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

This PR introduces a new “credential offer” issuance entry point for IT-Wallet, allowing users to start credential issuance by scanning a credential-offer QR code or opening a credential-offer deep link (custom scheme / universal link), normalizing and routing the incoming URL into the existing issuance state machine.

Changes:

  • Added credential-offer deep link normalization + routing (warm/cold start) and corresponding navigation route registration.
  • Extended the ITW credential issuance machine with credential-offer validation/resolution states and a new intro screen that kicks off the offer processing.
  • Added a new barcode type/decoder for credential offers, with unit/integration tests for normalization and navigation replay behavior.

Reviewed changes

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

Show a summary per file
File Description
apps/main-app/ts/navigation/linkingSubscription.ts Normalizes credential-offer links on warm-start subscription before passing them to React Navigation.
apps/main-app/ts/navigation/AppStackNavigator.tsx Adds credential-offer prefixes and normalizes initial URL before storing for replay.
apps/main-app/ts/navigation/test/linkingSubscription.test.ts Tests normalization behavior for credential-offer URLs on subscription events.
apps/main-app/ts/features/linking/sagas/index.ts Replays stored credential-offer URLs after login by navigating to the ITW intro screen.
apps/main-app/ts/features/linking/sagas/test/index.test.ts Tests stored-link replay navigation for credential-offer URLs.
apps/main-app/ts/features/itwallet/offer/utils/index.ts Adds detection/normalization helpers for credential-offer invocations and extraction.
apps/main-app/ts/features/itwallet/offer/utils/tests/index.test.ts Unit tests for credential-offer invocation detection + normalization helper.
apps/main-app/ts/features/itwallet/offer/screens/ItwIssuanceCredentialOfferIntro.tsx New intro screen that starts offer resolution and continues into the issuance flow.
apps/main-app/ts/features/itwallet/offer/screens/tests/ItwIssuanceCredentialOfferIntro.test.tsx Screen test ensuring redirection behavior when wallet lifecycle requires discovery.
apps/main-app/ts/features/itwallet/navigation/useItwLinkingOptions.tsx Registers the universal-link path for credential-offer intro screen.
apps/main-app/ts/features/itwallet/navigation/routes.ts Adds the new ITW issuance route constant for credential-offer intro.
apps/main-app/ts/features/itwallet/navigation/ItwStackNavigator.tsx Registers the new intro screen in the ITW stack with hidden header.
apps/main-app/ts/features/itwallet/navigation/ItwParamsList.ts Adds route params typing for the credential-offer intro route.
apps/main-app/ts/features/itwallet/machine/credential/selectors.ts Adds selector to expose resolved credential-offer data from machine context.
apps/main-app/ts/features/itwallet/machine/credential/machine.ts Introduces offer validation/resolution states and wires resolved offer into later steps.
apps/main-app/ts/features/itwallet/machine/credential/events.ts Adds start/confirm events for credential-offer flow.
apps/main-app/ts/features/itwallet/machine/credential/context.ts Extends machine context with credentialOfferUri + resolvedCredentialOffer.
apps/main-app/ts/features/itwallet/machine/credential/actors.ts Adds actor to resolve/extract grant details from credential-offer URIs and passes offer context through.
apps/main-app/ts/features/itwallet/machine/credential/tests/machine.test.ts Adds test coverage for credential-offer machine paths and context propagation.
apps/main-app/ts/features/itwallet/common/utils/itwTypesUtils.ts Introduces a CredentialOfferResolved type used across machine + issuance utils.
apps/main-app/ts/features/itwallet/common/utils/itwCredentialIssuanceUtils.ts Allows requesting credentials using issuer/config IDs from a resolved offer.
apps/main-app/ts/features/itwallet/common/utils/tests/itwCredentialIssuanceUtils.test.ts Adds unit test coverage for offer-driven issuer/config selection in requestCredential.
apps/main-app/ts/features/barcode/utils/tests/imageDecodingTask.test.ts Updates mocked state to include ITW specs version for new barcode decoder behavior.
apps/main-app/ts/features/barcode/types/decoders.ts Adds ITW_CREDENTIAL_OFFER barcode type + decoder gated by supported specs version.
apps/main-app/ts/features/barcode/types/tests/decoders.test.ts Adds coverage for credential-offer barcode decoding across valid/invalid cases.
apps/main-app/ts/features/barcode/screens/BarcodeScanScreen.tsx Routes credential-offer scans into the ITW credential-offer intro screen.
apps/main-app/locales/it/index.json Adds i18n fallback title for credential-offer intro.
apps/main-app/ios/IO/Info.plist Registers iOS custom URL schemes for credential-offer invocation.
apps/main-app/android/app/src/main/AndroidManifest.xml Registers Android intent-filters for credential-offer custom schemes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/main-app/ts/features/itwallet/machine/credential/actors.ts
Comment thread apps/main-app/ts/features/itwallet/machine/credential/actors.ts
Comment thread apps/main-app/ts/features/itwallet/offer/utils/index.ts

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 30 out of 30 changed files in this pull request and generated 2 comments.

Comment thread apps/main-app/ts/features/itwallet/common/utils/itwCredentialIssuanceUtils.ts Outdated
Comment thread apps/main-app/ts/features/barcode/types/decoders.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@riccardosacco99 riccardosacco99 force-pushed the SIW-4149-third-channel-credential-offer branch from 14cd0c0 to a244796 Compare June 18, 2026 12:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants