refactor: update forward authentication handling in domain schema and tests

- Replaced `forwardAuthProviderId` with `forwardAuthEnabled` in the domain schema to simplify the configuration of forward authentication.
- Updated related tests to reflect this change, ensuring consistency across the application.
- Introduced a new SQL migration to create the `forward_auth_settings` table for managing authentication domains and their configurations.

This refactor enhances the clarity and maintainability of the forward authentication logic within the application.
This commit is contained in:
Mauricio Siu
2026-06-06 03:53:45 -06:00
parent 35f452d25f
commit 1df6774ee8
12 changed files with 8483 additions and 29 deletions
@@ -34,7 +34,7 @@ describe("Host rule format regression tests", () => {
stripPath: false,
customEntrypoint: null,
middlewares: null,
forwardAuthProviderId: null,
forwardAuthEnabled: false,
};
describe("Host rule format validation", () => {
@@ -23,7 +23,7 @@ describe("createDomainLabels", () => {
internalPath: "/",
stripPath: false,
middlewares: null,
forwardAuthProviderId: null,
forwardAuthEnabled: false,
};
it("should create basic labels for web entrypoint", async () => {
@@ -34,7 +34,7 @@ const baseDomain: Domain = {
internalPath: "/",
stripPath: false,
middlewares: null,
forwardAuthProviderId: null,
forwardAuthEnabled: false,
};
describe("forwardAuthMiddlewareName", () => {
@@ -62,7 +62,7 @@ describe("createRouterConfig forward-auth wiring", () => {
test("adds forward-auth middleware when a provider is linked", async () => {
const domain: Domain = {
...baseDomain,
forwardAuthProviderId: "provider-abc",
forwardAuthEnabled: true,
};
const config = await createRouterConfig(app, domain, "websecure");
expect(config.middlewares).toContain(
@@ -73,7 +73,7 @@ describe("createRouterConfig forward-auth wiring", () => {
test("forward-auth runs before custom domain middlewares", async () => {
const domain: Domain = {
...baseDomain,
forwardAuthProviderId: "provider-abc",
forwardAuthEnabled: true,
middlewares: ["rate-limit@file"],
};
const config = await createRouterConfig(app, domain, "websecure");
@@ -89,7 +89,7 @@ describe("createRouterConfig forward-auth wiring", () => {
const domain: Domain = {
...baseDomain,
https: true,
forwardAuthProviderId: "provider-abc",
forwardAuthEnabled: true,
};
const config = await createRouterConfig(app, domain, "web");
expect(config.middlewares).toContain("redirect-to-https");
@@ -148,7 +148,7 @@ const baseDomain: Domain = {
internalPath: "/",
stripPath: false,
middlewares: null,
forwardAuthProviderId: null,
forwardAuthEnabled: false,
};
const baseRedirect: Redirect = {
@@ -0,0 +1,16 @@
CREATE TABLE "forward_auth_settings" (
"forwardAuthSettingsId" text PRIMARY KEY NOT NULL,
"authDomain" text NOT NULL,
"baseDomain" text NOT NULL,
"https" boolean DEFAULT true NOT NULL,
"certificateType" "certificateType" DEFAULT 'letsencrypt' NOT NULL,
"customCertResolver" text,
"providerId" text,
"serverId" text,
"createdAt" text NOT NULL,
CONSTRAINT "forward_auth_settings_serverId_unique" UNIQUE("serverId")
);
--> statement-breakpoint
ALTER TABLE "domain" ADD COLUMN "forwardAuthEnabled" boolean DEFAULT false NOT NULL;--> statement-breakpoint
ALTER TABLE "forward_auth_settings" ADD CONSTRAINT "forward_auth_settings_providerId_sso_provider_provider_id_fk" FOREIGN KEY ("providerId") REFERENCES "public"."sso_provider"("provider_id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "forward_auth_settings" ADD CONSTRAINT "forward_auth_settings_serverId_server_serverId_fk" FOREIGN KEY ("serverId") REFERENCES "public"."server"("serverId") ON DELETE cascade ON UPDATE no action;
File diff suppressed because it is too large Load Diff
+7
View File
@@ -1191,6 +1191,13 @@
"when": 1780127552074,
"tag": "0169_parched_johnny_storm",
"breakpoints": true
},
{
"idx": 170,
"version": "7",
"when": 1780739532982,
"tag": "0170_amusing_spot",
"breakpoints": true
}
]
}
+3 -11
View File
@@ -16,7 +16,6 @@ import { applications } from "./application";
import { compose } from "./compose";
import { previewDeployments } from "./preview-deployments";
import { certificateType } from "./shared";
import { ssoProvider } from "./sso";
export const domainType = pgEnum("domainType", [
"compose",
@@ -56,10 +55,7 @@ export const domains = pgTable("domain", {
internalPath: text("internalPath").default("/"),
stripPath: boolean("stripPath").notNull().default(false),
middlewares: text("middlewares").array().default(sql`ARRAY[]::text[]`),
forwardAuthProviderId: text("forwardAuthProviderId").references(
() => ssoProvider.providerId,
{ onDelete: "set null" },
),
forwardAuthEnabled: boolean("forwardAuthEnabled").notNull().default(false),
});
export const domainsRelations = relations(domains, ({ one }) => ({
@@ -75,10 +71,6 @@ export const domainsRelations = relations(domains, ({ one }) => ({
fields: [domains.previewDeploymentId],
references: [previewDeployments.previewDeploymentId],
}),
forwardAuthProvider: one(ssoProvider, {
fields: [domains.forwardAuthProviderId],
references: [ssoProvider.providerId],
}),
}));
const createSchema = createInsertSchema(domains, {
@@ -103,7 +95,7 @@ export const apiCreateDomain = createSchema.pick({
internalPath: true,
stripPath: true,
middlewares: true,
forwardAuthProviderId: true,
forwardAuthEnabled: true,
});
export const apiFindDomain = z.object({
@@ -136,6 +128,6 @@ export const apiUpdateDomain = createSchema
internalPath: true,
stripPath: true,
middlewares: true,
forwardAuthProviderId: true,
forwardAuthEnabled: true,
})
.merge(createSchema.pick({ domainId: true }).required());
@@ -108,10 +108,7 @@ export const getDomainSsoStatus = async (
domain: ["read"],
});
}
return {
enabled: !!domain.forwardAuthProviderId,
providerId: domain.forwardAuthProviderId ?? null,
};
return { enabled: !!domain.forwardAuthEnabled };
};
const settingsWhere = (serverId: string | null) =>
@@ -348,9 +345,7 @@ export const enableForwardAuthOnDomain = async (input: {
});
}
await updateDomainById(input.domainId, {
forwardAuthProviderId: settings.providerId,
});
await updateDomainById(input.domainId, { forwardAuthEnabled: true });
const domain = await findDomainById(input.domainId);
await manageDomain(application, domain);
@@ -365,7 +360,7 @@ export const disableForwardAuthOnDomain = async (input: {
);
const uniqueConfigKey = domain.uniqueConfigKey;
await updateDomainById(input.domainId, { forwardAuthProviderId: null });
await updateDomainById(input.domainId, { forwardAuthEnabled: false });
const updated = await findDomainById(input.domainId);
await manageDomain(application, updated);
await removeForwardAuthMiddleware(application, uniqueConfigKey);
+1 -1
View File
@@ -198,7 +198,7 @@ export const createRouterConfig = async (
// authentication runs first. No-op unless the domain links a provider.
// The -errors middleware must come first so a 401 from the auth check is
// rewritten to a 302 redirect to the login page.
if (domain.forwardAuthProviderId) {
if (domain.forwardAuthEnabled) {
const name = forwardAuthMiddlewareName(appName, uniqueConfigKey);
routerConfig.middlewares?.push(`${name}-errors`);
routerConfig.middlewares?.push(name);
@@ -73,7 +73,7 @@ export const createForwardAuthMiddleware = async (
app: ApplicationNested,
domain: Domain,
) => {
if (!domain.forwardAuthProviderId) {
if (!domain.forwardAuthEnabled) {
return;
}