Twan
Twan
TTCTheo's Typesafe Cult
Created by Twan on 10/9/2024 in #questions
Authorization with External API
Hi all, I'm working on a project that consists of a mobile application in React Native and a desktop application in NextJS. I was hoping to be able to share an API between these two applications, so I've built one in NestJS for this purpose. I am trying to implement auth flow into a NextJS project. Currently, I am facing an issue: When I log in - I'm able to generate an access and refresh token just fine, but once it expires, I have to refresh twice because the refresh call doesn't appear ready in time prior to the API being called from the page component, thus resulting in an unauthorized error.
middleware.ts

export const refreshSession = async () => {
const refresh_token = cookies().get('refresh_token')?.value;

if (!refresh_token) return;

const { headers } = await fetch('http://localhost:3000/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
cookie: cookies().toString(),
},
body: null,
credentials: 'include',
});

const setCookie = headers.get('set-cookie');

if (!setCookie) return;

const res = NextResponse.next();
res.headers.append('set-cookie', setCookie);

return res;
};

export async function middleware() {
return await refreshSession();
}
middleware.ts

export const refreshSession = async () => {
const refresh_token = cookies().get('refresh_token')?.value;

if (!refresh_token) return;

const { headers } = await fetch('http://localhost:3000/api/auth/refresh', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
cookie: cookies().toString(),
},
body: null,
credentials: 'include',
});

const setCookie = headers.get('set-cookie');

if (!setCookie) return;

const res = NextResponse.next();
res.headers.append('set-cookie', setCookie);

return res;
};

export async function middleware() {
return await refreshSession();
}
Page.tsx

export async function getUser() {
const res = await fetch('http://localhost:3000/api/users/me', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
cookie: cookies().toString(),
},
body: null,
credentials: 'include',
});

if (res.status !== 200) return;

const session = await res.json();

return session;
}

export default async function Page() {
const session = await getUser();

return (
<section>
<LoginForm />

<pre>{JSON.stringify(session, null, 2)}</pre>
</section>
);
}
Page.tsx

export async function getUser() {
const res = await fetch('http://localhost:3000/api/users/me', {
method: 'GET',
headers: {
'Content-Type': 'application/json',
cookie: cookies().toString(),
},
body: null,
credentials: 'include',
});

if (res.status !== 200) return;

const session = await res.json();

return session;
}

export default async function Page() {
const session = await getUser();

return (
<section>
<LoginForm />

<pre>{JSON.stringify(session, null, 2)}</pre>
</section>
);
}
3 replies