Next.js Discord

Discord Forum

getServerSideProps with app & next-auth

Answered
Mugger Crocodile posted this in #help-forum
Open in Discord
Mugger CrocodileOP
I've read the docs and this hasn't really helped with what I need to do to solve the error nextjs throws
import type {
    GetServerSidePropsContext,
    InferGetServerSidePropsType,
} from "next";
import { getProviders, signIn } from "next-auth/react";
import { auth } from "~/lib/auth.ts";

export default function SignIn({
    providers,
}: InferGetServerSidePropsType<typeof getServerSideProps>) {
    return (
        <>
            {Object.values(providers).map((provider) => (
                <div key={provider.name}>
                    <button onClick={() => signIn(provider.id)}>
                Sign in here with {provider.name}
                    </button>
                </div>
            ))}
        </>
    );
}

export async function getServerSideProps(context: GetServerSidePropsContext) {
    const session = await auth(context);

    // If the user is already logged in, redirect.
    // Note: Make sure not to redirect to the same page
    // To avoid an infinite loop!
    if (session) {
        return { redirect: { destination: "/account/guilds/" } };
    }

    const providers = await getProviders();

    return {
        props: { providers: providers ?? [] },
    };
}
Answered by Ray
app router doesn't have getServerSideProps, you could move the work in getServerSideProps to the component body instead
View full answer

77 Replies

Mugger CrocodileOP
oh sorry. lemme get the full error message
Import trace for requested module:
./src/app/account/signin/page.tsx
 ⨯ ./src/app/account/signin/page.tsx
