Skip to content

chore: authentication deep link login#9100

Merged
lorux0 merged 69 commits into
devfrom
chore/authentication/deep-link-login
Jul 17, 2026
Merged

chore: authentication deep link login#9100
lorux0 merged 69 commits into
devfrom
chore/authentication/deep-link-login

Conversation

@popuz

@popuz popuz commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

Pull Request Description

What does this PR change?

Replaces the legacy socket-based Dapp wallet sign-in with a new deep-link sign-in flow (AUTH_DEEPLINK_FLOW).

Main files

  • DappDeepLinkAuthenticator (new) — encapsulated deep-link login: creates a sign-in request on the auth server, opens the browser for the user to sign with their wallet, awaits the OS deep link (decentraland://?signin={identityId}) and resolves the resulting identity from the server.
  • IdentityVerificationDappDeepLinkAuthState (new) — auth screen state driving this flow (reports VerificationRequested to keep the analytics funnel intact).
  • DeepLinkSentinel / DeepLinkHandle — architectural change in deep-link consumption: the launcher bridge file is no longer deleted unconditionally. HandleDeepLink now returns whether the deep link was actually consumed, and a signin deep link is only consumed when a login flow is actively subscribed (DeeplinkSigninDispatcher.HasSubscriber). If nobody is awaiting the sign-in yet, the sentinel leaves the bridge file on disk and retries on the next poll — so a sign-in arriving before the login flow starts is not lost.

Supporting changes

  • DeeplinkSigninDispatcher (new) — single-slot signin bus between DeepLinkHandle (producer) and the authenticator (consumer).
  • CompositeWeb3Provider / BootstrapContainer wiring: login is routed through the deep-link authenticator; web3 operations keep using the socket implementation.

Removed / renamed

  • Old Dapp verification-code flow removed: IDappVerificationHandler, IdentityVerificationDappAuthState, code-verification feature-flag machinery and dead DTOs.
  • DappWeb3AuthenticatorDappWeb3EthereumApi (files renamed accordingly): it no longer implements IWeb3Authenticator — in production it only serves signature/confirmation for web3 operations (IEthereumApi). The socket login survives solely for the Archipelago dev playgrounds via the nested Default.

Follow-up (separate task)

A deeper clean-up of the legacy flow is still pending: besides the playground-only socket login code, unused assets (most likely the old verification screen prefab) need to be removed as well.

Test Instructions

Prerequisites

  • Download the build from this PR, rename the build folder to latest, and place it into %LocalAppData%\DecentralandLauncherLight — the deep-link flow only works when the client is launched from there (OS deep-link routing goes through the light launcher and its bridge file).

Test Steps

  1. Launch the client from the Launcher (it should run build from its latest folder)
  2. Pick wallet sign-in — the browser opens the signature web app.
  3. Sign in the browser with your wallet.
  4. The browser fires the decentraland:// deep link; the client picks it up and completes the login (no verification-code screen anymore).
  5. Smoke test Donations, Gifts, and other web3 operations — they use the refactored socket signature path; confirm the browser confirmation still works and the transaction completes.

Additional Testing Notes

  • Verify login cancellation (close the browser tab / cancel in client) returns to the login selection screen and a retry works.
  • Verify a second sign-in attempt after a cancelled one still receives the deep link.

Quality Checklist

  • Changes have been tested locally
  • Documentation has been updated (if required)
  • Performance impact has been considered
  • For SDK features: Test scene is included

Code Review Reference

Please review our Branch & PR Standards before submitting. It explains the automated review flow, QA/DEV approval requirements, and what each label does — especially useful for first-time contributors.

@popuz popuz self-assigned this Jun 30, 2026
@popuz popuz added the force-build Used to trigger a build on draft PR label Jun 30, 2026
@github-actions

github-actions Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

badge

New build in progress, come back later!

@popuz popuz added force-build Used to trigger a build on draft PR and removed force-build Used to trigger a build on draft PR labels Jul 1, 2026
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Warnings count reduced: 19087 => 14668

Warnings/errors in files changed by this PR (418)
File Line Rule Message
Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs 655 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs 163 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs 282 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailPoolManager.cs 49 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailPoolManager.cs 58 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailPoolManager.cs 93 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailPoolManager.cs 114 AccessToStaticMemberViaDerivedType Access to a static member of a type via a derived type
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 247 ArrangeRedundantParentheses Redundant parentheses
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 214 AssignNullToNotNullAttribute Possible 'null' assignment to non-nullable entity
Assets/DCL/Backpack/Gifting/Presenters/GiftTransfer/GiftTransferController.cs 28 CSharpWarnings::CS0108,CS0114 The keyword 'new' is required on 'State' because it hides property 'ControllerState MVC.ControllerBase<TView,TInputData>.State'
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 442 CSharpWarnings::CS0162 Code is unreachable
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 825 CSharpWarnings::CS0618 CS0618: Enum 'UnityEngine.FindObjectsSortMode' is obsolete: 'FindObjectsSortMode has been deprecated. Use the FindObjectsByType overloads that do not take a FindObjectsSortMode parameter.'
Assets/DCL/Passport/PassportController.cs 1056 CSharpWarnings::CS0618 CS0618: Method 'DCL.UI.ProfileElements.ProfilePictureView.Setup(ProfileRepositoryWrapper, in CompactInfo)' is obsolete: 'Use Bind instead.'
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 825 CSharpWarnings::CS0618 CS0618: Method 'UnityEngine.Object.FindObjectsByType(FindObjectsInactive, FindObjectsSortMode)' is obsolete: 'FindObjectsByType with FindObjectsSortMode parameter has been deprecated. Use FindObjectsByType() or FindObjectsByType(FindObjectsInactive) instead. InstanceID will be replaced in the future with EntityId and previous sort order cannot be maintained.'
Assets/DCL/Backpack/BackpackGridController.cs 239 CSharpWarnings::CS8600 Converting null literal or possible null value into non-nullable type
Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs 459 CSharpWarnings::CS8600 Converting null literal or possible null value into non-nullable type
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 213 CSharpWarnings::CS8600 Converting null literal or possible null value into non-nullable type
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 899 CSharpWarnings::CS8600 Converting null literal or possible null value into non-nullable type
Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/UI/MinimumSpecsScreenController.cs 35 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/ApplicationGuards/ApplicationMinimumSpecsGuard/UI/MinimumSpecsScreenController.cs 62 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/AuthenticationScreenFlow/AuthenticationScreenController.cs 153 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Backpack/BackpackGridController.cs 223 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Backpack/BackpackGridController.cs 224 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Backpack/BackpackGridController.cs 225 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Backpack/Gifting/Presenters/GiftTransfer/GiftTransferController.cs 107 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs 31 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs 44 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs 71 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs 84 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/ExternalUrlPrompt/ExternalUrlPromptController.cs 93 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/InWorldCamera/PhotoDetail/EquippedWearableController.cs 53 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs 109 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/InWorldCamera/PhotoDetail/PhotoDetailController.cs 305 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Infrastructure/Global/Dynamic/BootstrapContainer.cs 122 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Infrastructure/Global/Dynamic/BootstrapContainer.cs 141 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Infrastructure/Global/Dynamic/MainSceneLoader.cs 484 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/Navmap/PlaceInfoPanelController.cs 187 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 51 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 81 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 117 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 125 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 133 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 141 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/NftPrompt/NftPromptController.cs 154 CSharpWarnings::CS8602 Dereference of a possibly null reference
Assets/DCL/InWorldCamera/CameraReelGallery/CameraReelGalleryController.cs 472 CSharpWarnings::CS8603 Possible null reference return
Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs 269 CSharpWarnings::CS8604 Possible null reference argument for parameter 'communityId' in 'DCL.Communities.CommunitiesDataProvider.CommunitiesDataProvider.BanUserFromCommunityAsync'
Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs 529 CSharpWarnings::CS8604 Possible null reference argument for parameter 'communityId' in 'DCL.Communities.CommunitiesDataProvider.CommunitiesDataProvider.GetBannedCommunityMembersAsync'
Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs 531 CSharpWarnings::CS8604 Possible null reference argument for parameter 'communityId' in 'DCL.Communities.CommunitiesDataProvider.CommunitiesDataProvider.GetCommunityInviteRequestAsync'
Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs 533 CSharpWarnings::CS8604 Possible null reference argument for parameter 'communityId' in 'DCL.Communities.CommunitiesDataProvider.CommunitiesDataProvider.GetCommunityInviteRequestAsync'
Assets/DCL/Communities/CommunitiesCard/Members/MembersListController.cs 593 CSharpWarnings::CS8604 Possible null reference argument for parameter 'communityId' in 'DCL.Communities.CommunitiesDataProvider.CommunitiesDataProvider.GetCommunityInviteRequestAsync'

…and 368 more (see the csharp-lint-reports artifact).

@popuz popuz changed the title Chore/authentication/deep link login Chore: authentication deep link login Jul 2, 2026
Comment thread Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs Outdated

@Ludmilafantaniella Ludmilafantaniella 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.

Tested on Windows and Mac. ✅

  • Deep-link login flow works end-to-end: browser redirects back to the running Explorer without opening a second Launcher window ✅
  • Login with Metamask and Google both complete correctly ✅
  • Login cancellation returns to the login selection screen and retry works ✅
  • Second sign-in after cancellation still receives the deep link ✅
  • Web3 operations (Donations, Gifts) still work correctly after refactored socket signature path ✅
  • Multi-instance flow (--multi-instance) working on both platforms ✅
  • Gifts working on both platforms ✅
  • Found a bug during testing: a second Launcher instance was opening when switching accounts instead of reusing the existing one — fixed by Nico and verified on both platforms ✅

LGTM 🚀

Windows Evidence:

9100-evi.mp4

Mac Evidence:

9100-evi.mac.mp4

DONATIONS EVIDENCE:

donations.mp4

GIFT EVIDENCE:

gift.mp4

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Signed-off-by: Nicolas Lorusso <56365551+lorux0@users.noreply.github.com>
@claude

This comment has been minimized.

Comment thread Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs Outdated
Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
Signed-off-by: Nicolas Lorusso <56365551+lorux0@users.noreply.github.com>
@claude

claude Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Claude finished @lorux0's task in 2m 6s —— View job


PR Review: Authentication Deep Link Login (re-review after latest commits)

  • Step 1: Load context (CLAUDE.md, docs/README.md, diff)
  • Step 2: Root-cause check
  • Step 3: Design & integration review
  • Step 4: Member audit
  • Step 5: Line-level review
  • Step 6: Complexity assessment
  • Step 7: QA assessment
  • Step 8: Non-blocking warnings
  • Step 9: Final verdict

New commit since last review

Commit Summary
4df5a244 Removes the leftover truncated comment on DeepLinkSentinel.cs line 16 that narrated external-actor behavior (CLAUDE.md §11)

Step 2 — Root-cause check ✅

4df5a244 deleted the partial line // A signin deep link is not consumed unless this instance is the one logging in, so concurrent idle that was the sole remaining blocking issue from the previous review. The compliant replacement (// Maximum time a deferred signin bridge file is retained on disk; without this cap it would be re-read on every check-in forever.) is now the only comment above DEFERRED_SIGNIN_LIFETIME.


Step 3 — Design & integration ✅

Architecture is unchanged. DappDeepLinkAuthenticator.LoginAsync clears deeplinkSigninIdentityId before subscribing (stale-identity retry bug fixed). The finally block clears both loginAwaitingSigninRequestId and deeplinkSigninIdentityId on success, timeout, and cancellation. DeepLinkHandleImplementation correctly gates consumption on the authRequestId match. No new design concerns.


Step 4 — Member audit ✅

No new public members introduced by 4df5a244. All public members previously reviewed remain correct.


Step 5 — Line-level review ✅

All prior blocking issues confirmed resolved:

Issue Status
Compile error (duplicate var authRequestId) ✅ fixed by 8493198d
Stale deeplinkSigninIdentityId retry bug ✅ cleared at LoginAsync start
TimeoutException not caught in IdentityVerificationDappDeepLinkAuthState ✅ explicit catch (TimeoutException) present
§11 comment violations in DappDeepLinkAuthenticator.cs ✅ resolved
§11 comment violations in AppArgsFlags.cs, BootstrapContainer.cs, DeepLinkHandleImplementation.cs ✅ resolved
DeepLinkSentinel.cs line 16 leftover partial comment (last review's sole blocker) ✅ fixed by 4df5a244

No new blocking issues found.


REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Modifies auth, web3 signing, OS deep-link routing, and multi-instance coordination for the security-sensitive signin flow.
QA_REQUIRED: YES


💰 Review cost: $0.56 · claude-sonnet-4-6 · 17 turns

@decentraland-bot decentraland-bot 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.

Automated review

STEP 1 — Context loaded: CLAUDE.md, docs/README.md, docs/web3-authentication.md, docs/app-arguments.md, docs/async-programming.md, docs/mvc.md, the PR diff and changed files.

STEP 2 — Root-cause check: FAIL. The PR addresses the browser → Launcher → Explorer handoff, but introduces shared mutable signin state and logging of raw auth deeplinks. Those are root-cause issues in the new auth lifecycle, not just local style concerns.

STEP 3 — Design & integration: FAIL. New long-lived auth state is owned through BootstrapContainer.DeeplinkSigninIdentityId / DeeplinkLoginAwaitingSigninRequestId; the existing owners are the Web3 auth provider (BootstrapContainer.CreateWeb3Dependencies, CompositeWeb3Provider, DappDeepLinkAuthenticator) and runtime deep-link routing (DeepLinkHandle / DeepLinkSentinel from DynamicWorldContainer). The new flow should be serialized and auth-owned rather than writable shared bootstrap state.

STEP 4 — Member audit: LoginAsync and Dispose implement IWeb3Authenticator; DTO fields are consumed only inside FetchIdentityByIdAsync; DeepLinkHandle.HandleDeepLink is consumed by the sentinel. No public API consumer break found beyond the intentional authenticator replacement.

STEP 5 — Findings:

  • P1: DappDeepLinkAuthenticator.LoginAsync is not serialized; concurrent login attempts share and clear deeplinkSigninIdentityId / loginAwaitingSigninRequestId.
  • P1: Runtime deeplink logs print raw signin / authRequestId values. Application argument logging also prints parsed app args, so a process launched with signin would expose the same auth material.
  • P2: identityId from the deeplink is interpolated into the auth API path without format validation or path-segment encoding.

STEP 6 — Complexity assessment: COMPLEX.

STEP 7 — QA assessment: YES.

STEP 8 — Non-blocking warnings: none.

Security review: security issues found (raw signin/authRequestId logging and unvalidated auth path input). CI status: all reported checks are passing.

REVIEW_RESULT: FAIL ❌
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Changes runtime authentication, deep-link routing, browser opening, app arguments, and Web3 identity retrieval.
QA_REQUIRED: YES


Reviewed by Jarvis 🤖 · Requested by Ignacio Mazzara (<@U9ETM8CJH>) via Slack

Comment thread Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs
Comment thread Explorer/Assets/DCL/RuntimeDeepLink/DeepLinkSentinel.cs Outdated

@decentraland-bot decentraland-bot 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.

PR Review — chore: authentication deep link login

STEP 2 — Root-cause check

This PR replaces the legacy socket-based Dapp wallet verification-code sign-in with a browser deep-link flow (AUTH_DEEPLINK_FLOW). The change addresses the root cause directly — the old socket + verification-code mechanism is being replaced by a fundamentally different (and simpler) protocol where the browser fires an OS deep link (decentraland://?signin={identityId}) that the client picks up. PASS.

STEP 3 — Design & integration

Responsibility split: The diff cleanly separates login (now DappDeepLinkAuthenticator) from Ethereum API operations (now DappWeb3EthereumApi, renamed from DappWeb3Authenticator). CompositeWeb3Provider delegates login to DappDeepLinkAuthenticator and eth operations to DappWeb3EthereumApi. The legacy socket login survives only inside the Default nested class for Archipelago dev playgrounds. This is the right decomposition.

Owner search — DappDeepLinkAuthenticator:

  • Created in BootstrapContainer.CreateWeb3Dependencies (composition root).
  • Owned by CompositeWeb3Provider which calls Dispose() in its own Dispose().
  • No existing owner can host this logic — it is a new authentication mechanism with its own lifecycle.
  • PASS — correctly placed.

Owner search — ReactiveProperty<string?> coordination (DeeplinkSigninIdentityId, DeeplinkLoginAwaitingSigninRequestId):

  • Live on BootstrapContainer, shared between DappDeepLinkAuthenticator (consumer/writer of the request ID, reader of the identity ID) and DeepLinkHandle (reader of the request ID, writer of the identity ID).
  • These cross-cut the deep-link subsystem (polling layer) and the web3 auth subsystem. BootstrapContainer is the common ancestor that wires both — correct placement.
  • PASS.

IWebBrowser interface removal: The IWebBrowser interface had a single implementation (UnityAppWebBrowser) and no test stubs. Per CLAUDE.md §11 ("Interfaces with one implementation and no test coverage — delete the interface"), removing it is correct. The rename OpenUrlOpenUrlMainThreadOnly clarifies the threading contract. PASS.

IDappVerificationHandler removal: The entire code-verification flow is deleted. The interface, the VerificationRequired event, the ICodeVerificationFeatureFlag, and the WaitForCodeVerificationAsync method are all removed. The IdentityVerificationDappAuthState is renamed to IdentityVerificationDappDeepLinkAuthState and no longer drives a verification screen — it sets AuthStatus.VerificationRequested immediately for analytics continuity. PASS.

Teardown / consumption trace:

  • DappDeepLinkAuthenticator.WaitForSigninAsync: deeplinkSigninIdentityId subscription via UseCurrentValueAndSubscribeToUpdate → properly disposed via using var subscription. ✓
  • loginAwaitingSigninRequestId → cleared in finally block of WaitForSigninAsync. ✓
  • deeplinkSigninIdentityId → cleared in finally block of WaitForSigninAsync AND at the start of LoginAsync. ✓
  • DappDeepLinkAuthenticator.loginMutex (DCLSemaphoreSlim) → NOT disposed in Dispose(). See P2 finding below.
  • DeepLinkSentinel.TryDeleteBridgeFile → wrapped in try/catch, logs error on failure. ✓
  • SatelliteController.OnClickedGenesisCityLink subscription (view.OnClickedGenesisCityLink += ...) → no unsubscription, but this is pre-existing and unchanged by this PR.

STEP 4 — Member audit

New/changed public member Consumers Verdict
DappDeepLinkAuthenticator.LoginAsync CompositeWeb3Provider.currentAuthenticator (1) Interface implementation — OK
DappDeepLinkAuthenticator.Dispose() CompositeWeb3Provider.Dispose() (1) Empty body — see P2 finding
DappWeb3EthereumApi.DisconnectFromAuthApiAsync (was private) CompositeWeb3Provider.LogoutAsync (1) Correctly promoted to public for logout path
ICompositeWeb3Provider.LogoutAsync Auth flow (1) Moved from IWeb3Authenticator — only CompositeWeb3Provider has meaningful logout
BootstrapContainer.DeeplinkSigninIdentityId CreateWeb3Dependencies, DynamicWorldContainer (2) Coordination property — OK
BootstrapContainer.DeeplinkLoginAwaitingSigninRequestId CreateWeb3Dependencies, DynamicWorldContainer (2) Coordination property — OK
DeepLinkHandleResult enum DeepLinkSentinel, DeepLinkHandle, DeepLinkHandleImplementation (3) Replaces Result — cleaner semantics

STEP 5 — Line-level findings

See inline comments below.

Security review

  • Secrets & credentials: No hardcoded secrets. Auth API URLs from IDecentralandUrlsSource. ✓
  • Input validation: Deep link parameters parsed via DeepLink.FromJson with error handling. New regex in ProcessDeepLinkParameters strips host segments safely — tested with 3 unit tests. ✓
  • Auth flow: Client-generated GUID request IDs for correlation (not security — server validates identity). authRequestId matching prevents stale/foreign deep links from completing a login. ✓
  • IP validation: Server-side 403 for IP mismatch — client handles with clear DeeplinkSigninRetrievalException. ✓
  • Ephemeral key handling: Private key fetched from auth server over HTTPS, used only in memory for EthECKey construction. Ephemeral key validated against auth chain before use. ✓
  • Bridge file: Pre-existing disk-based mechanism. File is read/deleted with proper error handling. DEFERRED_SIGNIN_LIFETIME (300s) prevents indefinite retention. ✓
  • #if UNITY_EDITOR guard: &bridgeOnly flag prevents standalone build from stealing signin during editor testing. ✓

No security issues found.

STEP 6 — Complexity

COMPLEX — modifies auth/web3 signing, dependency injection wiring (BootstrapContainer, CompositeWeb3Provider), deep link handling, authentication state machine, and removes/renames interfaces used across assemblies.

STEP 7 — QA assessment

QA_REQUIRED: YES — changes the user-facing wallet sign-in flow, deep link handling, and web3 operation paths (donations, gifts).

STEP 8 — Non-blocking warnings

None. Main scene not modified.

STEP 9 — Verdict

REVIEW_RESULT: PASS ✅
COMPLEXITY: COMPLEX
COMPLEXITY_REASON: Modifies auth/web3 signing flow, dependency injection wiring (BootstrapContainer, CompositeWeb3Provider), deep link handling architecture, and authentication state machine
QA_REQUIRED: YES


Reviewed by Jarvis 🤖 · Requested by mikhail-dcl via GitHub

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Jarvis reviewed this PR and found no blocking issues, but assessed it as complex — human DEV review is still required before merging.

lorux0 and others added 3 commits July 16, 2026 14:10
…appDeepLinkAuthenticator.cs

Co-authored-by: Muna <44584806+decentraland-bot@users.noreply.github.com>
Signed-off-by: Nicolas Lorusso <56365551+lorux0@users.noreply.github.com>
# Conflicts:
#	Explorer/Assets/DCL/Passport/Modules/Creations/CreationsDetailsPassportModuleController.cs
#	Explorer/Assets/DCL/Passport/Modules/EquippedItemsPassportModuleController.cs
@lorux0
lorux0 enabled auto-merge (squash) July 17, 2026 14:40
@lorux0 lorux0 added no-warning-ratchet Prevent CI linting checks force-build Used to trigger a build on draft PR and removed no-warning-ratchet Prevent CI linting checks force-build Used to trigger a build on draft PR labels Jul 17, 2026
@lorux0
lorux0 merged commit a920676 into dev Jul 17, 2026
52 of 58 checks passed
@lorux0
lorux0 deleted the chore/authentication/deep-link-login branch July 17, 2026 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

force-build Used to trigger a build on draft PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants