N
Nuxt8mo ago
data

[OPEN] Working example of access/refresh token auth?

I didn't think this would be so complicated when I first started reading into Nuxt but after 4 different rewrite attempts I'm now a bit confused on whether it even makes sense. Does anyone have any resources or examples of an authentication flow where users are given an access token and refresh token? The features I'm looking for are: - Token rotation on expiration - Token invalidation - Server api guards (h3 layer) - Route guards (nuxt layer) & composables Because I want to load user data of private routes on the server, i need to always check if an access token is expired on each request... this means, that token rotation and expiration checking can be left entirely up to the server and the client no longer needs to worry about refreshing. This flow is very strange to me and non-standard from what i've been able to read, but I thought maybe this is what SSR-first apps need... Right now I have a working implementation that does all of the above (except route guards/composables), the server checks and rotates tokens on each request and then forwards the set-cookie header to nuxt, which uses appendResponseHeader and useRequestHeaders(['cookie']) in a custom fetch wrapper to forward cookies properly. However this does not work when user presses the back button, I get a weird node error, but in general I am very unhappy with this solution it feels hacky. Maybe token refresh is just not the move for an SSR environment? Would love to hear what you think, this is a major roadblock for me. I have also looked into Auth.js and sidebase-auth but they seem overkill for the simplicity I want and they seem to have the same weird edge cases.
1 Reply
data
dataOP8mo ago
My $fetch wrapper:
export async function useFetchCookie<T = unknown, R extends NitroFetchRequest = NitroFetchRequest, O extends NitroFetchOptions<R> = NitroFetchOptions<R>>(event: H3Event, request: R, opts?: O) {

const res = await $fetch.raw<T>(request, {
...opts,
headers: { ...opts?.headers, ...useRequestHeaders(['cookie']) },
})

// forward cookies into SSR response
const cookies = (res.headers.get('set-cookie') || '').split(',')
for (const cookie of cookies)
appendResponseHeader(event, 'set-cookie', cookie)

// Return the data of the response
return res._data
}
export async function useFetchCookie<T = unknown, R extends NitroFetchRequest = NitroFetchRequest, O extends NitroFetchOptions<R> = NitroFetchOptions<R>>(event: H3Event, request: R, opts?: O) {

const res = await $fetch.raw<T>(request, {
...opts,
headers: { ...opts?.headers, ...useRequestHeaders(['cookie']) },
})

// forward cookies into SSR response
const cookies = (res.headers.get('set-cookie') || '').split(',')
for (const cookie of cookies)
appendResponseHeader(event, 'set-cookie', cookie)

// Return the data of the response
return res._data
}
:Sadge::Jepinged:
Want results from more Discord servers?
Add your server