From 5f9a57ead5fbffae4eb278819b4c19b839a29091 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 16 Mar 2026 16:03:25 +0700 Subject: [PATCH 1/3] Strip URL scheme from login domain Add stripUrlScheme utility and use it to normalize domains by removing http/https schemes. Apply this to createLoginMessage, generateLoginPayload, and verifyLoginPayload so payload.domain is stored and compared without a URL scheme (per EIP-4361). Update tests to cover scheme stripping and backward compatibility when verifying payloads. Also adjust biome.json formatter line ending to CRLF. --- .changeset/hot-donkeys-itch.md | 5 +++ .../auth/core/create-login-message.test.ts | 35 +++++++++++++++- .../src/auth/core/create-login-message.ts | 12 +++++- .../auth/core/generate-login-payload.test.ts | 25 +++++++++++ .../src/auth/core/generate-login-payload.ts | 3 +- .../auth/core/verify-login-payload.test.ts | 42 +++++++++++++++++++ .../src/auth/core/verify-login-payload.ts | 5 ++- 7 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 .changeset/hot-donkeys-itch.md diff --git a/.changeset/hot-donkeys-itch.md b/.changeset/hot-donkeys-itch.md new file mode 100644 index 00000000000..b48a347e1b5 --- /dev/null +++ b/.changeset/hot-donkeys-itch.md @@ -0,0 +1,5 @@ +--- +"thirdweb": minor +--- + +Stripe URL scheme from SIWE domain across all touchpoints diff --git a/packages/thirdweb/src/auth/core/create-login-message.test.ts b/packages/thirdweb/src/auth/core/create-login-message.test.ts index 306557caeb1..5d3addebc4f 100644 --- a/packages/thirdweb/src/auth/core/create-login-message.test.ts +++ b/packages/thirdweb/src/auth/core/create-login-message.test.ts @@ -1,5 +1,5 @@ import { afterAll, beforeAll, describe, expect, test, vi } from "vitest"; -import { createLoginMessage } from "./create-login-message.js"; +import { createLoginMessage, stripUrlScheme } from "./create-login-message.js"; describe("createLoginMessage", () => { beforeAll(() => { @@ -72,4 +72,37 @@ describe("createLoginMessage", () => { Not Before: 1634567800" `); }); + + test("should strip URL scheme from domain in the message", () => { + const payload = { + address: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", + chain_id: "1", + domain: "https://example.com", + expiration_time: "1634567990", + invalid_before: "1634567800", + issued_at: "1634567890", + nonce: "123456", + statement: "This is a statement", + uri: "https://example.com", + version: "1.0", + }; + + const result = createLoginMessage(payload); + expect(result).toContain( + "example.com wants you to sign in with your Ethereum account:", + ); + expect(result).not.toContain("https://example.com wants you to sign in"); + }); + + test("stripUrlScheme should strip https scheme", () => { + expect(stripUrlScheme("https://example.com")).toBe("example.com"); + }); + + test("stripUrlScheme should strip http scheme", () => { + expect(stripUrlScheme("http://example.com")).toBe("example.com"); + }); + + test("stripUrlScheme should leave bare domains unchanged", () => { + expect(stripUrlScheme("example.com")).toBe("example.com"); + }); }); diff --git a/packages/thirdweb/src/auth/core/create-login-message.ts b/packages/thirdweb/src/auth/core/create-login-message.ts index 614fd26c089..ab3f079f847 100644 --- a/packages/thirdweb/src/auth/core/create-login-message.ts +++ b/packages/thirdweb/src/auth/core/create-login-message.ts @@ -1,5 +1,14 @@ import type { LoginPayload } from "./types.js"; +/** + * Strips the URL scheme (e.g. "https://") from a domain string. + * Per EIP-4361, the domain field should be an RFC 3986 authority (host without scheme). + * @internal + */ +export function stripUrlScheme(domain: string): string { + return domain.replace(/^https?:\/\//, ""); +} + /** * Create an EIP-4361 & CAIP-122 compliant message to sign based on the login payload * @param payload - The login payload containing the necessary information. @@ -8,7 +17,8 @@ import type { LoginPayload } from "./types.js"; */ export function createLoginMessage(payload: LoginPayload): string { const typeField = "Ethereum"; - const header = `${payload.domain} wants you to sign in with your ${typeField} account:`; + const domain = stripUrlScheme(payload.domain); + const header = `${domain} wants you to sign in with your ${typeField} account:`; let prefix = [header, payload.address].join("\n"); prefix = [prefix, payload.statement].join("\n\n"); if (payload.statement) { diff --git a/packages/thirdweb/src/auth/core/generate-login-payload.test.ts b/packages/thirdweb/src/auth/core/generate-login-payload.test.ts index a3e98d48475..7a5209eaf43 100644 --- a/packages/thirdweb/src/auth/core/generate-login-payload.test.ts +++ b/packages/thirdweb/src/auth/core/generate-login-payload.test.ts @@ -94,4 +94,29 @@ describe("generateLoginPayload", () => { } `); }); + + test("should strip URL scheme from domain", async () => { + const options = { + client: TEST_CLIENT, + domain: "https://example.com", + login: { + nonce: { + generate() { + return "20cd4ddb-6857-4d36-8e44-9f6e026b8de9"; + }, + validate(uuid: string) { + return uuid === "20cd4ddb-6857-4d36-8e44-9f6e026b8de9"; + }, + }, + }, + }; + + const generatePayload = generateLoginPayload(options); + const result = await generatePayload({ + address: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", + chainId: 1, + }); + + expect(result.domain).toBe("example.com"); + }); }); diff --git a/packages/thirdweb/src/auth/core/generate-login-payload.ts b/packages/thirdweb/src/auth/core/generate-login-payload.ts index 5debd48a04a..7f7fa38c040 100644 --- a/packages/thirdweb/src/auth/core/generate-login-payload.ts +++ b/packages/thirdweb/src/auth/core/generate-login-payload.ts @@ -3,6 +3,7 @@ import { DEFAULT_LOGIN_STATEMENT, DEFAULT_LOGIN_VERSION, } from "./constants.js"; +import { stripUrlScheme } from "./create-login-message.js"; import type { AuthOptions, LoginPayload } from "./types.js"; /** @@ -31,7 +32,7 @@ export function generateLoginPayload(options: AuthOptions) { return { address, chain_id: chainId ? chainId.toString() : undefined, - domain: options.domain, + domain: stripUrlScheme(options.domain), expiration_time: new Date(now + expirationTime).toISOString(), invalid_before: new Date(now - expirationTime).toISOString(), issued_at: new Date(now).toISOString(), diff --git a/packages/thirdweb/src/auth/core/verify-login-payload.test.ts b/packages/thirdweb/src/auth/core/verify-login-payload.test.ts index 429f0fd05a3..ba3f5feb21b 100644 --- a/packages/thirdweb/src/auth/core/verify-login-payload.test.ts +++ b/packages/thirdweb/src/auth/core/verify-login-payload.test.ts @@ -145,4 +145,46 @@ describe("verifyLoginPayload", () => { expect(verificationResult.valid).toBe(false); }); + + test("should work when domain has URL scheme (backward compat)", async () => { + const options = { + client: TEST_CLIENT, + domain: "https://example.com", + login: { + nonce: { + generate() { + return "20cd4ddb-6857-4d36-8e44-9f6e026b8de9"; + }, + validate(uuid: string) { + return uuid === "20cd4ddb-6857-4d36-8e44-9f6e026b8de9"; + }, + }, + payloadExpirationTimeSeconds: 3600, + statement: "This is a statement", + }, + }; + + const generatePayload = generateLoginPayload(options); + const payloadToSign = await generatePayload({ + address: TEST_ACCOUNT_A.address, + }); + + // sign the payload + const signatureResult = await signLoginPayload({ + account: TEST_ACCOUNT_A, + payload: payloadToSign, + }); + + // verify the payload + const verifyPayload = verifyLoginPayload(options); + + const verificationResult = await verifyPayload(signatureResult); + + expect(verificationResult.valid).toBe(true); + if (verificationResult.valid) { + expect(verificationResult.payload.address).toBe(TEST_ACCOUNT_A.address); + // domain in payload should have scheme stripped + expect(verificationResult.payload.domain).toBe("example.com"); + } + }); }); diff --git a/packages/thirdweb/src/auth/core/verify-login-payload.ts b/packages/thirdweb/src/auth/core/verify-login-payload.ts index 6eaac5b5880..da542f18145 100644 --- a/packages/thirdweb/src/auth/core/verify-login-payload.ts +++ b/packages/thirdweb/src/auth/core/verify-login-payload.ts @@ -2,7 +2,7 @@ import { trackLogin } from "../../analytics/track/siwe.js"; import { getCachedChain } from "../../chains/utils.js"; import { verifySignature } from "../verify-signature.js"; import { DEFAULT_LOGIN_STATEMENT, DEFAULT_LOGIN_VERSION } from "./constants.js"; -import { createLoginMessage } from "./create-login-message.js"; +import { createLoginMessage, stripUrlScheme } from "./create-login-message.js"; import type { AuthOptions, LoginPayload } from "./types.js"; /** @@ -48,7 +48,8 @@ export function verifyLoginPayload(options: AuthOptions) { signature, }: VerifyLoginPayloadParams): Promise => { // check that the intended domain matches the domain of the payload - if (payload.domain !== options.domain) { + // normalize both sides by stripping URL scheme for backward compatibility + if (stripUrlScheme(payload.domain) !== stripUrlScheme(options.domain)) { return { error: `Expected domain '${options.domain}' does not match domain on payload '${payload.domain}'`, valid: false, From 5535038e77edad58dfc85fecda9cbc3ea55fcff6 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 16 Mar 2026 16:36:14 +0700 Subject: [PATCH 2/3] Extract stripUrlScheme and normalize SIWE domain Move stripUrlScheme into its own module and add comprehensive tests. createLoginMessage no longer strips the scheme (uses payload.domain as-is), generate-login-payload imports the new util, and verify-login-payload now normalizes the domain before building the expected message for EIP-4361 compliance. verify logic also falls back to the legacy (scheme-included) message for backward compatibility with signatures from older SDKs. Updated/added tests to cover stripUrlScheme behavior and legacy payload verification. --- .changeset/hot-donkeys-itch.md | 3 +- .../auth/core/create-login-message.test.ts | 35 +------------ .../src/auth/core/create-login-message.ts | 12 +---- .../src/auth/core/generate-login-payload.ts | 2 +- .../src/auth/core/strip-url-scheme.test.ts | 34 ++++++++++++ .../src/auth/core/strip-url-scheme.ts | 8 +++ .../auth/core/verify-login-payload.test.ts | 52 +++++++++++++++++++ .../src/auth/core/verify-login-payload.ts | 30 +++++++++-- 8 files changed, 124 insertions(+), 52 deletions(-) create mode 100644 packages/thirdweb/src/auth/core/strip-url-scheme.test.ts create mode 100644 packages/thirdweb/src/auth/core/strip-url-scheme.ts diff --git a/.changeset/hot-donkeys-itch.md b/.changeset/hot-donkeys-itch.md index b48a347e1b5..139c0866a86 100644 --- a/.changeset/hot-donkeys-itch.md +++ b/.changeset/hot-donkeys-itch.md @@ -2,4 +2,5 @@ "thirdweb": minor --- -Stripe URL scheme from SIWE domain across all touchpoints +Strip URL scheme from SIWE message domain field for EIP-4361 compliance + diff --git a/packages/thirdweb/src/auth/core/create-login-message.test.ts b/packages/thirdweb/src/auth/core/create-login-message.test.ts index 5d3addebc4f..306557caeb1 100644 --- a/packages/thirdweb/src/auth/core/create-login-message.test.ts +++ b/packages/thirdweb/src/auth/core/create-login-message.test.ts @@ -1,5 +1,5 @@ import { afterAll, beforeAll, describe, expect, test, vi } from "vitest"; -import { createLoginMessage, stripUrlScheme } from "./create-login-message.js"; +import { createLoginMessage } from "./create-login-message.js"; describe("createLoginMessage", () => { beforeAll(() => { @@ -72,37 +72,4 @@ describe("createLoginMessage", () => { Not Before: 1634567800" `); }); - - test("should strip URL scheme from domain in the message", () => { - const payload = { - address: "0xAb5801a7D398351b8bE11C439e05C5B3259aeC9B", - chain_id: "1", - domain: "https://example.com", - expiration_time: "1634567990", - invalid_before: "1634567800", - issued_at: "1634567890", - nonce: "123456", - statement: "This is a statement", - uri: "https://example.com", - version: "1.0", - }; - - const result = createLoginMessage(payload); - expect(result).toContain( - "example.com wants you to sign in with your Ethereum account:", - ); - expect(result).not.toContain("https://example.com wants you to sign in"); - }); - - test("stripUrlScheme should strip https scheme", () => { - expect(stripUrlScheme("https://example.com")).toBe("example.com"); - }); - - test("stripUrlScheme should strip http scheme", () => { - expect(stripUrlScheme("http://example.com")).toBe("example.com"); - }); - - test("stripUrlScheme should leave bare domains unchanged", () => { - expect(stripUrlScheme("example.com")).toBe("example.com"); - }); }); diff --git a/packages/thirdweb/src/auth/core/create-login-message.ts b/packages/thirdweb/src/auth/core/create-login-message.ts index ab3f079f847..614fd26c089 100644 --- a/packages/thirdweb/src/auth/core/create-login-message.ts +++ b/packages/thirdweb/src/auth/core/create-login-message.ts @@ -1,14 +1,5 @@ import type { LoginPayload } from "./types.js"; -/** - * Strips the URL scheme (e.g. "https://") from a domain string. - * Per EIP-4361, the domain field should be an RFC 3986 authority (host without scheme). - * @internal - */ -export function stripUrlScheme(domain: string): string { - return domain.replace(/^https?:\/\//, ""); -} - /** * Create an EIP-4361 & CAIP-122 compliant message to sign based on the login payload * @param payload - The login payload containing the necessary information. @@ -17,8 +8,7 @@ export function stripUrlScheme(domain: string): string { */ export function createLoginMessage(payload: LoginPayload): string { const typeField = "Ethereum"; - const domain = stripUrlScheme(payload.domain); - const header = `${domain} wants you to sign in with your ${typeField} account:`; + const header = `${payload.domain} wants you to sign in with your ${typeField} account:`; let prefix = [header, payload.address].join("\n"); prefix = [prefix, payload.statement].join("\n\n"); if (payload.statement) { diff --git a/packages/thirdweb/src/auth/core/generate-login-payload.ts b/packages/thirdweb/src/auth/core/generate-login-payload.ts index 7f7fa38c040..eebf2d3a2c4 100644 --- a/packages/thirdweb/src/auth/core/generate-login-payload.ts +++ b/packages/thirdweb/src/auth/core/generate-login-payload.ts @@ -3,7 +3,7 @@ import { DEFAULT_LOGIN_STATEMENT, DEFAULT_LOGIN_VERSION, } from "./constants.js"; -import { stripUrlScheme } from "./create-login-message.js"; +import { stripUrlScheme } from "./strip-url-scheme.js"; import type { AuthOptions, LoginPayload } from "./types.js"; /** diff --git a/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts b/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts new file mode 100644 index 00000000000..f6056d10680 --- /dev/null +++ b/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, test } from "vitest"; +import { stripUrlScheme } from "./strip-url-scheme.js"; + +describe("stripUrlScheme", () => { + test("should strip https scheme", () => { + expect(stripUrlScheme("https://example.com")).toBe("example.com"); + }); + + test("should strip http scheme", () => { + expect(stripUrlScheme("http://example.com")).toBe("example.com"); + }); + + test("should leave bare domains unchanged", () => { + expect(stripUrlScheme("example.com")).toBe("example.com"); + }); + + test("should strip trailing slash", () => { + expect(stripUrlScheme("https://example.com/")).toBe("example.com"); + }); + + test("should strip trailing path", () => { + expect(stripUrlScheme("https://example.com/path/to/resource")).toBe( + "example.com", + ); + }); + + test("should preserve port", () => { + expect(stripUrlScheme("https://localhost:3000")).toBe("localhost:3000"); + }); + + test("should strip trailing slash from bare domain", () => { + expect(stripUrlScheme("example.com/")).toBe("example.com"); + }); +}); diff --git a/packages/thirdweb/src/auth/core/strip-url-scheme.ts b/packages/thirdweb/src/auth/core/strip-url-scheme.ts new file mode 100644 index 00000000000..15f32ea9400 --- /dev/null +++ b/packages/thirdweb/src/auth/core/strip-url-scheme.ts @@ -0,0 +1,8 @@ +/** + * Strips the URL scheme (e.g. "https://") and any trailing path/slash from a domain string. + * Per EIP-4361, the domain field should be an RFC 3986 authority (host without scheme). + * @internal + */ +export function stripUrlScheme(domain: string): string { + return domain.replace(/^https?:\/\//, "").replace(/\/.*$/, ""); +} diff --git a/packages/thirdweb/src/auth/core/verify-login-payload.test.ts b/packages/thirdweb/src/auth/core/verify-login-payload.test.ts index ba3f5feb21b..f4fe1bb4e06 100644 --- a/packages/thirdweb/src/auth/core/verify-login-payload.test.ts +++ b/packages/thirdweb/src/auth/core/verify-login-payload.test.ts @@ -4,6 +4,7 @@ import { TEST_ACCOUNT_A, TEST_ACCOUNT_B, } from "../../../test/src/test-wallets.js"; +import { createLoginMessage } from "./create-login-message.js"; import { generateLoginPayload } from "./generate-login-payload.js"; import { signLoginPayload } from "./sign-login-payload.js"; import { verifyLoginPayload } from "./verify-login-payload.js"; @@ -187,4 +188,55 @@ describe("verifyLoginPayload", () => { expect(verificationResult.payload.domain).toBe("example.com"); } }); + + test("should verify legacy payloads with scheme in domain", async () => { + // Simulate a legacy payload where the old SDK did NOT strip the scheme + const legacyPayload = { + address: TEST_ACCOUNT_A.address, + domain: "https://example.com", + expiration_time: new Date(3600000).toISOString(), + invalid_before: new Date(-3600000).toISOString(), + issued_at: new Date(0).toISOString(), + nonce: "20cd4ddb-6857-4d36-8e44-9f6e026b8de9", + statement: "This is a statement", + uri: "https://example.com", + version: "1", + }; + + // createLoginMessage now uses domain as-is, so the signed message + // will contain the scheme — matching what the old SDK would have produced + const legacyMessage = createLoginMessage(legacyPayload); + expect(legacyMessage).toContain("https://example.com wants you to sign in"); + + const signature = await TEST_ACCOUNT_A.signMessage({ + message: legacyMessage, + }); + + // Verify with options whose domain also has scheme + const verifyPayload = verifyLoginPayload({ + client: TEST_CLIENT, + domain: "https://example.com", + login: { + nonce: { + generate() { + return "20cd4ddb-6857-4d36-8e44-9f6e026b8de9"; + }, + validate(uuid: string) { + return uuid === "20cd4ddb-6857-4d36-8e44-9f6e026b8de9"; + }, + }, + payloadExpirationTimeSeconds: 3600, + statement: "This is a statement", + uri: "https://example.com", + version: "1", + }, + }); + + const verificationResult = await verifyPayload({ + payload: legacyPayload, + signature, + }); + + expect(verificationResult.valid).toBe(true); + }); }); diff --git a/packages/thirdweb/src/auth/core/verify-login-payload.ts b/packages/thirdweb/src/auth/core/verify-login-payload.ts index da542f18145..609fbc2fd28 100644 --- a/packages/thirdweb/src/auth/core/verify-login-payload.ts +++ b/packages/thirdweb/src/auth/core/verify-login-payload.ts @@ -2,7 +2,8 @@ import { trackLogin } from "../../analytics/track/siwe.js"; import { getCachedChain } from "../../chains/utils.js"; import { verifySignature } from "../verify-signature.js"; import { DEFAULT_LOGIN_STATEMENT, DEFAULT_LOGIN_VERSION } from "./constants.js"; -import { createLoginMessage, stripUrlScheme } from "./create-login-message.js"; +import { createLoginMessage } from "./create-login-message.js"; +import { stripUrlScheme } from "./strip-url-scheme.js"; import type { AuthOptions, LoginPayload } from "./types.js"; /** @@ -129,19 +130,38 @@ export function verifyLoginPayload(options: AuthOptions) { } } - // this is the message the user should have signed (resulting in the singature passd) - const computedMessage = createLoginMessage(payload); + // Build message with normalized (scheme-stripped) domain for EIP-4361 compliance + const normalizedDomain = stripUrlScheme(payload.domain); + const normalizedPayload = + normalizedDomain !== payload.domain + ? { ...payload, domain: normalizedDomain } + : payload; + const computedMessage = createLoginMessage(normalizedPayload); - const signatureIsValid = await verifySignature({ + const verifyOpts = { address: payload.address, chain: payload.chain_id ? getCachedChain(Number.parseInt(payload.chain_id)) : undefined, client: options.client, - message: computedMessage, signature: signature, + }; + + let signatureIsValid = await verifySignature({ + ...verifyOpts, + message: computedMessage, }); + // If normalized message failed and domain contained a scheme, try the legacy + // message for backward compatibility with signatures from older SDK versions + if (!signatureIsValid && normalizedDomain !== payload.domain) { + const legacyMessage = createLoginMessage(payload); + signatureIsValid = await verifySignature({ + ...verifyOpts, + message: legacyMessage, + }); + } + if (!signatureIsValid) { return { error: "Invalid signature", From 74fde1d66b89e23c62b8b2eca2a9aeb2cd06c1db Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Mon, 16 Mar 2026 17:08:01 +0700 Subject: [PATCH 3/3] Use https for login URI and improve URL stripping GenerateLoginPayload now defaults uri to a fully-qualified https:// by using stripUrlScheme and prepending https://, ensuring the login payload contains a valid URL. stripUrlScheme was updated to remove query strings and fragments (in addition to scheme and trailing slashes). Tests were updated to expect the https URI and to cover query/fragment cases. --- .../src/auth/core/generate-login-payload.test.ts | 3 ++- .../thirdweb/src/auth/core/generate-login-payload.ts | 2 +- .../thirdweb/src/auth/core/strip-url-scheme.test.ts | 12 ++++++++++++ packages/thirdweb/src/auth/core/strip-url-scheme.ts | 2 +- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/packages/thirdweb/src/auth/core/generate-login-payload.test.ts b/packages/thirdweb/src/auth/core/generate-login-payload.test.ts index 7a5209eaf43..0d781304f3b 100644 --- a/packages/thirdweb/src/auth/core/generate-login-payload.test.ts +++ b/packages/thirdweb/src/auth/core/generate-login-payload.test.ts @@ -89,7 +89,7 @@ describe("generateLoginPayload", () => { "issued_at": "1970-01-01T00:00:00.000Z", "resources": undefined, "statement": "Please ensure that the domain above matches the URL of the current website.", - "uri": "example.com", + "uri": "https://example.com", "version": "1", } `); @@ -118,5 +118,6 @@ describe("generateLoginPayload", () => { }); expect(result.domain).toBe("example.com"); + expect(result.uri).toBe("https://example.com"); }); }); diff --git a/packages/thirdweb/src/auth/core/generate-login-payload.ts b/packages/thirdweb/src/auth/core/generate-login-payload.ts index eebf2d3a2c4..2de336bcf5a 100644 --- a/packages/thirdweb/src/auth/core/generate-login-payload.ts +++ b/packages/thirdweb/src/auth/core/generate-login-payload.ts @@ -46,7 +46,7 @@ export function generateLoginPayload(options: AuthOptions) { )(), resources: options.login?.resources, statement: options.login?.statement || DEFAULT_LOGIN_STATEMENT, - uri: options.login?.uri || options.domain, + uri: options.login?.uri || `https://${stripUrlScheme(options.domain)}`, version: options.login?.version || DEFAULT_LOGIN_VERSION, }; }; diff --git a/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts b/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts index f6056d10680..dff002b48a3 100644 --- a/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts +++ b/packages/thirdweb/src/auth/core/strip-url-scheme.test.ts @@ -31,4 +31,16 @@ describe("stripUrlScheme", () => { test("should strip trailing slash from bare domain", () => { expect(stripUrlScheme("example.com/")).toBe("example.com"); }); + + test("should strip query string", () => { + expect(stripUrlScheme("example.com?x=1")).toBe("example.com"); + }); + + test("should strip fragment", () => { + expect(stripUrlScheme("example.com#frag")).toBe("example.com"); + }); + + test("should strip query string with scheme", () => { + expect(stripUrlScheme("https://example.com?x=1")).toBe("example.com"); + }); }); diff --git a/packages/thirdweb/src/auth/core/strip-url-scheme.ts b/packages/thirdweb/src/auth/core/strip-url-scheme.ts index 15f32ea9400..0adcc653dd0 100644 --- a/packages/thirdweb/src/auth/core/strip-url-scheme.ts +++ b/packages/thirdweb/src/auth/core/strip-url-scheme.ts @@ -4,5 +4,5 @@ * @internal */ export function stripUrlScheme(domain: string): string { - return domain.replace(/^https?:\/\//, "").replace(/\/.*$/, ""); + return domain.replace(/^https?:\/\//, "").replace(/[/?#].*$/, ""); }