Skip to content

Commit 4bc7d2a

Browse files
committed
fix: get config to openauth client in Next.js production build
1 parent ea70250 commit 4bc7d2a

File tree

9 files changed

+61
-54
lines changed

9 files changed

+61
-54
lines changed

apps/api/Dockerfile

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ RUN adduser --system --uid 1001 runner
7272
COPY --from=installer --chown=runner:runner /app/apps/api/wait-for-it.sh /usr/local/bin/
7373
RUN chmod 500 /usr/local/bin/wait-for-it.sh
7474

75+
RUN mkdir -p /app/.data
76+
RUN chown runner:runner /app/.data
77+
7578
USER runner
7679

7780
COPY --from=builder --chown=runner:runner /app/apps/api/out/index.min.mjs ./index.min.mjs

apps/api/src/lib/auth-client.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
1-
import { getRuntimeClient } from "@karr/auth/client"
2-
import { lazy, APP_URL, API_BASE } from "@karr/config"
1+
import { getClient, getCallbackUrl } from "@karr/auth/client"
2+
import { lazy } from "@karr/config"
33

4-
const c = lazy(() => getRuntimeClient(APP_URL, API_BASE))
4+
const c = lazy(async () => await getClient())
5+
const u = lazy(async () => await getCallbackUrl())
56

6-
export const { client, callbackUrl } = c.value
7+
export const client = await c.value
8+
export const callbackUrl = await u.value

apps/api/src/routes/auth/issuer.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ import sqlite from "db0/connectors/node-sqlite"
1212
import dbDriver from "unstorage/drivers/db0"
1313

1414
import { subjects } from "@karr/auth/subjects"
15-
import { API_BASE } from "@karr/config"
15+
import { API_BASE, APP_URL } from "@karr/config"
1616
import { logger } from "@karr/util/logger"
1717

1818
import { callbackUrl, client } from "@/lib/auth-client"
1919
import { responseErrorObject } from "@/lib/helpers"
2020
import { UnStorage } from "./unstorage-adapter"
21+
import { authBaseUrl } from "@karr/auth/client"
2122

