Skip to content

Commit 150091d

Browse files
authored
Added Support for Multiple Custom Domain (#1109)
2 parents 3d9204c + 39f3094 commit 150091d

File tree

7 files changed

+229
-8
lines changed

7 files changed

+229
-8
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export * from './lib/errors.js';
55
export * from './lib/models.js';
66
export * from './lib/httpResponseHeadersUtils.js';
77
export * from './deprecations.js';
8+
export { CustomDomainHeader } from './lib/runtime.js';

src/lib/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from './errors.js';
22
export * from './models.js';
33
export { RetryConfiguration } from './retry.js';
4+
export { CustomDomainHeader } from './runtime.js';

src/lib/runtime.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,48 @@ export function applyQueryParams<
291291
) as Pick<TRequestParams, ReadonlyArray<Key>[number]>;
292292
}
293293

294+
// Pre-compiled regex for matching whitelisted paths
295+
const compiledWhitelistedPathRegexes: RegExp[] = compileWhitelistedPathPatterns();
296+
297+
// Function to compile the whitelisted patterns
298+
function compileWhitelistedPathPatterns(): RegExp[] {
299+
const patterns = [
300+
'^/api/v2/jobs/verification-email$',
301+
'^/api/v2/tickets/email-verification$',
302+
'^/api/v2/tickets/password-change$',
303+
'^/api/v2/organizations/[^/]+/invitations$',
304+
'^/api/v2/users$',
305+
'^/api/v2/users/[^/]+$',
306+
'^/api/v2/guardian/enrollments/ticket$',
307+
];
308+
309+
return patterns.map((pattern) => new RegExp(pattern));
310+
}
311+
312+
// Function to check if the path matches any whitelisted pattern
313+
function isCustomDomainPathWhitelisted(path: string): boolean {
314+
return compiledWhitelistedPathRegexes.some((regex) => regex.test(path));
315+
}
316+
317+
// Function to create the custom domain header for a request
318+
export function CustomDomainHeader(domain: string): InitOverrideFunction {
319+
return async ({ init, context }: { init: RequestInit; context: RequestOpts }) => {
320+
const headers: Record<string, string> = { ...init.headers } as Record<string, string>;
321+
322+
// Only add the custom domain header for whitelisted paths
323+
const formattedPath = context.path.startsWith('/api/v2/')
324+
? context.path
325+
: `/api/v2${context.path}`;
326+
327+
if (isCustomDomainPathWhitelisted(formattedPath)) {
328+
headers['auth0-custom-domain'] = domain;
329+
}
330+
331+
// Return the updated init with custom domain header if needed
332+
return { ...init, headers: headers };
333+
};
334+
}
335+
294336
/**
295337
* @private
296338
*/

src/management/__generated/managers/custom-domains-manager.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,14 @@ export class CustomDomainsManager extends BaseAPI {
6565
key: 'from',
6666
config: {},
6767
},
68+
{
69+
key: 'domain_metadata_filter',
70+
config: {},
71+
},
72+
{
73+
key: 'domain_name_filter',
74+
config: {},
75+
},
6876
]);
6977

