diff --git a/apps/api/src/services/oauth/provider.test.ts b/apps/api/src/services/oauth/provider.test.ts new file mode 100644 index 00000000..907e08c4 --- /dev/null +++ b/apps/api/src/services/oauth/provider.test.ts @@ -0,0 +1,50 @@ +import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { getCallbackUrl } from "./provider.js"; + +describe("getCallbackUrl", () => { + const originalEnv = { ...process.env }; + + beforeEach(() => { + // Clear relevant environment variables before each test + delete process.env.PUBLIC_URL; + delete process.env.PUBLIC_API_URL; + delete process.env.API_PORT; + }); + + afterEach(() => { + // Restore original environment + process.env = { ...originalEnv }; + }); + + describe.each(["github", "google", "oidc"])("with provider %s", (provider) => { + it("uses PUBLIC_URL when it is set and PUBLIC_API_URL is not", () => { + process.env.PUBLIC_URL = "https://optio.example.com"; + expect(getCallbackUrl(provider)).toBe( + `https://optio.example.com/api/auth/${provider}/callback`, + ); + }); + + it("uses PUBLIC_API_URL when it is set", () => { + process.env.PUBLIC_API_URL = "https://optio-api.example.com/api"; + expect(getCallbackUrl(provider)).toBe( + `https://optio-api.example.com/api/auth/${provider}/callback`, + ); + }); + + it("uses PUBLIC_API_URL and trims trailing slash", () => { + process.env.PUBLIC_API_URL = "https://optio-api.example.com/api/"; + expect(getCallbackUrl(provider)).toBe( + `https://optio-api.example.com/api/auth/${provider}/callback`, + ); + }); + + it("falls back to localhost with API_PORT when PUBLIC_URL is not set", () => { + process.env.API_PORT = "8080"; + expect(getCallbackUrl(provider)).toBe(`http://localhost:8080/api/auth/${provider}/callback`); + }); + + it("falls back to localhost:4000 when neither PUBLIC_URL nor API_PORT are set", () => { + expect(getCallbackUrl(provider)).toBe(`http://localhost:4000/api/auth/${provider}/callback`); + }); + }); +}); diff --git a/apps/api/src/services/oauth/provider.ts b/apps/api/src/services/oauth/provider.ts index b950e2ba..d3871097 100644 --- a/apps/api/src/services/oauth/provider.ts +++ b/apps/api/src/services/oauth/provider.ts @@ -21,6 +21,10 @@ export interface OAuthProvider { } export function getCallbackUrl(provider: string): string { + if (process.env.PUBLIC_API_URL) { + const base = process.env.PUBLIC_API_URL.replace(/\/$/, ""); + return `${base}/auth/${provider}/callback`; + } const base = process.env.PUBLIC_URL ?? `http://localhost:${process.env.API_PORT ?? 4000}`; return `${base}/api/auth/${provider}/callback`; } diff --git a/helm/optio/templates/api-deployment.yaml b/helm/optio/templates/api-deployment.yaml index b85ab7d6..c535ec80 100644 --- a/helm/optio/templates/api-deployment.yaml +++ b/helm/optio/templates/api-deployment.yaml @@ -92,6 +92,16 @@ spec: value: "0.0.0.0" - name: OPTIO_API_INTERNAL_URL value: "http://{{ .Release.Name }}-api:{{ .Values.api.port }}" + {{- if .Values.web.publicApiUrl }} + - name: PUBLIC_API_URL + value: {{ .Values.web.publicApiUrl | quote }} + {{- else if .Values.publicUrl }} + - name: PUBLIC_API_URL + value: "{{ trimSuffix "/" .Values.publicUrl }}/api" + {{- else if and (eq .Values.api.service.type "NodePort") .Values.api.service.nodePort }} + - name: PUBLIC_API_URL + value: "http://localhost:{{ .Values.api.service.nodePort }}" + {{- end }} - name: NODE_ENV value: "production" - name: LOG_LEVEL diff --git a/helm/optio/templates/web-deployment.yaml b/helm/optio/templates/web-deployment.yaml index ace5927e..e153b8d1 100644 --- a/helm/optio/templates/web-deployment.yaml +++ b/helm/optio/templates/web-deployment.yaml @@ -79,6 +79,9 @@ spec: {{- if .Values.web.publicApiUrl }} - name: PUBLIC_API_URL value: {{ .Values.web.publicApiUrl | quote }} + {{- else if .Values.publicUrl }} + - name: PUBLIC_API_URL + value: "{{ trimSuffix "/" .Values.publicUrl }}/api" {{- else if and (eq .Values.api.service.type "NodePort") .Values.api.service.nodePort }} - name: PUBLIC_API_URL value: "http://localhost:{{ .Values.api.service.nodePort }}" diff --git a/helm/optio/values.yaml b/helm/optio/values.yaml index 5b4cacd2..b9bd91d4 100644 --- a/helm/optio/values.yaml +++ b/helm/optio/values.yaml @@ -96,6 +96,8 @@ web: maxReplicas: 4 targetCPUUtilizationPercentage: 70 targetMemoryUtilizationPercentage: "" + # Optional override for the public API URL (defaults to PUBLIC_URL with /api path) + publicApiUrl: "" # ────────────────────────────────────────────────────────────────────────────── # Optio Operations Assistant Pod