2223
async function getUser(provider: string, email: string) {
2324
console.log(provider, email)
@@ -49,7 +50,7 @@ const THEME_OPENAUTH: Theme = {
4950
}
5051

5152
const app = issuer({
52-
basePath: `${API_BASE}/auth`,
53+
basePath: authBaseUrl(API_BASE),
5354
select: Select({
5455
providers: {
5556
github: {
@@ -112,6 +113,15 @@ const app = issuer({
112113
}
113114
})
114115

116+
app.get("/test", async (ctx) => {
117+
logger.debug("Test route", ctx.req.url)
118+
logger.debug("callbackUrl", callbackUrl)
119+
logger.debug("app url", APP_URL)
120+
logger.debug("auth base", authBaseUrl(API_BASE))
121+
logger.debug("auth base with app url", authBaseUrl(API_BASE, APP_URL))
122+
return ctx.json({ message: "Hello, world!" })
123+
})
124+
115125
app.get("/callback", async (ctx) => {
116126
const url = new URL(ctx.req.url)
117127
const code = ctx.req.query("code")

apps/web/Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ LABEL repository="https://github.com/finxol/karr"
55
ENV NEXT_TELEMETRY_DISABLED=1
66
ENV TURBO_TELEMETRY_DISABLED=1
77
ENV HUSKY=0
8-
# The port that the api listens to.
9-
ENV APP_URL=http://localhost
108
ENV DOCKER=1
119

1210
ENV PNPM_HOME="/pnpm"
@@ -43,6 +41,8 @@ COPY --from=installer /app/out/json/ .
4341
RUN pnpm install --frozen-lockfile
4442

4543
ENV NODE_ENV=production
44+
# Set required config values for the build
45+
ENV APP_URL=http://buildtime
4646

4747
# Build the project
4848
COPY --from=installer /app/out/full/ .

apps/web/next.config.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import createNextIntlPlugin from "next-intl/plugin"
22

3-
import { API_BASE, APP_URL } from "@karr/config"
3+
import { API_BASE } from "@karr/config"
44

55
const withNextIntl = createNextIntlPlugin()
66

@@ -14,8 +14,7 @@ const nextConfig = {
1414
"/**/*.css": ["src/assets/**/*.css"]
1515
},
1616
env: {
17-
NEXT_PUBLIC_API_BASE: API_BASE,
18-
NEXT_PUBLIC_APP_URL: APP_URL
17+
NEXT_PUBLIC_API_BASE: API_BASE
1918
},
2019

2120
experimental: {

apps/web/src/app/auth/actions.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,20 @@
22

33
import { cookies } from "next/headers"
44
import { getLocale } from "next-intl/server"
5+
import { Tokens } from "@openauthjs/openauth/client"
56

6-
import { client, callbackUrl } from "@/app/auth/client"
7+
import { getClient, getCallbackUrl } from "@karr/auth/client"
78
import { subjects } from "@karr/auth/subjects"
89

910
import { redirect } from "@/i18n/routing"
1011

11-
import { Tokens } from "@openauthjs/openauth/client"
12-
1312
export async function auth() {
1413
const jar = await cookies()
1514
const accessToken = jar.get("access_token")
1615
const refreshToken = jar.get("refresh_token")
1716

17+
const client = await getClient()
18+
1819
if (!accessToken) {
1920
return false
2021
}
@@ -40,6 +41,9 @@ export async function login() {
4041
const accessToken = jar.get("access_token")
4142
const refreshToken = jar.get("refresh_token")
4243

44+
const client = await getClient()
45+
const callbackUrl = await getCallbackUrl()
46+
4347
if (accessToken) {
4448
const verified = await client.verify(subjects, accessToken.value, {
4549
refresh: refreshToken?.value

apps/web/src/app/auth/client.ts

Lines changed: 0 additions & 11 deletions
This file was deleted.

compose-dev.yml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,7 @@ services:
44
context: .
55
dockerfile: ./apps/web/Dockerfile
66
environment:
7-
- LOG_LEVEL=debug
87
- CONFIG_DIR=/app/config
9-
- API=http://api:1993
108
- PORT=3000
119
ports:
1210
- 3000:3000
@@ -22,7 +20,6 @@ services:
2220
secrets:
2321
- db-password
2422
environment:
25-
- LOG_LEVEL=debug
2623
- CONFIG_DIR=/app/config
2724
- DB_HOST=db
2825
- DB_USER=postgres
@@ -56,7 +53,7 @@ services:
5653
dockerfile: Dockerfile
5754
restart: unless-stopped
5855
ports:
59-
- 80:80
56+
- 8080:8080
6057
#- "443:443"
6158
#- "443:443/udp"
6259
environment:

packages/auth/src/client.ts

Lines changed: 28 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { createClient, type ClientInput } from "@openauthjs/openauth/client"
1+
import { createClient } from "@openauthjs/openauth/client"
22
import { logger } from "@karr/util/logger"
33

44
/**
@@ -20,40 +20,46 @@ export const clientID = "karr"
2020
* @param apiBase - The base path of the API (e.g., /api/v1)
2121
* @returns The full issuer URL
2222
*/
23-
export const authBaseUrl = (appUrl: string, apiBase: string) => {
23+
export const authBaseUrl = (apiBase: string, appUrl?: string) => {
24+
const path = `${apiBase.replace(/\/$/, "")}${issuerPath}`
25+
if (!appUrl) return path
26+
2427
const url = new URL(appUrl)
25-
url.pathname = `${apiBase.replace(/\/$/, "")}${issuerPath}`
28+
url.pathname = path
2629
return url.toString()
2730
}
2831

2932
/**
3033
* Constructs the full callback URL based on the runtime issuer URL.
31-
* @param issuerUrl - The full base URL of the OpenAuth issuer (e.g., http://localhost:8080/api/v1/auth)
3234
* @returns The full callback URL
3335
*/
34-
function getRuntimeCallbackUrl(issuerUrl: string) {
36+
export async function getCallbackUrl() {
37+
const { APP_URL, API_BASE } = await import("@karr/config")
38+
39+
const issuerUrl = authBaseUrl(API_BASE, APP_URL)
40+
3541
if (!issuerUrl) {
3642
logger.error("Issuer URL must be provided at runtime to getCallbackUrl.")
3743
return ""
3844
}
39-
// Ensure issuerUrl doesn't have a trailing slash before appending
40-
const cleanIssuerUrl = issuerUrl.replace(/\/$/, "")
41-
return `${cleanIssuerUrl}${callbackPath}`
45+
const callbackUrl = `${issuerUrl.replace(/\/$/, "")}${callbackPath}`
46+
47+
if (!callbackUrl) {
48+
logger.error("Failed to initialize callback URL.")
49+
process.exit(1)
50+
}
51+
52+
return callbackUrl
4253
}
4354

4455
/**
4556
* Creates an auth client instance configured with the runtime issuer URL.
46-
* @param appUrl - The base URL of the app (e.g., http://localhost)
47-
* @param apiBase - The base path of the API (e.g., /api/v1)
48-
* @param options - Optional additional client options
4957
* @returns An initialized OpenAuth client and the callback URL
5058
*/
51-
export function getRuntimeClient(
52-
appUrl: string,
53-
apiBase: string,
54-
options?: Omit<ClientInput, "issuer" | "clientID">
55-
) {
56-
const issuerUrl = authBaseUrl(appUrl, apiBase)
59+
export async function getClient() {
60+
const { APP_URL, API_BASE } = await import("@karr/config")
61+
62+
const issuerUrl = authBaseUrl(API_BASE, APP_URL)
5763

5864
if (!issuerUrl) {
5965
logger.error("Issuer URL must be provided at runtime to getClient.")
@@ -63,19 +69,16 @@ export function getRuntimeClient(
6369
const client = createClient({
6470
clientID,
6571
issuer: issuerUrl,
66-
...options
72+
fetch: (url, options) => {
73+
logger.debug("fetch", url, options)
74+
return fetch(url, options)
75+
}
6776
})
68-
const callbackUrl = getRuntimeCallbackUrl(issuerUrl)
6977

7078
if (!client) {
7179
logger.error("Failed to initialize OpenAuth client.")
7280
process.exit(1)
7381
}
7482

75-
if (!callbackUrl) {
76-
logger.error("Failed to initialize callback URL.")
77-
process.exit(1)
78-
}
79-
80-
return { client, callbackUrl }
83+
return client
8184
}

0 commit comments

Comments
 (0)