From 54f28e489ca8d360150641746d78e730255fd333 Mon Sep 17 00:00:00 2001 From: skibitsky Date: Wed, 2 Sep 2026 12:49:58 +0300 Subject: [PATCH 1/3] fix(core): attribute social and email logins to the app's project id MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Social and email login opens the Reown Web Wallet in the system browser, and the Web Wallet only knows its own project id — so every login started from an app was attributed to it instead of to the app. Send the app's project id along as a projectId query parameter on that URL, and encode the query parameter values. Deep links to third-party wallets are unchanged. Co-Authored-By: Claude Opus 5 --- .changeset/social-login-project-id.md | 19 +++++++ .../__tests__/utils/CoreHelperUtil.test.ts | 54 +++++++++++++++++++ packages/core/src/utils/CoreHelperUtil.ts | 13 +++-- 3 files changed, 83 insertions(+), 3 deletions(-) create mode 100644 .changeset/social-login-project-id.md create mode 100644 packages/core/src/__tests__/utils/CoreHelperUtil.test.ts diff --git a/.changeset/social-login-project-id.md b/.changeset/social-login-project-id.md new file mode 100644 index 00000000..10683d2b --- /dev/null +++ b/.changeset/social-login-project-id.md @@ -0,0 +1,19 @@ +--- +'@reown/appkit-react-native': patch +'@reown/appkit-bitcoin-react-native': patch +'@reown/appkit-coinbase-react-native': patch +'@reown/appkit-common-react-native': patch +'@reown/appkit-core-react-native': patch +'@reown/appkit-ethers-react-native': patch +'@reown/appkit-solana-react-native': patch +'@reown/appkit-ui-react-native': patch +'@reown/appkit-wagmi-react-native': patch +--- + +fix(core): attribute social & email logins to the app's project id + +Social and email login opens the Reown Web Wallet in the system browser, and the +Web Wallet only knows its own project id — so every login started from an app was +attributed to it instead of to the app. Send the app's project id along as a +`projectId` query parameter on that URL, and encode the query parameter values. +Deep links to third-party wallets are unchanged. diff --git a/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts b/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts new file mode 100644 index 00000000..8f80b853 --- /dev/null +++ b/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts @@ -0,0 +1,54 @@ +import { CoreHelperUtil } from '../../utils/CoreHelperUtil'; +import { OptionsController } from '../../controllers/OptionsController'; + +const WEB_WALLET_URL = 'https://web-wallet.walletconnect.org'; +const WC_URI = 'wc:topic@2?relay-protocol=irn&symKey=key'; +const ENCODED_WC_URI = encodeURIComponent(WC_URI); + +describe('CoreHelperUtil', () => { + afterEach(() => { + OptionsController.setProjectId(''); + }); + + describe('formatUniversalUrl', () => { + it('should add the encoded provider and project id for social login', () => { + OptionsController.setProjectId('test-project-id'); + const { redirect, href } = CoreHelperUtil.formatUniversalUrl( + WEB_WALLET_URL, + WC_URI, + 'google' + ); + expect(redirect).toBe( + `${WEB_WALLET_URL}/wc?uri=${ENCODED_WC_URI}&provider=google&projectId=test-project-id` + ); + expect(href).toBe(`${WEB_WALLET_URL}/`); + }); + + it('should omit the project id when it is blank', () => { + OptionsController.setProjectId(' '); + const { redirect } = CoreHelperUtil.formatUniversalUrl(WEB_WALLET_URL, WC_URI, 'email'); + expect(redirect).toBe(`${WEB_WALLET_URL}/wc?uri=${ENCODED_WC_URI}&provider=email`); + }); + + it('should not add the project id without a provider', () => { + OptionsController.setProjectId('test-project-id'); + const { redirect } = CoreHelperUtil.formatUniversalUrl('https://wallet.example.com', WC_URI); + expect(redirect).toBe(`https://wallet.example.com/wc?uri=${ENCODED_WC_URI}`); + }); + }); + + describe('formatNativeUrl', () => { + it('should not add the project id to a native deep link', () => { + OptionsController.setProjectId('test-project-id'); + const { redirect, href } = CoreHelperUtil.formatNativeUrl('wallet://', WC_URI); + expect(redirect).toBe(`wallet://wc?uri=${ENCODED_WC_URI}`); + expect(href).toBe('wallet://'); + }); + + it('should not add the project id to a universal deep link', () => { + OptionsController.setProjectId('test-project-id'); + const { redirect } = CoreHelperUtil.formatNativeUrl('https://wallet.example.com', WC_URI); + expect(redirect).toBe(`https://wallet.example.com/wc?uri=${ENCODED_WC_URI}`); + }); + }); +}); diff --git a/packages/core/src/utils/CoreHelperUtil.ts b/packages/core/src/utils/CoreHelperUtil.ts index f6bdd7fb..9d721d7a 100644 --- a/packages/core/src/utils/CoreHelperUtil.ts +++ b/packages/core/src/utils/CoreHelperUtil.ts @@ -144,11 +144,18 @@ export const CoreHelperUtil = { safeAppUrl = `${safeAppUrl}/`; } const encodedWcUrl = encodeURIComponent(wcUri); + let redirect = `${safeAppUrl}wc?uri=${encodedWcUrl}`; + + if (provider) { + redirect = `${redirect}&provider=${encodeURIComponent(provider)}`; + const projectId = OptionsController.state.projectId.trim(); + if (projectId) { + redirect = `${redirect}&projectId=${encodeURIComponent(projectId)}`; + } + } return { - redirect: provider - ? `${safeAppUrl}wc?uri=${encodedWcUrl}&provider=${provider}` - : `${safeAppUrl}wc?uri=${encodedWcUrl}`, + redirect, href: safeAppUrl }; }, From bd92da007180619230b87532b3b6c61bfc6daa0b Mon Sep 17 00:00:00 2001 From: skibitsky Date: Wed, 2 Sep 2026 13:03:34 +0300 Subject: [PATCH 2/3] test(core): assert the social login url encodes special characters The previous assertions used values that encode to themselves, so they passed whether or not encoding was applied. Co-Authored-By: Claude Opus 5 --- .../src/__tests__/utils/CoreHelperUtil.test.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts b/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts index 8f80b853..9895b92f 100644 --- a/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts +++ b/packages/core/src/__tests__/utils/CoreHelperUtil.test.ts @@ -1,3 +1,5 @@ +import type { SocialProvider } from '@reown/appkit-common-react-native'; + import { CoreHelperUtil } from '../../utils/CoreHelperUtil'; import { OptionsController } from '../../controllers/OptionsController'; @@ -24,6 +26,18 @@ describe('CoreHelperUtil', () => { expect(href).toBe(`${WEB_WALLET_URL}/`); }); + it('should encode special characters in the provider and project id', () => { + OptionsController.setProjectId('proj+id=1&x'); + const { redirect } = CoreHelperUtil.formatUniversalUrl( + WEB_WALLET_URL, + WC_URI, + 'email+test' as SocialProvider + ); + expect(redirect).toBe( + `${WEB_WALLET_URL}/wc?uri=${ENCODED_WC_URI}&provider=email%2Btest&projectId=proj%2Bid%3D1%26x` + ); + }); + it('should omit the project id when it is blank', () => { OptionsController.setProjectId(' '); const { redirect } = CoreHelperUtil.formatUniversalUrl(WEB_WALLET_URL, WC_URI, 'email'); From 4e18ff90ba3a2e0a10245d44aa1904b3d5727a8d Mon Sep 17 00:00:00 2001 From: Gleb Skibitsky Date: Sat, 5 Sep 2026 12:20:46 +0300 Subject: [PATCH 3/3] Update social-login-project-id.md Co-authored-by: Ignacio Santise <25931366+ignaciosantise@users.noreply.github.com> --- .changeset/social-login-project-id.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.changeset/social-login-project-id.md b/.changeset/social-login-project-id.md index 10683d2b..1f339ff5 100644 --- a/.changeset/social-login-project-id.md +++ b/.changeset/social-login-project-id.md @@ -11,9 +11,3 @@ --- fix(core): attribute social & email logins to the app's project id - -Social and email login opens the Reown Web Wallet in the system browser, and the -Web Wallet only knows its own project id — so every login started from an app was -attributed to it instead of to the app. Send the app's project id along as a -`projectId` query parameter on that URL, and encode the query parameter values. -Deep links to third-party wallets are unchanged.