Skip to content

Commit

Permalink
Merge pull request #189 from manchenkoff/188-csrf-token-error
Browse files Browse the repository at this point in the history
fix: prevent concurrent update of request headers
  • Loading branch information
manchenkoff authored Oct 1, 2024
2 parents 7810a4c + c5af530 commit 79ab8f1
Show file tree
Hide file tree
Showing 3 changed files with 22 additions and 25 deletions.
9 changes: 4 additions & 5 deletions src/runtime/interceptors/common/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@ export default async function handleRequestHeaders(
): Promise<void> {
const method = ctx.options.method?.toLowerCase() ?? 'get'

if (!ctx.options.headers) {
ctx.options.headers = {}
}

Object.assign(ctx.options.headers!, { Accept: 'application/json' })
ctx.options.headers = Object.assign(
ctx.options.headers || {},
{ Accept: 'application/json' },
)

// https://laravel.com/docs/10.x/routing#form-method-spoofing
if (method === 'put' && ctx.options.body instanceof FormData) {
Expand Down
33 changes: 14 additions & 19 deletions src/runtime/interceptors/cookie/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,7 @@ import type { FetchContext } from 'ofetch'
import type { ConsolaInstance } from 'consola'
import { useSanctumConfig } from '../../composables/useSanctumConfig'
import type { ModuleOptions } from '../../types/options'
import {
useCookie,
useRequestHeaders,
useRequestURL,
type NuxtApp,
} from '#app'
import { type NuxtApp, useCookie, useRequestHeaders, useRequestURL } from '#app'

const SECURE_METHODS = new Set(['post', 'delete', 'put', 'patch'])
const COOKIE_OPTIONS: { readonly: true } = { readonly: true }
Expand All @@ -17,15 +12,15 @@ const COOKIE_OPTIONS: { readonly: true } = { readonly: true }
* @param headers Headers collection to extend
* @param config Module configuration
*/
function appendServerHeaders(
headers: HeadersInit,
function useServerHeaders(
headers: HeadersInit | undefined,
config: ModuleOptions,
): void {
): HeadersInit {
const clientHeaders = useRequestHeaders(['cookie', 'user-agent'])
const origin = config.origin ?? useRequestURL().origin

Object.assign(
headers,
return Object.assign(
headers || {},
{
Referer: origin,
Origin: origin,
Expand Down Expand Up @@ -60,10 +55,10 @@ async function initCsrfCookie(
* @param logger Logger instance
*/
async function useCsrfHeader(
headers: HeadersInit,
headers: HeadersInit | undefined,
config: ModuleOptions,
logger: ConsolaInstance,
): Promise<void> {
): Promise<HeadersInit> {
let csrfToken = useCookie(config.csrf.cookie!, COOKIE_OPTIONS)

if (!csrfToken.value) {
Expand All @@ -77,13 +72,13 @@ async function useCsrfHeader(
`${config.csrf.cookie} cookie is missing, unable to set ${config.csrf.header} header`,
)

return
return headers || {}
}

logger.debug(`Added ${config.csrf.header} header to pass to the API`)

Object.assign(
headers,
return Object.assign(
headers || {},
{ [config.csrf.header!]: csrfToken.value },
)
}
Expand All @@ -102,12 +97,12 @@ export default async function handleRequestCookies(
const method = ctx.options.method?.toLowerCase() ?? 'get'

if (import.meta.server) {
appendServerHeaders(ctx.options.headers!, config)
ctx.options.headers = useServerHeaders(ctx.options.headers, config)
}

if (SECURE_METHODS.has(method)) {
await useCsrfHeader(
ctx.options.headers!,
ctx.options.headers = await useCsrfHeader(
ctx.options.headers,
config,
logger,
)
Expand Down
5 changes: 4 additions & 1 deletion src/runtime/interceptors/token/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,10 @@ export default async function handleRequestTokenHeader(
return
}

Object.assign(ctx.options.headers!, { Authorization: `Bearer ${token}` })
ctx.options.headers = Object.assign(
ctx.options.headers || {},
{ Authorization: `Bearer ${token}` },
)

logger.debug(
'[handleRequestTokenHeader] headers modified',
Expand Down

0 comments on commit 79ab8f1

Please sign in to comment.