1

Im using Auth0 to authenticate users.

Im protected api routes like this:

// pages/api/secret.js

import { withApiAuthRequired, getSession } from '@auth0/nextjs-auth0';

export default withApiAuthRequired(function ProtectedRoute(req, res) {
  const session = getSession(req, res);
  const data = { test: 'test' };
  res.json({ data });
});

My problem is when I'm trying to fetch the data from getServerSideProps I'm getting 401 error code.

If I use useEffect Im able to get data from api route.

Im trying to fetch the data like this:

export const getServerSideProps = withPageAuthRequired({
  async getServerSideProps(ctx) {
    const res = await fetch('http://localhost:3000/api/secret');
    const data = await res.json();

    return { props: { data } };
  },
});

Im getting the following response: error: "not_authenticated", description: "The user does not have an active session or is not authenticated"

Any idea guys? Thanks!!

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Manos
  • 35
  • 1
  • 8
  • You should use the logic that's in your API routes directly in `getServerSideProps` rather than fetching from your internal API. See [Internal API fetch with getServerSideProps? (Next.js)](https://stackoverflow.com/a/65760948/1870780) for more details. – juliomalves Jun 20 '21 at 13:48
  • I see. I will check it! Thanks you very much! – Manos Jun 20 '21 at 13:59

2 Answers2

5

When you call from getServerSideProps the protected API end-point you are not passing any user's context (such as Cookies) to the request, therefore, you are not authenticated.

When you call from useEffect it runs inside your browser, which attaches all cookies to the request, one of them is the session cookie.

You need to forward the session cookie that was passed to the getServerSideProps (by the browser) to the API call.

export const getServerSideProps = withPageAuthRequired({
  async getServerSideProps(ctx) {
    const res = await fetch('http://localhost:3000/api/secret', {
      headers: { Cookie: ctx.req.headers.cookie },
// ---------------------------^ this req is the browser request to the getServersideProps
    });
    const data = await res.json();

    return { props: { data } };
  },
});

For more info.

felixmosh
  • 32,615
  • 9
  • 69
  • 88
  • Thanks you very much for your answer! As you can imagine I'm not a professional. Im learning by internet. I added this line and now Im gettinig: TypeError: ctx.req.getHeader is not a function – Manos Jun 20 '21 at 14:00
  • 1
    I change it to ctx.req.headers.cookie and now its working! Thanks you very much! – Manos Jun 20 '21 at 14:04
  • This resolved my issue, but Auth0's docs don't address this. WithApiRequired and withPageAuthRequired work together to provide the session info when not fetching data in getServerSideProps, but with my internal API call I had the same issue as the user. Maybe not mentioning the need for the header was an oversight on the docs? https://auth0.github.io/nextjs-auth0/modules/helpers_with_page_auth_required.html – Chris Aug 09 '22 at 07:29
0

@auth0/nextjs-auth0 has useUser hook. This example is from: https://auth0.com/blog/ultimate-guide-nextjs-authentication-auth0/

// pages/index.js
import { useUser } from '@auth0/nextjs-auth0';

export default () => {
  const { user, error, isLoading } = useUser();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>{error.message}</div>;

  if (user) {
    return (
      <div>
        Welcome {user.name}! <a href="/api/auth/logout">Logout</a>
      </div>
    );
  }
  // if not user 
  return <a href="/api/auth/login">Login</a>;
};

Note that authentication takes place on the server in this model, meaning that the client isn't aware that the user is logged in. The useUser hook makes it aware by accessing that information in the initial state or through the /api/auth/profile endpoint, but it won't expose any id_token or access_token to the client. That information remains on the server side.

Custom HOF:

// getData is a callback function
export const withAuth = (getData) => async ({req, res}) => {
  const session = await auth0.getSession(req);
  if (!session || !session.user) {
    res.writeHead(302, {
      Location: '/api/v1/login'
    });
    res.end();
    return {props: {}};
  }

  const data = getData ? await getData({req, res}, session.user) : {};

  return {props: {user: session.user, ...data}}
}

Example of using:

export const getServerSideProps = withAuth(async ({req, res}, user) => {
  const title = await getTitle();
  return title;
});
Yilmaz
  • 35,338
  • 10
  • 157
  • 202