1.0.21 • Published 10 months ago

next-interceptor v1.0.21

Weekly downloads
-
License
-
Repository
-
Last release
10 months ago

Server Side Interceptor

Description

Server side interceptor for server components. Handles refresh rotation essentially.

Requirements

  • Next 13 or Above (App Router)

Instructions

  • yarn add next-interceptor

add esmExternals: "loose" on next config experimental.

(coming soon)

next-interceptor assumes:

  • the developer has already set an access token cookie on the client side after successful login...
  • the developer has an express middleware already in place to add to routes.

Example Usage

export async function storeToken(request: StoreTokenRequest) {
  "use server";
  cookies().set({
    name: request.name,
    value: request.token,
    httpOnly: true,
    sameSite: "strict",
    secure: true,
  });
}

Create a client side wrapper that sets the cookie on client side. This can be used to synchronize access and refresh tokens from the server to the client.

"use client";

import { ReactNode, useEffect } from "react";
import { storeToken } from "./cookie";
import React from "react";

type TokenType = {
  name: string;
  token: string;
};

type CookieWrapperType = {
  children: ReactNode;
  refreshToken: TokenType;
  accessToken: TokenType;
};

function useCookie({ token, name }: TokenType): void {
  useEffect(() => {
    if (!name || token === undefined) return;
    storeToken({ name: name, token: token });
  }, [token, name]);
  return;
}

/**
 *
 * This can be used to synchronize access and refresh tokens from the server to the client.
 */

export function CookieWrapper({
  children,
  refreshToken = { name: "", token: "" },
  accessToken = { name: "", token: "" },
}: CookieWrapperType) {
  useCookie?.({
    name: refreshToken?.name,
    token: refreshToken?.token,
  });
  useCookie?.({
    name: accessToken?.name,
    token: accessToken?.token,
  });
  return <>{children}</>;
}
import { nextIntercepor } from "next-interceptor";

const fetchInterceptor = nextIntercepor({
  base_url: "http://localhost:5001", // this is the base url were express server is running.
  refresh_token_name: "refreshToken", // this matches my express api response property -> refreshToken.
  access_token_name: "accessToken", // this also matches my express api response property -> accessToken.
  refresh_url: "api/v1/users/refresh", // this is the url that points to my express refresh token api.
});


// remember that we need an accessToken present in client side cookies.

export default async function Home() {
  const getUser = async () => {
    try {
      const data = await fetchInterceptor("/api/v1/users/current_user", {
        method: "GET",
        has_authorization_token: true,
      });
      return data;
    } catch (error) {
      console.error("Error fetching data:", error);
    }
  };

  const data = await getUser();

  return (

    <CookieWrapper
      accessToken={data?.accessToken as any}
      refreshToken={data?.refreshToken as any}
    >
      test
    </CookieWrapper>
  );
}

Express (server) refesh token example

export async function refresh(req: Request, res: Response) {
  try {
    const refreshToken = req.header("RefreshToken") as string; // note: Header must match RefreshToken.

    const [err, result] = await verifyToken(refreshToken, "REFRESH_SECRET");

    if (err) {
      return auth401(res, "invalidToken");
    }

    const dbToken = await PRISMA_DB.token.findFirst({
      where: {
        user_id: result?.id,
        expired_at: {
          gte: new Date(),
        },
      } as any,
    });

    if (!dbToken) {
      return auth401(res, "unAuthenticated");
    }

    /**
     * generates new access token upon every refresh request which
     */

    const { access_token } = await signToken(result);

    return res.status(200).send({
      accessToken: access_token,
      refreshToken: refreshToken,
      status: 200,
    });
  } catch (error) {
    return auth401(res, "expiredToken");
  }
}
1.0.19

10 months ago

1.0.18

10 months ago

1.0.1-8.beta

10 months ago

1.0.16

10 months ago

1.0.1-7.beta

10 months ago

1.0.1-9.beta

10 months ago

1.0.11

10 months ago

1.0.21

10 months ago

1.0.20

10 months ago

1.0.15

10 months ago

1.0.13

10 months ago

1.0.12

10 months ago

1.0.10

11 months ago

1.0.9

12 months ago

1.0.8

12 months ago

1.0.7

12 months ago

1.0.6

12 months ago

1.0.5

12 months ago

1.0.4-test

12 months ago

1.0.3

12 months ago

1.0.1

12 months ago

1.0.0

12 months ago