7078
const response = await this.request(
@@ -118,19 +126,18 @@ export class CustomDomainsManager extends BaseAPI {
118126
* <pre><code>{ "custom_client_ip_header": "cf-connecting-ip" }</code></pre>
119127
*
120128
* <h5>Updating TLS_POLICY for a custom domain</h5>To update the <code>tls_policy</code> for a domain, the body to send should be:
121-
* <pre><code>{ "tls_policy": "compatible" }</code></pre>
129+
* <pre><code>{ "tls_policy": "recommended" }</code></pre>
122130
*
123131
*
124132
* TLS Policies:
125133
*
126134
* - recommended - for modern usage this includes TLS 1.2 only
127-
* - compatible - compatible with older browsers this policy includes TLS 1.0, 1.1, 1.2
128135
*
129136
*
130137
* Some considerations:
131138
*
132139
* - The TLS ciphers and protocols available in each TLS policy follow industry recommendations, and may be updated occasionally.
133-
* - Do not use the <code>compatible</code> TLS policy unless you have clients that require TLS 1.0.
140+
* - The <code>compatible</code> TLS policy is no longer supported.
134141
*
135142
* Update custom domain configuration
136143
*

src/management/__generated/models/index.ts

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,48 @@ export interface ActionsDraftUpdate {
88
*/
99
update_draft?: boolean;
1010
}
11+
/**
12+
* Certificate information. This object is relevant only for Custom Domains with Auth0-Managed Certificates.
13+
*/
14+
export interface Certificate {
15+
/**
16+
* The provisioning status of the certificate.
17+
*
18+
*/
19+
status?: CertificateStatusEnum;
20+
/**
21+
* A user-friendly error message will be presented if the certificate status is provisioning_failed or renewing_failed.
22+
*
23+
*/
24+
error_msg?: string;
25+
/**
26+
* The Certificate Authority issued the certificate.
27+
*
28+
*/
29+
certificate_authority?: CertificateCertificateAuthorityEnum;
30+
/**
31+
* The certificate will be renewed prior to this date.
32+
*
33+
*/
34+
renews_before?: string;
35+
}
36+
37+
export const CertificateStatusEnum = {
38+
provisioning: 'provisioning',
39+
provisioning_failed: 'provisioning_failed',
40+
provisioned: 'provisioned',
41+
renewing_failed: 'renewing_failed',
42+
} as const;
43+
export type CertificateStatusEnum =
44+
(typeof CertificateStatusEnum)[keyof typeof CertificateStatusEnum];
45+
46+
export const CertificateCertificateAuthorityEnum = {
47+
letsencrypt: 'letsencrypt',
48+
googletrust: 'googletrust',
49+
} as const;
50+
export type CertificateCertificateAuthorityEnum =
51+
(typeof CertificateCertificateAuthorityEnum)[keyof typeof CertificateCertificateAuthorityEnum];
52+
1153
/**
1254
*
1355
*/
@@ -3776,6 +3818,14 @@ export interface CustomDomain {
37763818
*
37773819
*/
37783820
tls_policy?: string;
3821+
/**
3822+
* Domain metadata associated with the custom domain, in the form of an object with string values (max 255 chars). Maximum of 10 domain metadata properties allowed.
3823+
*
3824+
*/
3825+
domain_metadata?: { [key: string]: any };
3826+
/**
3827+
*/
3828+
certificate?: Certificate;
37793829
}
37803830

37813831
export const CustomDomainStatusEnum = {
@@ -9838,7 +9888,7 @@ export interface PatchCredentialsByCredentialIdRequest {
98389888
*/
98399889
export interface PatchCustomDomainsByIdRequest {
98409890
/**
9841-
* compatible includes TLS 1.0, 1.1, 1.2, and recommended only includes TLS 1.2
9891+
* recommended includes TLS 1.2
98429892
*
98439893
*/
98449894
tls_policy?: PatchCustomDomainsByIdRequestTlsPolicyEnum;
@@ -9847,11 +9897,15 @@ export interface PatchCustomDomainsByIdRequest {
98479897
*
98489898
*/
98499899
custom_client_ip_header?: PatchCustomDomainsByIdRequestCustomClientIpHeaderEnum;
9900+
/**
9901+
* Domain metadata associated with the custom domain, in the form of an object with string values (max 255 chars). Maximum of 10 domain metadata properties allowed.
9902+
*
9903+
*/
9904+
domain_metadata?: { [key: string]: any };
98509905
}
98519906

98529907
export const PatchCustomDomainsByIdRequestTlsPolicyEnum = {
98539908
recommended: 'recommended',
9854-
compatible: 'compatible',
98559909
} as const;
98569910
export type PatchCustomDomainsByIdRequestTlsPolicyEnum =
98579911
(typeof PatchCustomDomainsByIdRequestTlsPolicyEnum)[keyof typeof PatchCustomDomainsByIdRequestTlsPolicyEnum];
@@ -11198,6 +11252,14 @@ export interface PostCustomDomains201Response {
1119811252
*
1119911253
*/
1120011254
tls_policy?: string;
11255+
/**
11256+
* Domain metadata associated with the custom domain, in the form of an object with string values (max 255 chars). Maximum of 10 domain metadata properties allowed.
11257+
*
11258+
*/
11259+
domain_metadata?: { [key: string]: any };
11260+
/**
11261+
*/
11262+
certificate?: Certificate;
1120111263
}
1120211264

1120311265
export const PostCustomDomains201ResponseStatusEnum = {
@@ -11225,7 +11287,31 @@ export interface PostCustomDomains201ResponseVerification {
1122511287
*
1122611288
*/
1122711289
methods?: Array<PostCustomDomains201ResponseVerificationMethodsInner>;
11290+
/**
11291+
* The DNS record verification status. This field is relevant only for Custom Domains with Auth0-Managed Certificates.
11292+
*
11293+
*/
11294+
status?: PostCustomDomains201ResponseVerificationStatusEnum;
11295+
/**
11296+
* The user0-friendly error message in case of failed verification. This field is relevant only for Custom Domains with Auth0-Managed Certificates.
11297+
*
11298+
*/
11299+
error_msg?: string;
11300+
/**
11301+
* The date and time when the custom domain was last verified. This field is relevant only for Custom Domains with Auth0-Managed Certificates.
11302+
*
11303+
*/
11304+
last_verified_at?: string;
1122811305
}
11306+
11307+
export const PostCustomDomains201ResponseVerificationStatusEnum = {
11308+
verified: 'verified',
11309+
pending: 'pending',
11310+
failed: 'failed',
11311+
} as const;
11312+
export type PostCustomDomains201ResponseVerificationStatusEnum =
11313+
(typeof PostCustomDomains201ResponseVerificationStatusEnum)[keyof typeof PostCustomDomains201ResponseVerificationStatusEnum];
11314+
1122911315
/**
1123011316
*
1123111317
*/
@@ -11274,7 +11360,7 @@ export interface PostCustomDomainsRequest {
1127411360
*/
1127511361
verification_method?: PostCustomDomainsRequestVerificationMethodEnum;
1127611362
/**
11277-
* compatible includes TLS 1.0, 1.1, 1.2, and recommended only includes TLS 1.2
11363+
* Custom domain TLS policy. Must be `recommended`, includes TLS 1.2.
1127811364
*
1127911365
*/
1128011366
tls_policy?: PostCustomDomainsRequestTlsPolicyEnum;
@@ -11283,6 +11369,11 @@ export interface PostCustomDomainsRequest {
1128311369
*
1128411370
*/
1128511371
custom_client_ip_header?: PostCustomDomainsRequestCustomClientIpHeaderEnum;
11372+
/**
11373+
* Domain metadata associated with the custom domain, in the form of an object with string values (max 255 chars). Maximum of 10 domain metadata properties allowed.
11374+
*
11375+
*/
11376+
domain_metadata?: { [key: string]: any };
1128611377
}
1128711378

1128811379
export const PostCustomDomainsRequestTypeEnum = {
@@ -11300,7 +11391,6 @@ export type PostCustomDomainsRequestVerificationMethodEnum =
1130011391

1130111392
export const PostCustomDomainsRequestTlsPolicyEnum = {
1130211393
recommended: 'recommended',
11303-
compatible: 'compatible',
1130411394
} as const;
1130511395
export type PostCustomDomainsRequestTlsPolicyEnum =
1130611396
(typeof PostCustomDomainsRequestTlsPolicyEnum)[keyof typeof PostCustomDomainsRequestTlsPolicyEnum];
@@ -15056,6 +15146,14 @@ export interface PostVerify200Response {
1505615146
*
1505715147
*/
1505815148
tls_policy?: string;
15149+
/**
15150+
* Domain metadata associated with the custom domain, in the form of an object with string values (max 255 chars). Maximum of 10 domain metadata properties allowed.
15151+
*
15152+
*/
15153+
domain_metadata?: { [key: string]: any };
15154+
/**
15155+
*/
15156+
certificate?: Certificate;
1505915157
}
1506015158

1506115159
export const PostVerify200ResponseStatusEnum = {
@@ -18872,6 +18970,16 @@ export interface GetCustomDomainsRequest {
1887218970
*
1887318971
*/
1887418972
from?: string;
18973+
/**
18974+
* Optional filter on domain_metadata.
18975+
*
18976+
*/
18977+
domain_metadata_filter?: string;
18978+
/**
18979+
* Optional filter on domain_name.
18980+
*
18981+
*/
18982+
domain_name_filter?: string;
1887518983
}
1887618984
/**
1887718985
*

src/management/management-client-options.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { ClientOptions } from '../lib/runtime.js';
33
export interface ManagementClientOptions extends ClientOptions {
44
domain: string;
55
audience?: string;
6+
headers?: Record<string, string>;
67
}
78

89
export interface ManagementClientOptionsWithToken extends ManagementClientOptions {

test/lib/runtime.test.ts

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
AuthApiError,
1111
} from '../../src/index.js';
1212
import { InitOverrideFunction, RequestOpts } from '../../src/lib/models.js';
13-
import { BaseAPI, applyQueryParams } from '../../src/lib/runtime.js';
13+
import { BaseAPI, applyQueryParams, CustomDomainHeader } from '../../src/lib/runtime.js';
1414

1515
import * as utils from '../../src/utils.js';
1616
import { base64url } from 'jose';
@@ -909,3 +909,64 @@ describe('Runtime for UserInfoClient', () => {
909909
expect(request.isDone()).toBe(true);
910910
});
911911
});
912+
913+
describe('CustomDomainHeader', () => {
914+
const domain = 'custom.domain.com';
915+
916+
const whitelistedPaths = [
917+
'/api/v2/jobs/verification-email',
918+
'/api/v2/tickets/email-verification',
919+
'/api/v2/tickets/password-change',
920+
'/api/v2/organizations/org123/invitations',
921+
'/api/v2/users',
922+
'/api/v2/users/user123',
923+
'/api/v2/guardian/enrollments/ticket',
924+
];
925+
926+
const nonWhitelistedPath = '/api/v2/not-whitelisted';
927+
928+
const method = 'GET';
929+
930+
it('adds the custom domain header for whitelisted paths', async () => {
931+
for (const path of whitelistedPaths) {
932+
const fn = CustomDomainHeader(domain);
933+
const result = await fn({
934+
init: { method, headers: {} },
935+
context: { method, path },
936+
});
937+
const headers = result.headers as Record<string, string>;
938+
expect(headers['auth0-custom-domain']).toBe(domain);
939+
}
940+
});
941+
942+
it('does not add the custom domain header for non-whitelisted paths', async () => {
943+
const fn = CustomDomainHeader(domain);
944+
const result = await fn({
945+
init: { method, headers: {} },
946+
context: { method, path: nonWhitelistedPath },
947+
});
948+
const headers = result.headers as Record<string, string>;
949+
expect(headers['auth0-custom-domain']).toBeUndefined();
950+
});
951+
952+
it('prepends /api/v2 to non-prefixed paths', async () => {
953+
const fn = CustomDomainHeader(domain);
954+
const result = await fn({
955+
init: { method, headers: {} },
956+
context: { method, path: '/users' },
957+
});
958+
const headers = result.headers as Record<string, string>;
959+
expect(headers['auth0-custom-domain']).toBe(domain);
960+
});
961+
962+
it('preserves existing headers', async () => {
963+
const fn = CustomDomainHeader(domain);
964+
const result = await fn({
965+
init: { method, headers: { 'existing-header': 'value' } },
966+
context: { method, path: whitelistedPaths[0] },
967+
});
968+
const headers = result.headers as Record<string, string>;
969+
expect(headers['existing-header']).toBe('value');
970+
expect(headers['auth0-custom-domain']).toBe(domain);
971+
});
972+
});

0 commit comments

Comments
 (0)