diff --git a/.changeset/angry-points-throw.md b/.changeset/angry-points-throw.md new file mode 100644 index 00000000..128586f0 --- /dev/null +++ b/.changeset/angry-points-throw.md @@ -0,0 +1,5 @@ +--- +'@hono/stytch-auth': patch +--- + +Add support for custom domain usage by setting the STYTCH_DOMAIN environment variable diff --git a/packages/stytch-auth/README.md b/packages/stytch-auth/README.md index eb6abdeb..ccd97210 100644 --- a/packages/stytch-auth/README.md +++ b/packages/stytch-auth/README.md @@ -262,6 +262,14 @@ app.get('/advanced-org-ops', async (c) => { ### Custom Configuration +**Custom Base URL:** + +Set `STYTCH_DOMAIN` as an environment variable to instruct the SDK to use your [custom domain](https://stytch.com/docs/guides/custom-domains/overview) for all API calls. + +```bash +STYTCH_DOMAIN=https://login.example.com +``` + **Custom Cookie Name:** ```ts diff --git a/packages/stytch-auth/src/index.test.ts b/packages/stytch-auth/src/index.test.ts index 07804fb3..fa064938 100644 --- a/packages/stytch-auth/src/index.test.ts +++ b/packages/stytch-auth/src/index.test.ts @@ -46,9 +46,10 @@ vi.mock(import('stytch'), async (importOriginal) => { // Forcing the mocked class constructor to be a real type causes tsc to crash // e.g. same error as https://github.com/microsoft/TypeScript/issues/52952 but probably different bug // eslint-disable-next-line @typescript-eslint/no-explicit-any - const ConsumerClient: any = vi.fn(function (this: any, { project_id, secret }) { + const ConsumerClient: any = vi.fn(function (this: any, { project_id, secret, custom_base_url }) { this.project_id = project_id this.secret = secret + this.custom_base_url = custom_base_url this.sessions = ConsumerSessions this.idp = ConsumerOAuth }) @@ -56,9 +57,10 @@ vi.mock(import('stytch'), async (importOriginal) => { // Forcing the mocked class constructor to be a real type causes tsc to crash // e.g. same error as https://github.com/microsoft/TypeScript/issues/52952 but probably different bug // eslint-disable-next-line @typescript-eslint/no-explicit-any - const B2BClientMock: any = vi.fn(function (this: any, { project_id, secret }) { + const B2BClientMock: any = vi.fn(function (this: any, { project_id, secret, custom_base_url }) { this.project_id = project_id this.secret = secret + this.custom_base_url = custom_base_url this.sessions = B2BSessions this.idp = B2BIdp }) @@ -77,6 +79,7 @@ describe('Consumer', () => { beforeEach(() => { vi.stubEnv('STYTCH_PROJECT_ID', 'project-test-xxxxx') vi.stubEnv('STYTCH_PROJECT_SECRET', 'secret-key-test-xxxxx') + vi.stubEnv('STYTCH_DOMAIN', 'https://login.example.com') }) describe('getClient', () => { test('Instantiates client from ctx for handlers to use', async () => { @@ -86,7 +89,11 @@ describe('Consumer', () => { app.get('/', (ctx) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const client = Consumer.getClient(ctx) as any - return ctx.json({ project_id: client.project_id, secret: client.secret }) + return ctx.json({ + project_id: client.project_id, + secret: client.secret, + custom_base_url: client.custom_base_url, + }) }) const response = await app.request(req) @@ -95,6 +102,7 @@ describe('Consumer', () => { expect(await response.json()).toEqual({ project_id: 'project-test-xxxxx', secret: 'secret-key-test-xxxxx', + custom_base_url: 'https://login.example.com', }) }) }) @@ -488,6 +496,7 @@ describe('B2B', () => { beforeEach(() => { vi.stubEnv('STYTCH_PROJECT_ID', 'project-test-b2b-xxxxx') vi.stubEnv('STYTCH_PROJECT_SECRET', 'secret-key-test-b2b-xxxxx') + vi.stubEnv('STYTCH_DOMAIN', 'https://login.example.com') }) describe('getClient', () => { test('Instantiates B2B client from ctx for handlers to use', async () => { @@ -497,7 +506,11 @@ describe('B2B', () => { app.get('/', (ctx) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any const client = B2B.getClient(ctx) as any - return ctx.json({ project_id: client.project_id, secret: client.secret }) + return ctx.json({ + project_id: client.project_id, + secret: client.secret, + custom_base_url: client.custom_base_url, + }) }) const response = await app.request(req) @@ -506,6 +519,7 @@ describe('B2B', () => { expect(await response.json()).toEqual({ project_id: 'project-test-b2b-xxxxx', secret: 'secret-key-test-b2b-xxxxx', + custom_base_url: 'https://login.example.com', }) }) }) diff --git a/packages/stytch-auth/src/index.ts b/packages/stytch-auth/src/index.ts index 8a77db79..c9d99f59 100644 --- a/packages/stytch-auth/src/index.ts +++ b/packages/stytch-auth/src/index.ts @@ -13,6 +13,8 @@ type StytchEnv = { STYTCH_PROJECT_ID: string /** The Stytch project secret */ STYTCH_PROJECT_SECRET: string + /** The Stytch Project domain */ + STYTCH_DOMAIN?: string } type ConsumerTokenClaims = Awaited> @@ -193,6 +195,7 @@ const getConsumerClient = (c: Context) => { new Client({ project_id: stytchEnv.STYTCH_PROJECT_ID, secret: stytchEnv.STYTCH_PROJECT_SECRET, + custom_base_url: stytchEnv.STYTCH_DOMAIN, }) return consumerClients[stytchEnv.STYTCH_PROJECT_ID] } @@ -214,6 +217,7 @@ const getB2BClient = (c: Context) => { new B2BClient({ project_id: stytchEnv.STYTCH_PROJECT_ID, secret: stytchEnv.STYTCH_PROJECT_SECRET, + custom_base_url: stytchEnv.STYTCH_DOMAIN, }) return b2bClients[stytchEnv.STYTCH_PROJECT_ID] }