fix: cookie stuff
This commit is contained in:
parent
f10772084d
commit
329a71931b
@ -7,15 +7,32 @@ function getSharedCookieDomain(req: NextRequest): string | undefined {
|
|||||||
return host.endsWith('profit-planet.partners') ? '.profit-planet.partners' : undefined
|
return host.endsWith('profit-planet.partners') ? '.profit-planet.partners' : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function splitSetCookieHeader(header: string): string[] {
|
||||||
|
const parts: string[] = []
|
||||||
|
let start = 0
|
||||||
|
let inExpires = false
|
||||||
|
for (let i = 0; i < header.length; i++) {
|
||||||
|
const lower = header.slice(i, i + 8).toLowerCase()
|
||||||
|
if (lower === 'expires=') inExpires = true
|
||||||
|
if (inExpires && header[i] === ';') inExpires = false
|
||||||
|
if (!inExpires && header[i] === ',') {
|
||||||
|
parts.push(header.slice(start, i).trim())
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const last = header.slice(start).trim()
|
||||||
|
if (last) parts.push(last)
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
function readSetCookies(res: Response): string[] {
|
function readSetCookies(res: Response): string[] {
|
||||||
const anyHeaders = res.headers as any
|
const anyHeaders = res.headers as any
|
||||||
if (typeof anyHeaders.getSetCookie === 'function') return anyHeaders.getSetCookie()
|
if (typeof anyHeaders.getSetCookie === 'function') return anyHeaders.getSetCookie()
|
||||||
const single = res.headers.get('set-cookie')
|
const single = res.headers.get('set-cookie')
|
||||||
return single ? [single] : []
|
return single ? splitSetCookieHeader(single) : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRefreshCookie(setCookie: string) {
|
function parseRefreshCookie(setCookie: string) {
|
||||||
// refreshToken=VALUE; Max-Age=...; Expires=...; SameSite=...; ...
|
|
||||||
const m = setCookie.match(/^refreshToken=([^;]*)/i)
|
const m = setCookie.match(/^refreshToken=([^;]*)/i)
|
||||||
if (!m) return null
|
if (!m) return null
|
||||||
const value = m[1] ?? ''
|
const value = m[1] ?? ''
|
||||||
@ -52,7 +69,23 @@ export async function POST(req: NextRequest) {
|
|||||||
const refreshSetCookie = setCookies.find((c) => /^refreshToken=/i.test(c))
|
const refreshSetCookie = setCookies.find((c) => /^refreshToken=/i.test(c))
|
||||||
if (refreshSetCookie) {
|
if (refreshSetCookie) {
|
||||||
const parsed = parseRefreshCookie(refreshSetCookie)
|
const parsed = parseRefreshCookie(refreshSetCookie)
|
||||||
if (parsed) {
|
if (parsed?.value) {
|
||||||
|
// Clear host-only duplicates first.
|
||||||
|
out.cookies.set('refreshToken', '', {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
maxAge: 0,
|
||||||
|
})
|
||||||
|
out.cookies.set('__Secure-refreshToken', '', {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
maxAge: 0,
|
||||||
|
})
|
||||||
|
|
||||||
out.cookies.set('refreshToken', parsed.value, {
|
out.cookies.set('refreshToken', parsed.value, {
|
||||||
domain: getSharedCookieDomain(req),
|
domain: getSharedCookieDomain(req),
|
||||||
path: '/',
|
path: '/',
|
||||||
|
|||||||
@ -28,6 +28,12 @@ export async function POST(req: NextRequest) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const out = NextResponse.json(data, { status })
|
const out = NextResponse.json(data, { status })
|
||||||
|
|
||||||
|
// Clear host-only variants
|
||||||
|
out.cookies.set('refreshToken', '', { path: '/', httpOnly: true, secure: true, sameSite: 'lax', maxAge: 0 })
|
||||||
|
out.cookies.set('__Secure-refreshToken', '', { path: '/', httpOnly: true, secure: true, sameSite: 'lax', maxAge: 0 })
|
||||||
|
|
||||||
|
// Clear shared-domain variant
|
||||||
out.cookies.set('refreshToken', '', {
|
out.cookies.set('refreshToken', '', {
|
||||||
domain: getSharedCookieDomain(req),
|
domain: getSharedCookieDomain(req),
|
||||||
path: '/',
|
path: '/',
|
||||||
@ -36,5 +42,6 @@ export async function POST(req: NextRequest) {
|
|||||||
sameSite: 'lax',
|
sameSite: 'lax',
|
||||||
maxAge: 0,
|
maxAge: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,11 +7,30 @@ function getSharedCookieDomain(req: NextRequest): string | undefined {
|
|||||||
return host.endsWith('profit-planet.partners') ? '.profit-planet.partners' : undefined
|
return host.endsWith('profit-planet.partners') ? '.profit-planet.partners' : undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function splitSetCookieHeader(header: string): string[] {
|
||||||
|
// Handles "Expires=Wed, 21 Oct ..." commas.
|
||||||
|
const parts: string[] = []
|
||||||
|
let start = 0
|
||||||
|
let inExpires = false
|
||||||
|
for (let i = 0; i < header.length; i++) {
|
||||||
|
const lower = header.slice(i, i + 8).toLowerCase()
|
||||||
|
if (lower === 'expires=') inExpires = true
|
||||||
|
if (inExpires && header[i] === ';') inExpires = false
|
||||||
|
if (!inExpires && header[i] === ',') {
|
||||||
|
parts.push(header.slice(start, i).trim())
|
||||||
|
start = i + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const last = header.slice(start).trim()
|
||||||
|
if (last) parts.push(last)
|
||||||
|
return parts
|
||||||
|
}
|
||||||
|
|
||||||
function readSetCookies(res: Response): string[] {
|
function readSetCookies(res: Response): string[] {
|
||||||
const anyHeaders = res.headers as any
|
const anyHeaders = res.headers as any
|
||||||
if (typeof anyHeaders.getSetCookie === 'function') return anyHeaders.getSetCookie()
|
if (typeof anyHeaders.getSetCookie === 'function') return anyHeaders.getSetCookie()
|
||||||
const single = res.headers.get('set-cookie')
|
const single = res.headers.get('set-cookie')
|
||||||
return single ? [single] : []
|
return single ? splitSetCookieHeader(single) : []
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseRefreshCookie(setCookie: string) {
|
function parseRefreshCookie(setCookie: string) {
|
||||||
@ -35,11 +54,24 @@ export async function POST(req: NextRequest) {
|
|||||||
const apiBase = process.env.NEXT_PUBLIC_API_BASE_URL
|
const apiBase = process.env.NEXT_PUBLIC_API_BASE_URL
|
||||||
if (!apiBase) return NextResponse.json({ message: 'Missing NEXT_PUBLIC_API_BASE_URL' }, { status: 500 })
|
if (!apiBase) return NextResponse.json({ message: 'Missing NEXT_PUBLIC_API_BASE_URL' }, { status: 500 })
|
||||||
|
|
||||||
const cookie = req.headers.get('cookie') ?? ''
|
// Prefer a single parsed cookie value to avoid "refreshToken=old; refreshToken=new" ambiguity.
|
||||||
|
const rt =
|
||||||
|
req.cookies.get('refreshToken')?.value ??
|
||||||
|
req.cookies.get('__Secure-refreshToken')?.value ??
|
||||||
|
''
|
||||||
|
|
||||||
|
const headers: Record<string, string> = {}
|
||||||
|
if (rt) {
|
||||||
|
headers.cookie = `refreshToken=${rt}`
|
||||||
|
} else {
|
||||||
|
// fallback (best-effort)
|
||||||
|
const cookie = req.headers.get('cookie') ?? ''
|
||||||
|
if (cookie) headers.cookie = cookie
|
||||||
|
}
|
||||||
|
|
||||||
const apiRes = await fetch(`${apiBase}/api/refresh`, {
|
const apiRes = await fetch(`${apiBase}/api/refresh`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { cookie },
|
headers,
|
||||||
cache: 'no-store',
|
cache: 'no-store',
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -50,7 +82,24 @@ export async function POST(req: NextRequest) {
|
|||||||
const refreshSetCookie = setCookies.find((c) => /^refreshToken=/i.test(c))
|
const refreshSetCookie = setCookies.find((c) => /^refreshToken=/i.test(c))
|
||||||
if (refreshSetCookie) {
|
if (refreshSetCookie) {
|
||||||
const parsed = parseRefreshCookie(refreshSetCookie)
|
const parsed = parseRefreshCookie(refreshSetCookie)
|
||||||
if (parsed) {
|
if (parsed?.value) {
|
||||||
|
// Clear any host-only variants on the frontend host to prevent duplicates.
|
||||||
|
out.cookies.set('refreshToken', '', {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
maxAge: 0,
|
||||||
|
})
|
||||||
|
out.cookies.set('__Secure-refreshToken', '', {
|
||||||
|
path: '/',
|
||||||
|
httpOnly: true,
|
||||||
|
secure: true,
|
||||||
|
sameSite: 'lax',
|
||||||
|
maxAge: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Set the shared-domain cookie used across subdomains.
|
||||||
out.cookies.set('refreshToken', parsed.value, {
|
out.cookies.set('refreshToken', parsed.value, {
|
||||||
domain: getSharedCookieDomain(req),
|
domain: getSharedCookieDomain(req),
|
||||||
path: '/',
|
path: '/',
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user