Error: 
  × "getServerSideProps" is not supported in app/. Read more: https://nextjs.org/docs/app/building-your-application/data-fetching
  │ 
  │ 
    ╭─[/Users/USER/PATH/TO/WEBSITE/CODE/src/app/account/signin/page.tsx:21:1]
 21 │   );
 22 │ }
 23 │ 
 24 │ export async function getServerSideProps(context: GetServerSidePropsContext) {
    ·                       ──────────────────
 25 │   const session = await auth(context);
 26 │ 
 27 │   // If the user is already logged in, redirect.
    ╰────
├── @prisma/client@5.8.1
├── @types/next-auth@3.15.0
├── @types/node@20.11.6
├── @types/react@18.2.48
├── @types/react-dom@18.2.18
├── bun-types@1.0.25
├── dotenv@16.4.0
├── eslint@8.56.0
├── eslint-config-next@14.0.4
├── next@14.1.0
├── next-auth@5.0.0-beta.5
├── prisma@5.8.1
├── react@18.2.0
├── react-dom@18.2.0
└── typescript@5.3.3

Using bun
packages shown above
Mugger CrocodileOP
anyone have any ideas?
@Mugger Crocodile anyone have any ideas?
app router doesn't have getServerSideProps, you could move the work in getServerSideProps to the component body instead
Answer
Mugger CrocodileOP
sorry wdym?
ive understand that the app router doesnt have getServerSideProps, but wdym by move it into... getServerSideProps
move the work in getServerSideProps to the component body
Mugger CrocodileOP
oh... ok so like this?
export default function SignIn() {
    // getServerSideProps
    return (
        <>
            {Object.values(providers).map((provider) => (
                <div key={provider.name}>
                    <button onClick={() => signIn(provider.id)}>
                Sign in here with {provider.name}
                    </button>
                </div>
            ))}
        </>
    );
}
@Mugger Crocodile oh... ok so like this? ts export default function SignIn() { // getServerSideProps return ( <> {Object.values(providers).map((provider) => ( <div key={provider.name}> <button onClick={() => signIn(provider.id)}> Sign in here with {provider.name} </button> </div> ))} </> ); }
export default async function SignIn() {
    const session = await auth();

    // If the user is already logged in, redirect.
    // Note: Make sure not to redirect to the same page
    // To avoid an infinite loop!
    if (session) {
        redirect("/account/guilds/")
    }

    const providers = await getProviders();

    return (
        <>
            {Object.values(providers).map((provider) => (
                <div key={provider.name}>
                    <button onClick={() => signIn(provider.id)}>
                Sign in here with {provider.name}
                    </button>
                </div>
            ))}
        </>
    );
}
Mugger CrocodileOP
ah ok... ill see if that works. thank you for the help
the context is no longer typed. how can i get that to work
Mugger CrocodileOP
ok. thanks
⨯ src/app/account/signin/page.tsx (15:37) @ getProviders
 ⨯ TypeError: (0 , next_auth_react__WEBPACK_IMPORTED_MODULE_1__.getProviders) is not a function
    at SignIn (./src/app/account/signin/page.tsx:22:90)
  13 |  }
  14 |
> 15 |  const providers = await getProviders();
     |                                     ^
  16 |
  17 |  if (!providers) {
  18 |          return redirect("/");
Mugger CrocodileOP
so i need to put "use client" ?
@Mugger Crocodile so i need to put "use client" ?
yes but create a client component in other file
and leave the page component to server component so you could use server side code
Mugger CrocodileOP
ok. i'll look into this. thanks
@Mugger Crocodile ok. i'll look into this. thanks
export default async function SignIn() {
    const session = await auth();

    // If the user is already logged in, redirect.
    // Note: Make sure not to redirect to the same page
    // To avoid an infinite loop!
    if (session) {
        redirect("/account/guilds/")
    }

    return <SignInForm />
}

// signin-form.tsx
'use client';

export default function SignInForm() {
  const providers = getProviders();

  return (
      <>
          {Object.values(providers).map((provider) => (
              <div key={provider.name}>
                  <button onClick={() => signIn(provider.id)}>
              Sign in here with {provider.name}
                  </button>
              </div>
          ))}
      </>
  );
}
Mugger CrocodileOP
should the providers be in the signin... as its async
@Mugger Crocodile should the providers be in the signin... as its async
oh wait, does it return the promise?
Mugger CrocodileOP
ye
@Ray oh wait, does it return the promise?
Mugger CrocodileOP
auth and getProviders both return a promise. i think
@Mugger Crocodile `auth` and `getProviders` both return a promise. i think
where are you importing getProviders from?
Mugger CrocodileOP
next-auth/react
look like it is not exist in next-auth@beta
Mugger CrocodileOP
unfortunate
ok thank you for helping out though
@Ray no prob
Mugger CrocodileOP
getCsrfToken and getProviders are still available as imports, but we plan to deprecate them in the future and introduce a new API to get this data server-side.

Client-side: Instead of using these APIs, you can make a fetch request to the /api/auth/providers and /api/auth/csrf endpoints respectively.
oh ok, so you could make a request to /api/auth/providers
Mugger CrocodileOP
oh... sounds simple enough
@Mugger Crocodile oh... sounds simple enough
btw, if you fetch on server side, you need fetch with absolute url
Mugger CrocodileOP
ah ok
so like http://localhost:3000/api/auth/providers
@Mugger Crocodile so like `http://localhost:3000/api/auth/providers`
yeah its better to set a env variable it because it is going to be different when you deploy the site
Mugger CrocodileOP
ok.
do you recommend axois for this, plain js or nextjs stuff (if they have one)
Mugger CrocodileOP
idk. im making a get request no?
Mugger CrocodileOP
ok.
Mugger CrocodileOP
also in this:
export default async function SignIn() {
    const session = await auth();

    // If the user is already logged in, redirect.
    // Note: Make sure not to redirect to the same page
    // To avoid an infinite loop!
    if (session) {
        return redirect("/account/guilds/");
    }

    const providers = await fetch("")

    if (!providers) {
        return redirect("/");
    }

    <SignInForm />;
}

dont i need to pass anything in the `<SignInForm /> so that the client side has the providers
Mugger CrocodileOP
sorry, this is gonna sound stupid. how do i do that
@Mugger Crocodile sorry, this is gonna sound stupid. how do i do that
<SignInForm providers={providers} />
Mugger CrocodileOP
im getting an error:
Type '{ providers: Response; }' is not assignable to type 'IntrinsicAttributes'.
  Property 'providers' does not exist on type 'IntrinsicAttributes'.ts(2322
Mugger CrocodileOP
how would that look on the client side
 const providersResponse = await fetch("")
 const providers = await providersResponse.json()
Mugger CrocodileOP
as in here export default function SignInForm() {
Mugger CrocodileOP
how do i have the data on the client side
Mugger CrocodileOP
like dis? export default function SignInForm({ providers }) {
Mugger CrocodileOP
and what type do i give it?
@Mugger Crocodile and what type do i give it?
I don't know, log the providers to console
Mugger CrocodileOP
{"discord":{"id":"discord","name":"Discord","type":"oauth","signinUrl":"http://localhost:3000/api/auth/signin/discord","callbackUrl":"http://localhost:3000/api/auth/callback/discord"}}
this is the response json data
i went to the api page
should i create a custom type for this?
Mugger CrocodileOP
ok
type Provider = {
  id: string,
  name: string,
  type: string,
  signinUrl: string,
  callbackUrl: string
}

does that look good
Mugger CrocodileOP
ive done this:
"use client";

import { signIn } from "next-auth/react";

type Provider = {
    id: string,
    name: string,
    type: string,
    signinUrl: string,
    callbackUrl: string
}

export default function SignInForm({ providers }: { providers: Provider[] }) {
    return (
        <>
            {Object.values(providers).map((provider) => (
                <div key={provider.name}>
                    <button onClick={() => signIn(provider.id)}>
                Sign in here with {provider.name}
                    </button>
                </div>
            ))}
        </>
    );
}
Mugger CrocodileOP
the page doesnt render the stuff
"use server";

import { redirect } from "next/navigation";
import { auth } from "~/lib/auth.ts";
import SignInForm from "~/Components/Auth/signin-form.tsx";

export default async function SignIn() {
    const session = await auth();

    // If the user is already logged in, redirect.
    // Note: Make sure not to redirect to the same page
    // To avoid an infinite loop!
    if (session) {
        return redirect("/account/guilds/");
    }

    const providerResponse = await fetch("http://localhost:3000/api/auth/providers");

    if (!providerResponse.ok) {
        return redirect("/");
    }

    const data = await providerResponse.json();

    console.log(data);

    <SignInForm providers={data}/>;
}

"use client";

import { signIn } from "next-auth/react";

type Provider = {
    id: string,
    name: string,
    type: string,
    signinUrl: string,
    callbackUrl: string
}

export default function SignInForm({ providers }: { providers: Provider[] }) {
    return (
        <>
            {Object.values(providers).map((provider) => (
                <div key={provider.name}>
                    <button onClick={() => signIn(provider.id)}>
                Sign in here with {provider.name}
                    </button>
                </div>
            ))}
        </>
    );
}
Mugger CrocodileOP
oml im so stupid
yeah it works now
thanks so much