Add Authorization Header via server middleware in Nuxt3

156 Views Asked by At

I've setup a simple Nuxt3 server api route that calls a third party api. The third party api required a access_token that is refreshed by a refresh_token saved in the .env file. To not expose it to the client application, the client application should call the server route /api/products which then calls the third party backend like this:

/api/products.get.ts

export default defineEventHandler(async (event) => {
  const apiUrl = `https://www.xxx.eu/Products?fields=Product_Name&per_page=1`;
  const data = await $fetch(apiUrl, {
    method: "GET"
  }).catch((err) => {
    throw createError({
      statusCode: err.status,
      statusMessage: "Error fetching data from API",
      data: err,
    });
  });

  return data;
});

Because the third party API needs an access token authorization that shouldn't be exposed to the client side and might need to be refreshed upon expiry, I added a server middleware and a server utility:

middleware/checkAuth.ts

export default defineEventHandler(async (event) => {
  const apiRoute = event.node.req.url?.startsWith("/api");
  if (apiRoute) {
    let access_token = await useStorage().getItem("auth:access_token");
    const expiry: number|null = await useStorage().getItem("auth:expiry");
    const now = Date.now();
    if (!expiry || now > expiry - 60 * 1000) { // Fetch new token before expiry
      console.log("refreshing token");
      access_token = await refreshToken();
    }
    event.node.req.headers.Authorization = `Bearer ${access_token}`;
  }
});

utils/refreshToken.ts

interface AuthData {
  access_token: string;
  api_domain: string;
  token_type: string;
  expires_in: number;
}

export default async function () {
  const apiUrl = `https://xxx.eu/oauth/v2/token?` +
    `client_id=${process.env.CLIENT_ID}` +
    `&client_secret=${process.env.CLIENT_SECRET}` +
    `&refresh_token=${process.env.REFRESH_TOKEN}` +
    `&grant_type=refresh_token`;
  const authData = (await $fetch(apiUrl, {
    method: "POST"
  }).catch((err) => {
    throw createError({
      statusCode: err.status,
      message: "Error",
      statusMessage: "Error refreshing access token from API",
      data: err,
    });
  })) as AuthData | any;
  await useStorage().setItem("auth:access_token", authData.access_token);
  await useStorage().setItem("auth:expiry", Date.now() + 3600 * 1000); // 60 minutes expiry
  return authData.access_token;
}

For some crazy reason event.node.req.headers.Authorization = `Bearer ${access_token}`; does not add that header to the request. Whaaat am I doing wrong? I'm aware that I can set the token directly in the $fetch options but it should work in the middleware as well, right? Please help.

0

There are 0 best solutions below