Handling expired/cut session_id
Unanswered
Tornjak posted this in #help-forum
TornjakOP
Hi everyone,
I am currently working on a Next.js application in which I use NextAuth to log in and create a guest session. When entering the page, a unique session_id is generated, which I have to attach to the header of each request to the external API.
The first problem I encounter is the session. (Currently, the duration of these sessions is set to the same on the API and NEXT sides) - it is still far from ideal, but for now it is enough.
The second problem: access to resources
All resources require a valid session_id. When the session on the API side expires or is deleted, each request returns 401 Unauthorized and throws an exception.
Here the problem is a bit more complicated because I have X API endpoints and X server actions. These functions sometimes throw exceptions, which leads to the application crashing (errors are not handled properly).
What I would like to achieve if possible is:
Automatic session refresh, on the first 401. That is, catch the error, refresh what is needed and re-query with a new session_id.
As I mentioned, I have this X (quite a lot) and I don't want to write it in every endpoint. I tried to make some wrapper but here I had a problem updating cookies. Some code below to better illustrate the situation:
I am currently working on a Next.js application in which I use NextAuth to log in and create a guest session. When entering the page, a unique session_id is generated, which I have to attach to the header of each request to the external API.
The first problem I encounter is the session. (Currently, the duration of these sessions is set to the same on the API and NEXT sides) - it is still far from ideal, but for now it is enough.
The second problem: access to resources
All resources require a valid session_id. When the session on the API side expires or is deleted, each request returns 401 Unauthorized and throws an exception.
Here the problem is a bit more complicated because I have X API endpoints and X server actions. These functions sometimes throw exceptions, which leads to the application crashing (errors are not handled properly).
What I would like to achieve if possible is:
Automatic session refresh, on the first 401. That is, catch the error, refresh what is needed and re-query with a new session_id.
As I mentioned, I have this X (quite a lot) and I don't want to write it in every endpoint. I tried to make some wrapper but here I had a problem updating cookies. Some code below to better illustrate the situation:
export default async function RootLayout({ children }: { children: React.ReactNode }) {
const session = await auth()
const SESSION_ID = session?.user?.data?.session_id
const countries = await getCountriesData(SESSION_ID)
return (
<html suppressHydrationWarning lang={locale} className={poppins.variable}>
<body suppressHydrationWarning>
<NextAuthProvider session={session}>
...
</NextAuthProvider>
</body>
</html>
)
}
2 Replies
TornjakOP
server action:
NEXT API ENDPOINT:
'use server'
import { BASE_URL } from '@/config'
import { CountryOption, Country } from '@/types/FormsTypes'
export const getCountriesData = async (SESSION_ID: string): Promise<CountryOption[]> => {
try {
const response = await fetch(`${BASE_URL}/api/dictionary/country`, {
method: 'GET',
cache: 'no-store',
headers: {
accept: 'application/json',
'X-SESSION-ID': SESSION_ID,
},
})
if (!response.ok) {
throw new Error('Błąd podczas pobierania danych o krajach')
}
const countries: Country[] = await response.json()
return countries.map((country) => ({
symbol: country.ikraje,
name: country.okraje.PL,
dostawa_wg_ikody: country.dostawa_wg_ikody,
}))
} catch (error) {
console.error('Error fetching countries:', error)
return []
}
}
NEXT API ENDPOINT:
import { NextRequest, NextResponse } from 'next/server'
import { fetchCountries } from '@/actions/dictionary/dictionary-actions'
import { auth } from '@/helpers/auth'
export const dynamic = 'force-dynamic'
export async function GET(req: NextRequest): Promise<NextResponse> {
try {
const SESSION_ID = req.headers.get('X-SESSION-ID') || (await auth())?.user.data.session_id
if (!SESSION_ID) {
return new NextResponse(JSON.stringify({ error: 'Autoryzacja zakończona niepowodzeniem' }), { status: 401 })
}
const countries = await fetchCountries(SESSION_ID)
return new NextResponse(JSON.stringify(countries), {
status: 200,
headers: { 'Content-Type': 'application/json' },
})
} catch (e) {
console.error('No authorization', e)
return new NextResponse('No authorization', { status: 500 })
}
}
server action again:
I have many questions, not necessarily many answers.
I would like to do something great at the lowest possible cost.
I have already tried to create something like this:
but here I have a problem, how can I update the cookie from next auth.
export const fetchCountries = async (SESSION_ID: string): Promise<CountriesProps> => {
try {
const response = await fetch(`${API_URL}/dictionary/country`, {
method: 'GET',
cache: 'no-store',
headers: {
Accept: 'application/json',
'X-SESSION-ID': SESSION_ID,
},
})
if (!response.ok) {
const errorMessage = await response.text()
console.error('Failed to fetch countries data', errorMessage)
throw new Error('Failed to fetch countries data')
}
const { data: countries } = await response.json()
return countries as CountriesProps
} catch (e) {
console.error('Error fetching countries data:', e)
throw e
}
}
I have many questions, not necessarily many answers.
I would like to do something great at the lowest possible cost.
I have already tried to create something like this:
'use server'
export async function fetchWithAuthServer(url: string, options?: RequestInit) {
const response = await fetch(url, options)
if (response.status === 401) {
throw new Error('Unauthorized')
}
return response
}
but here I have a problem, how can I update the cookie from next auth.