From fbc8a7437d2f8d6b8d3d54f0dfe215f652791613 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 6 Sep 2025 03:25:35 +0700 Subject: [PATCH 1/4] Add API domain override and update OTP endpoint Introduces an 'api' domain override in domains.ts and updates the OTP authentication flow to use the new API endpoint for initiation. This change improves flexibility for API server configuration and aligns OTP requests with the updated backend route. Closes BLD-220 --- packages/thirdweb/src/utils/domains.ts | 8 + .../src/wallets/in-app/web/lib/auth/otp.ts | 194 +++++++++--------- 2 files changed, 105 insertions(+), 97 deletions(-) diff --git a/packages/thirdweb/src/utils/domains.ts b/packages/thirdweb/src/utils/domains.ts index 9e345046ee9..d39a840e15e 100644 --- a/packages/thirdweb/src/utils/domains.ts +++ b/packages/thirdweb/src/utils/domains.ts @@ -14,6 +14,11 @@ type DomainOverrides = { * @default "embedded-wallet.thirdweb.com" */ inAppWallet?: string; + /** + * The base URL for the API server. + * @default "api.thirdweb.com" + */ + api?: string; /** * The base URL for the payment server. * @default "pay.thirdweb.com" @@ -54,6 +59,7 @@ type DomainOverrides = { export const DEFAULT_RPC_URL = "rpc.thirdweb.com"; const DEFAULT_SOCIAL_URL = "social.thirdweb.com"; const DEFAULT_IN_APP_WALLET_URL = "embedded-wallet.thirdweb.com"; +const DEFAULT_API_URL = "api.thirdweb.com"; const DEFAULT_PAY_URL = "pay.thirdweb.com"; const DEFAULT_STORAGE_URL = "storage.thirdweb.com"; const DEFAULT_BUNDLER_URL = "bundler.thirdweb.com"; @@ -64,6 +70,7 @@ const DEFAULT_BRIDGE_URL = "bridge.thirdweb.com"; let domains: { [k in keyof DomainOverrides]-?: string } = { analytics: DEFAULT_ANALYTICS_URL, + api: DEFAULT_API_URL, bridge: DEFAULT_BRIDGE_URL, bundler: DEFAULT_BUNDLER_URL, engineCloud: DEFAULT_ENGINE_CLOUD_URL, @@ -78,6 +85,7 @@ let domains: { [k in keyof DomainOverrides]-?: string } = { export const setThirdwebDomains = (DomainOverrides: DomainOverrides) => { domains = { analytics: DomainOverrides.analytics ?? DEFAULT_ANALYTICS_URL, + api: DomainOverrides.api ?? DEFAULT_API_URL, bridge: DomainOverrides.bridge ?? DEFAULT_BRIDGE_URL, bundler: DomainOverrides.bundler ?? DEFAULT_BUNDLER_URL, engineCloud: DomainOverrides.engineCloud ?? DEFAULT_ENGINE_CLOUD_URL, diff --git a/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts b/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts index b14fec04aca..84969607ae1 100644 --- a/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts +++ b/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts @@ -1,13 +1,11 @@ import type { ThirdwebClient } from "../../../../../client/client.js"; +import { getThirdwebBaseUrl } from "../../../../../utils/domains.js"; import { stringify } from "../../../../../utils/json.js"; -import { - getLoginCallbackUrl, - getLoginUrl, -} from "../../../core/authentication/getLoginPath.js"; +import { getLoginCallbackUrl } from "../../../core/authentication/getLoginPath.js"; import type { - AuthStoredTokenWithCookieReturnType, - MultiStepAuthArgsType, - PreAuthArgsType, + AuthStoredTokenWithCookieReturnType, + MultiStepAuthArgsType, + PreAuthArgsType, } from "../../../core/authentication/types.js"; import type { Ecosystem } from "../../../core/wallet/types.js"; @@ -15,101 +13,103 @@ import type { Ecosystem } from "../../../core/wallet/types.js"; * @internal */ export const sendOtp = async (args: PreAuthArgsType): Promise => { - const { client, ecosystem } = args; - const url = getLoginUrl({ authOption: args.strategy, client, ecosystem }); - - const headers: Record = { - "Content-Type": "application/json", - "x-client-id": client.clientId, - }; - - if (ecosystem?.id) { - headers["x-ecosystem-id"] = ecosystem.id; - } - - if (ecosystem?.partnerId) { - headers["x-ecosystem-partner-id"] = ecosystem.partnerId; - } - - const body = (() => { - switch (args.strategy) { - case "email": - return { - email: args.email, - }; - case "phone": - return { - phone: args.phoneNumber, - }; - } - })(); - - const response = await fetch(url, { - body: stringify(body), - headers, - method: "POST", - }); - - if (!response.ok) { - throw new Error("Failed to send verification code"); - } - - return await response.json(); + const { client, ecosystem } = args; + const url = `${getThirdwebBaseUrl("api")}/v1/auth/initiate`; + + const headers: Record = { + "Content-Type": "application/json", + "x-client-id": client.clientId, + }; + + if (ecosystem?.id) { + headers["x-ecosystem-id"] = ecosystem.id; + } + + if (ecosystem?.partnerId) { + headers["x-ecosystem-partner-id"] = ecosystem.partnerId; + } + + const body = (() => { + switch (args.strategy) { + case "email": + return { + type: "email", + email: args.email, + }; + case "phone": + return { + type: "phone", + phone: args.phoneNumber, + }; + } + })(); + + const response = await fetch(url, { + body: stringify(body), + headers, + method: "POST", + }); + + if (!response.ok) { + throw new Error("Failed to send verification code"); + } + + return await response.json(); }; /** * @internal */ export const verifyOtp = async ( - args: MultiStepAuthArgsType & { - client: ThirdwebClient; - ecosystem?: Ecosystem; - }, + args: MultiStepAuthArgsType & { + client: ThirdwebClient; + ecosystem?: Ecosystem; + }, ): Promise => { - const { client, ecosystem } = args; - const url = getLoginCallbackUrl({ - authOption: args.strategy, - client: args.client, - ecosystem: args.ecosystem, - }); - - const headers: Record = { - "Content-Type": "application/json", - "x-client-id": client.clientId, - }; - - if (ecosystem?.id) { - headers["x-ecosystem-id"] = ecosystem.id; - } - - if (ecosystem?.partnerId) { - headers["x-ecosystem-partner-id"] = ecosystem.partnerId; - } - - const body = (() => { - switch (args.strategy) { - case "email": - return { - code: args.verificationCode, - email: args.email, - }; - case "phone": - return { - code: args.verificationCode, - phone: args.phoneNumber, - }; - } - })(); - - const response = await fetch(url, { - body: stringify(body), - headers, - method: "POST", - }); - - if (!response.ok) { - throw new Error("Failed to verify verification code"); - } - - return await response.json(); + const { client, ecosystem } = args; + const url = getLoginCallbackUrl({ + authOption: args.strategy, + client: args.client, + ecosystem: args.ecosystem, + }); + + const headers: Record = { + "Content-Type": "application/json", + "x-client-id": client.clientId, + }; + + if (ecosystem?.id) { + headers["x-ecosystem-id"] = ecosystem.id; + } + + if (ecosystem?.partnerId) { + headers["x-ecosystem-partner-id"] = ecosystem.partnerId; + } + + const body = (() => { + switch (args.strategy) { + case "email": + return { + code: args.verificationCode, + email: args.email, + }; + case "phone": + return { + code: args.verificationCode, + phone: args.phoneNumber, + }; + } + })(); + + const response = await fetch(url, { + body: stringify(body), + headers, + method: "POST", + }); + + if (!response.ok) { + throw new Error("Failed to verify verification code"); + } + + return await response.json(); }; From e644c3d1d65647463e34e1bd87a98a70e0accc2b Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 6 Sep 2025 03:29:38 +0700 Subject: [PATCH 2/4] fmt --- .../src/wallets/in-app/web/lib/auth/otp.ts | 190 +++++++++--------- 1 file changed, 95 insertions(+), 95 deletions(-) diff --git a/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts b/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts index 84969607ae1..edc85b4433b 100644 --- a/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts +++ b/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts @@ -3,9 +3,9 @@ import { getThirdwebBaseUrl } from "../../../../../utils/domains.js"; import { stringify } from "../../../../../utils/json.js"; import { getLoginCallbackUrl } from "../../../core/authentication/getLoginPath.js"; import type { - AuthStoredTokenWithCookieReturnType, - MultiStepAuthArgsType, - PreAuthArgsType, + AuthStoredTokenWithCookieReturnType, + MultiStepAuthArgsType, + PreAuthArgsType, } from "../../../core/authentication/types.js"; import type { Ecosystem } from "../../../core/wallet/types.js"; @@ -13,103 +13,103 @@ import type { Ecosystem } from "../../../core/wallet/types.js"; * @internal */ export const sendOtp = async (args: PreAuthArgsType): Promise => { - const { client, ecosystem } = args; - const url = `${getThirdwebBaseUrl("api")}/v1/auth/initiate`; - - const headers: Record = { - "Content-Type": "application/json", - "x-client-id": client.clientId, - }; - - if (ecosystem?.id) { - headers["x-ecosystem-id"] = ecosystem.id; - } - - if (ecosystem?.partnerId) { - headers["x-ecosystem-partner-id"] = ecosystem.partnerId; - } - - const body = (() => { - switch (args.strategy) { - case "email": - return { - type: "email", - email: args.email, - }; - case "phone": - return { - type: "phone", - phone: args.phoneNumber, - }; - } - })(); - - const response = await fetch(url, { - body: stringify(body), - headers, - method: "POST", - }); - - if (!response.ok) { - throw new Error("Failed to send verification code"); - } - - return await response.json(); + const { client, ecosystem } = args; + const url = `${getThirdwebBaseUrl("api")}/v1/auth/initiate`; + + const headers: Record = { + "Content-Type": "application/json", + "x-client-id": client.clientId, + }; + + if (ecosystem?.id) { + headers["x-ecosystem-id"] = ecosystem.id; + } + + if (ecosystem?.partnerId) { + headers["x-ecosystem-partner-id"] = ecosystem.partnerId; + } + + const body = (() => { + switch (args.strategy) { + case "email": + return { + type: "email", + email: args.email, + }; + case "phone": + return { + type: "phone", + phone: args.phoneNumber, + }; + } + })(); + + const response = await fetch(url, { + body: stringify(body), + headers, + method: "POST", + }); + + if (!response.ok) { + throw new Error("Failed to send verification code"); + } + + return await response.json(); }; /** * @internal */ export const verifyOtp = async ( - args: MultiStepAuthArgsType & { - client: ThirdwebClient; - ecosystem?: Ecosystem; - }, + args: MultiStepAuthArgsType & { + client: ThirdwebClient; + ecosystem?: Ecosystem; + }, ): Promise => { - const { client, ecosystem } = args; - const url = getLoginCallbackUrl({ - authOption: args.strategy, - client: args.client, - ecosystem: args.ecosystem, - }); - - const headers: Record = { - "Content-Type": "application/json", - "x-client-id": client.clientId, - }; - - if (ecosystem?.id) { - headers["x-ecosystem-id"] = ecosystem.id; - } - - if (ecosystem?.partnerId) { - headers["x-ecosystem-partner-id"] = ecosystem.partnerId; - } - - const body = (() => { - switch (args.strategy) { - case "email": - return { - code: args.verificationCode, - email: args.email, - }; - case "phone": - return { - code: args.verificationCode, - phone: args.phoneNumber, - }; - } - })(); - - const response = await fetch(url, { - body: stringify(body), - headers, - method: "POST", - }); - - if (!response.ok) { - throw new Error("Failed to verify verification code"); - } - - return await response.json(); + const { client, ecosystem } = args; + const url = getLoginCallbackUrl({ + authOption: args.strategy, + client: args.client, + ecosystem: args.ecosystem, + }); + + const headers: Record = { + "Content-Type": "application/json", + "x-client-id": client.clientId, + }; + + if (ecosystem?.id) { + headers["x-ecosystem-id"] = ecosystem.id; + } + + if (ecosystem?.partnerId) { + headers["x-ecosystem-partner-id"] = ecosystem.partnerId; + } + + const body = (() => { + switch (args.strategy) { + case "email": + return { + code: args.verificationCode, + email: args.email, + }; + case "phone": + return { + code: args.verificationCode, + phone: args.phoneNumber, + }; + } + })(); + + const response = await fetch(url, { + body: stringify(body), + headers, + method: "POST", + }); + + if (!response.ok) { + throw new Error("Failed to verify verification code"); + } + + return await response.json(); }; From 16464baa2c6f0848b032b209f536be424a833736 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 6 Sep 2025 03:38:53 +0700 Subject: [PATCH 3/4] Update OTP auth to use 'method' and 'sms' for phone Changed the OTP initiation payload to use 'method' instead of 'type', and set phone strategy to 'sms' instead of 'phone'. Also removed the unused return value from sendOtp to match updated API expectations. --- packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts b/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts index edc85b4433b..4626ff47f9d 100644 --- a/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts +++ b/packages/thirdweb/src/wallets/in-app/web/lib/auth/otp.ts @@ -33,12 +33,12 @@ export const sendOtp = async (args: PreAuthArgsType): Promise => { switch (args.strategy) { case "email": return { - type: "email", + method: "email", email: args.email, }; case "phone": return { - type: "phone", + method: "sms", phone: args.phoneNumber, }; } @@ -54,7 +54,7 @@ export const sendOtp = async (args: PreAuthArgsType): Promise => { throw new Error("Failed to send verification code"); } - return await response.json(); + return; }; /** From 8d80613b803fc03d82c5125d51bc94c0c7aedde3 Mon Sep 17 00:00:00 2001 From: 0xFirekeeper <0xFirekeeper@gmail.com> Date: Sat, 6 Sep 2025 03:47:00 +0700 Subject: [PATCH 4/4] Add api domain to Thirdweb domain tests Included 'api.thirdweb.com' in the domain list for test coverage in domain.test.ts. --- packages/thirdweb/src/utils/domain.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/thirdweb/src/utils/domain.test.ts b/packages/thirdweb/src/utils/domain.test.ts index 8c22e32f024..21ad80b1339 100644 --- a/packages/thirdweb/src/utils/domain.test.ts +++ b/packages/thirdweb/src/utils/domain.test.ts @@ -18,6 +18,7 @@ describe("Thirdweb Domains", () => { rpc: "rpc.thirdweb.com", social: "social.thirdweb.com", storage: "storage.thirdweb.com", + api: "api.thirdweb.com", }; beforeEach(() => {