# SSR (Remix) onError: how to redirect to login from a link?

**URL:** <https://community.apollographql.com/t/ssr-remix-onerror-how-to-redirect-to-login-from-a-link/6852>\
**Category:** Client SDKs\
**Tags:** client, web\
**Created:** [October 17, 2023, 10:06am UTC](https://community.apollographql.com/t/ssr-remix-onerror-how-to-redirect-to-login-from-a-link/6852 "2023-10-17T10:06:28Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![davidesigner](https://avatars.discourse-cdn.com/v4/letter/d/8e7dd6/32.png) [@davidesigner](https://community.apollographql.com/u/davidesigner)\
**Post date:** [October 17, 2023, 10:06am UTC](https://community.apollographql.com/t/ssr-remix-onerror-how-to-redirect-to-login-from-a-link/6852/1 "2023-10-17T10:06:28Z")

</div>

Hi there,

I am looking to redirect the user to the login page when a GQL API call throw an UNAUTHENTICATED error.

Note that my stack is Remix (SSR) and GQL is running on the server side.

Here is my code (redirect not working):

```ts
import https from "https";
import { onError } from "@apollo/client/link/error";
import { fromPromise } from "@apollo/client";
import { redirect, redirectDocument } from "@remix-run/node";
import { authTokenCookie } from "~/cookies.server";

async function authenticate(request: Request) {
  const payload: { token: string; isLoggedIn: boolean } = await fetch(
    `https://domain.tld/api/remix/auth-token`,
    {
      agent: new https.Agent({
        rejectUnauthorized: process.env.NODE_ENV !== "development",
      }),
      headers: {
        cookie: request.headers.get("cookie"),
      },
    } as RequestInit,
  )
    .then((response) => response.json())
    .catch((error) => {
      console.error(error);
      return null;
    });

  if (!payload.isLoggedIn) {
    // Redirect to login form.
    throw redirectDocument(
      `https://domain.tld/login?_target_path=${new URL(request.url).href}`,
    );
  }

  // Update the token cookie for future requests.
  throw redirect(request.url, {
    headers: {
      "Set-Cookie": await authTokenCookie.serialize(payload.token),
    },
  });
}

async function createClient(request: Request) {
  const cookieHeader = request.headers.get("Cookie");
  const authToken = cookieHeader ? await authTokenCookie.parse(cookieHeader) : null;

  if (!authToken) {
    throw await authenticate(request);
  }

  const httpLink = createHttpLink({
    uri: "https://domain.tld/api/gql",
    fetch, // Import from node-fetch, don't know why that is not working without this declaration...
    fetchOptions: {
      agent: new https.Agent({
        rejectUnauthorized: process.env.NODE_ENV !== "development",
      }),
    },
  });

  const authLink = setContext((_, { headers }) => {
    return {
      headers: {
        ...headers,
        cookie: cookieHeader ? await sessionCookie.parse(cookieHeader) : null,
        authorization: `Bearer ${authToken}`,
      },
    };
  });

  const errorLink = onError(({ graphQLErrors, operation, forward }) => {
    const isAuthenticationError = graphQLErrors?.some((error) => {
      return error.extensions.code === "UNAUTHENTICATED";
    });

    // If it's an unauthenticated error, we refresh the token cookie (if the user is logged in) or we redirect the user to the login form.
    if (isAuthenticationError) {
      // THIS REDIRECT IS NOT WORKING...
      return fromPromise(authenticate(request))
        .filter((value) => Boolean(value))
        .flatMap(() => {
          return forward(operation);
        });
    }

    // If that's another error, we log it to console.
    if (graphQLErrors) {
      graphQLErrors.forEach((error) => {
        console.error(
          `[GraphQL error]: ${error.message}`,
          error,
        );
      });
    }
  });

  const retryLink = new RetryLink({
    delay: {
      initial: 300,
      max: 500,
      jitter: true,
    },
    attempts: {
      max: 3,
      retryIf: (error, _operation) => !!error,
    },
  });

  const links = [authLink, errorLink, retryLink, httpLink];

  return new ApolloClient({
    ssrMode: true,
    cache: createApolloCache(),
    link: from(links),
    connectToDevTools: process.env.NODE_ENV === "development",
  });
}

```

PS: I tried to add a `redirect: "follow"` to `fetchOptions` but that is not working neither.

Is it possible to make a http redirect from an Apollo link?

Thanks for your help!  
David

---

<div class="post-metadata">

**Author:** ![Justin\_Gonzalez](https://sea1.discourse-cdn.com/flex019/user_avatar/community.apollographql.com/justin_gonzalez/32/5359_2.png) [@Justin\_Gonzalez](https://community.apollographql.com/u/Justin_Gonzalez)\
**Post date:** [February 6, 2025, 8:48pm UTC](https://community.apollographql.com/t/ssr-remix-onerror-how-to-redirect-to-login-from-a-link/6852/2 "2025-02-06T20:48:13Z")

</div>

Archived on February 6, 2025, 8:48pm UTC


