Skip to content

Commit 326781e

Browse files
committed
fix: do a correct implementation of getServerBaseUrl
1 parent c4d3826 commit 326781e

File tree

4 files changed

+44
-29
lines changed

4 files changed

+44
-29
lines changed

src/runtime/composables/authjs/useAuth.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,6 @@ async function getSession(getSessionOptions?: GetSessionOptions): Promise<Sessio
188188
}
189189

190190
const headers = await getRequestHeaders(nuxt)
191-
console.log('BEFORE doing fetch', headers)
192191

193192
return _fetch<SessionData>(nuxt, '/session', {
194193
onResponse: ({ response }) => {

src/runtime/server/plugins/assertOrigin.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
*/
44
import type { NitroApp } from 'nitropack/types'
55
import { ERROR_MESSAGES } from '../services/errors'
6-
import { isProduction } from '../../helpers'
7-
import { getServerOrigin } from '../services/authjs/utils'
6+
import { isProduction, useTypedBackendConfig } from '../../helpers'
7+
import { getServerBaseUrl } from '../services/authjs/utils'
88
import { useRuntimeConfig } from '#imports'
99

1010
// type stub
@@ -18,7 +18,8 @@ function defineNitroPlugin(def: NitroAppPlugin): NitroAppPlugin {
1818
export default defineNitroPlugin(() => {
1919
try {
2020
const runtimeConfig = useRuntimeConfig()
21-
getServerOrigin(runtimeConfig)
21+
const trustHostUserPreference = useTypedBackendConfig(runtimeConfig, 'authjs').trustHost
22+
getServerBaseUrl(runtimeConfig, false, trustHostUserPreference, isProduction)
2223
}
2324
catch (error) {
2425
if (!isProduction) {

src/runtime/server/services/authjs/nuxtAuthHandler.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import { defu } from 'defu'
1313
import { joinURL } from 'ufo'
1414
import { ERROR_MESSAGES } from '../errors'
1515
import { isNonEmptyObject } from '../../../utils/checkSessionResult'
16-
import { useTypedBackendConfig } from '../../../helpers'
16+
import { isProduction, useTypedBackendConfig } from '../../../helpers'
1717
import { resolveApiBaseURL } from '../../../utils/url'
18-
import { getHostValueForAuthjs, getServerOrigin } from './utils'
18+
import { getHostValueForAuthjs, getServerBaseUrl } from './utils'
1919
import { useRuntimeConfig } from '#imports'
2020

2121
type RuntimeConfig = ReturnType<typeof useRuntimeConfig>
@@ -45,7 +45,7 @@ export function NuxtAuthHandler(nuxtAuthOptions?: AuthOptions) {
4545
logger: undefined,
4646
providers: [],
4747

48-
// SAFETY: We trust host here because `getRequestURLFromH3Event` is responsible for producing a trusted URL
48+
// SAFETY: We trust host here because `getHostValueForAuthjs` is responsible for producing a trusted URL
4949
trustHost: true,
5050

5151
// AuthJS uses `/auth` as default, but we rely on `/api/auth` (same as in previous `next-auth`)
@@ -133,7 +133,7 @@ export async function getServerSession(event: H3Event) {
133133
cookies: parseCookies(event),
134134
providerId: undefined,
135135
error: undefined,
136-
host: getHostValueForAuthjs(event, runtimeConfig, trustHostUserPreference),
136+
host: getHostValueForAuthjs(event, runtimeConfig, trustHostUserPreference, isProduction),
137137
query: {}
138138
}
139139

@@ -162,6 +162,7 @@ export async function getServerSession(event: H3Event) {
162162
*/
163163
export function getToken<R extends boolean = false>({ event, secureCookie, secret, ...rest }: Omit<GetTokenParams<R>, 'req'> & { event: H3Event }) {
164164
const runtimeConfig = useRuntimeConfig()
165+
const trustHostUserPreference = useTypedBackendConfig(runtimeConfig, 'authjs').trustHost
165166

166167
return authjsGetToken({
167168
// @ts-expect-error As our request is not a real next-auth request, we pass down only what's required for the method, as per code from https://github.com/nextauthjs/next-auth/blob/8387c78e3fef13350d8a8c6102caeeb05c70a650/packages/next-auth/src/jwt/index.ts#L68
@@ -170,7 +171,7 @@ export function getToken<R extends boolean = false>({ event, secureCookie, secre
170171
headers: getHeaders(event) as IncomingHttpHeaders
171172
},
172173
// see https://github.com/nextauthjs/next-auth/blob/8387c78e3fef13350d8a8c6102caeeb05c70a650/packages/next-auth/src/jwt/index.ts#L73
173-
secureCookie: secureCookie ?? getServerOrigin(runtimeConfig, event).startsWith('https://'),
174+
secureCookie: secureCookie ?? getServerBaseUrl(runtimeConfig, false, trustHostUserPreference, isProduction, event).startsWith('https://'),
174175
secret: secret || usedSecret,
175176
...rest
176177
})
@@ -189,7 +190,7 @@ async function createRequestForAuthjs(
189190
): Promise<RequestInternal> {
190191
const nextRequest: Omit<RequestInternal, 'action'> = {
191192
// `authjs` expects the baseURL here despite the param name
192-
host: getHostValueForAuthjs(event, runtimeConfig, trustHostUserPreference),
193+
host: getHostValueForAuthjs(event, runtimeConfig, trustHostUserPreference, isProduction),
193194
body: undefined,
194195
cookies: parseCookies(event),
195196
query: undefined,

src/runtime/server/services/authjs/utils.ts

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import type { H3Event } from 'h3'
2-
import getURL from 'requrl'
3-
import { parseURL } from 'ufo'
4-
import { isProduction } from '../../../helpers'
2+
import { getRequestURL } from 'h3'
3+
import { parseURL, withLeadingSlash } from 'ufo'
54
import { type RuntimeConfig, resolveApiBaseURL } from '../../../utils/url'
65
import { ERROR_MESSAGES } from '../errors'
76

@@ -28,31 +27,33 @@ import { ERROR_MESSAGES } from '../errors'
2827
*
2928
* @param event The H3 Event containing the request
3029
* @param runtimeConfig Nuxt RuntimeConfig
31-
* @param trustHost Whether the host can be trusted. If `true`, base will be inferred from the request, otherwise the configured origin will be used. * @returns {string} Value formatted for usage with Authjs
30+
* @param trustHostUserPreference Whether the host can be trusted. If `true`, base will be inferred from the request, otherwise the configured origin will be used. * @returns {string} Value formatted for usage with Authjs
3231
* @throws {Error} When server origin was incorrectly configured or when URL building failed
3332
*/
3433
export function getHostValueForAuthjs(
3534
event: H3Event,
3635
runtimeConfig: RuntimeConfig,
37-
trustHost: boolean,
36+
trustHostUserPreference: boolean,
37+
isProduction: boolean
3838
): string {
39-
if (trustHost) {
40-
return getServerBaseUrl(runtimeConfig, true, event)
41-
}
42-
43-
return resolveApiBaseURL(runtimeConfig, false)
39+
return getServerBaseUrl(runtimeConfig, true, trustHostUserPreference, isProduction, event)
4440
}
4541

4642
/**
47-
* Get `origin` and fallback to `x-forwarded-host` or `host` headers if not in production.
43+
* Get the full base URL including Origin and pathname
44+
*
45+
* @param runtimeConfig Nuxt Runtime Config
46+
* @param includePath Whether function should output just Origin or the full URL
47+
* @param trustHostUserPreference Whether the host can be trusted. If `true`, base will be inferred from the request, otherwise the configured origin will be used. * @returns {string} Value formatted for usage with Authjs
48+
* @param isProduction Whether app is running in production mode. In non-production mode function will try to infer the result from the passed event.
49+
* @param event The H3 Event for inferring the result (optional)
50+
* @throws {Error} When the calculated result did not include a valid Origin, e.g. it will throw for the result of `/api/auth`, but will succeed for `https://example.com/api/auth`
4851
*/
49-
export function getServerOrigin(runtimeConfig: RuntimeConfig, event?: H3Event): string {
50-
return getServerBaseUrl(runtimeConfig, false, event)
51-
}
52-
53-
function getServerBaseUrl(
52+
export function getServerBaseUrl(
5453
runtimeConfig: RuntimeConfig,
5554
includePath: boolean,
55+
trustHostUserPreference: boolean,
56+
isProduction: boolean,
5657
event?: H3Event,
5758
): string {
5859
// Prio 1: Environment variable
@@ -69,9 +70,22 @@ function getServerBaseUrl(
6970
: base
7071
}
7172

72-
// Prio 3: Try to infer the origin if we're not in production
73-
if (event && !isProduction) {
74-
return getURL(event.node.req, includePath)
73+
// Prio 3: Try to infer the origin if we're not in production or if user trusts host
74+
if (event && (!isProduction || trustHostUserPreference)) {
75+
const requestUrl = getRequestURL(event, {
76+
xForwardedHost: trustHostUserPreference,
77+
xForwardedProto: trustHostUserPreference || undefined
78+
})
79+
80+
if (!includePath) {
81+
return requestUrl.origin
82+
}
83+
84+
// When path is needed, use the preconfigured base path instead of parsing request's pathname
85+
const basePath = withLeadingSlash(parsed.pathname)
86+
requestUrl.pathname = basePath
87+
88+
return requestUrl.href
7589
}
7690

7791
throw new Error(ERROR_MESSAGES.NO_ORIGIN)

0 commit comments

Comments
 (0)