Jump to content

Attention: This page is 28 days older than the English version and might be outdated. If you're a native speaker of this language and would like to contribute to the project, please consider updating this page to match the latest English version.

You can also view the English version of this page.

NextAuth.js

Quando voc√™ deseja um sistema de autentica√ß√£o em sua aplica√ß√£o Next.js, o NextAuth.js √© uma excelente solu√ß√£o para trazer a complexidade da seguran√ßa sem o inc√īmodo de ter que constru√≠-lo sozinho. Ele vem com uma extensa lista de provedores para adicionar rapidamente a autentica√ß√£o OAuth e fornece adaptadores para muitos bancos de dados e ORMs.

Context Provider

No ponto de entrada do seu aplicativo, você verá que ele está envolvida pelo SessionProvider↗:

pages/_app.tsx
<SessionProvider session={session}>
  <Component {...pageProps} />
</SessionProvider>

Este provedor de contexto permite que seu aplicativo acesse os dados da sess√£o de qualquer lugar em seu aplicativo, sem ter que pass√°-los como props:

pages/users/[id].tsx
import { useSession } from "next-auth/react";

const User = () => {
  const { data: session } = useSession();

  if (!session) {
    // Lida com o estado n√£o autenticado, por exemplo renderizar um componente SignIn
    return <SignIn />;
  }

  return <p>Bem-vindo {session.user.name}!</p>;
};

Recuperando a sess√£o do lado do servidor.

Às vezes, você poderá querer solicitar a sessão no servidor. Para fazer isso, faça uma requisição usando o utilitário getServerAuthSession que create-t3-app fornece e passe-a para o cliente usando getServerSideProps:

pages/users/[id].tsx
import { getServerAuthSession } from "../server/auth";
import { type GetServerSideProps } from "next";

export const getServerSideProps: GetServerSideProps = async (ctx) => {
  const session = await getServerAuthSession(ctx);
  return {
    props: { session },
  };
};

const User = () => {
  const { data: session } = useSession();
  // NOTA: `session` não terá um estado de carregamento, pois já foi pré-carregado no servidor

  ...
}

Inclus√£o do user.id na Sess√£o

create-t3-app está configurado para utilizar o retorno de chamada de sessão (sesion callback)↗ na configuração NextAuth.js para incluir o ID do usuário dentro do objeto session.

pages/api/auth/[...nextauth].ts
callbacks: {
    session({ session, user }) {
      if (session.user) {
        session.user.id = user.id;
      }
      return session;
    },
  },

Isso é acoplado a um arquivo de declaração de tipo para garantir que o user.id tenha seu tipo quando acessado no objeto session. Leia mais sobre Module Augmentation↗ nos documentos de NextAuth.js.

types/next-auth.d.ts
import { DefaultSession } from "next-auth";

declare module "next-auth" {
  interface Session {
    user?: {
      id: string;
    } & DefaultSession["user"];
  }
}

O mesmo padr√£o pode ser usado para adicionar quaisquer outros dados ao objeto session, como um campo role, mas n√£o deve ser mal utilizado para armazenar dados confidenciais no cliente.

Uso com tRPC

Ao usar NextAuth.js com tRPC, você pode criar procedimentos protegidos e reutilizáveis usando middleware↗. Isso permite criar procedimentos que só podem ser acessados por usuários autenticados. create-t3-app configura tudo isso para você, permitindo que você acesse facilmente o objeto de sessão dentro de procedimentos autenticados.

Isso é feito em um processo de duas etapas:

  1. Pegar a sessão dos headers da request usando a função getServerSession↗. A vantagem de usar getServerSession em vez do getSession regular é que é uma função que é executada somente do lado do servidor e não faz chamadas de busca desnecessárias. O create-t3-app cria uma função auxiliar que abstrai essa API peculiar.
server/common/get-server-auth-session.ts
export const getServerAuthSession = async (ctx: {
  req: GetServerSidePropsContext["req"];
  res: GetServerSidePropsContext["res"];
}) => {
  return await getServerSession(ctx.req, ctx.res, nextAuthOptions);
};

Usando esta função auxiliar, podemos pegar a sessão e passá-la para o contexto tRPC:

server/trpc/context.ts
import { getServerAuthSession } from "../common/get-server-auth-session";

export const createContext = async (opts: CreateNextContextOptions) => {
  const { req, res } = opts;
  const session = await getServerAuthSession({ req, res });
  return await createContextInner({
    session,
  });
};
  1. Criar um middleware tRPC que verifique se o usuário está autenticado. Em seguida, usamos o middleware em um protectedProcedure. Qualquer chamador para esses procedimentos deve ser autenticado, caso contrário, será lançado um erro que pode ser tratado adequadamente pelo cliente.
server/trpc/trpc.ts
const isAuthed = t.middleware(({ ctx, next }) => {
  if (!ctx.session || !ctx.session.user) {
    throw new TRPCError({ code: "UNAUTHORIZED" });
  }
  return next({
    ctx: {
      // Infere `session` como n√£o-nulo
      session: { ...ctx.session, user: ctx.session.user },
    },
  });
});

export const protectedProcedure = t.procedure.use(isAuthed);

O objeto de sessão é uma representação leve e mínima do usuário e contém apenas alguns campos. Ao usar protectedProcedures, você tem acesso ao id do usuário que pode ser usado para buscar mais dados do banco de dados.

server/trpc/router/user.ts
const userRouter = router({
  me: protectedProcedure.query(async ({ ctx }) => {
    const user = await prisma.user.findUnique({
      where: {
        id: ctx.session.user.id,
      },
    });
    return user;
  }),
});

Uso com Prisma

Fazer o NextAuth.js funcionar com o Prisma requer muita configuração inicial↗. O create-t3-app lida com tudo isso para você e, se você selecionar Prisma e NextAuth.js, obterá um sistema de autenticação totalmente funcional com todos os modelos necessários pré-configurados. Enviamos seu aplicativo montado com um provedor do Discord OAuth pré-configurado, que escolhemos porque é um dos mais fáceis de começar - basta fornecer seus tokens no .env e pronto. No entanto, você pode adicionar facilmente mais provedores seguindo a documentação do NextAuth.js↗. Observe que certos provedores exigem que campos extras sejam adicionados a determinados modelos. Recomendamos que você leia a documentação do provedor que deseja usar para certificar-se de que possui todos os campos obrigatórios.

Adicionando novos campos aos seus modelos

Ao adicionar novos campos a qualquer um dos modelos User, Account, Session ou VerificationToken (provavelmente você só precisaria modificar o modelo User), você precisa ter em mente que o Adaptador Prisma↗ cria campos automaticamente nesses modelos quando novos usuários se inscrevem e fazem login. Portanto, ao adicionar novos campos a esses modelos, você deve fornecer padrão valores para eles, pois o adaptador não está ciente desses campos.

Se, por exemplo, você quiser adicionar um role (cargo) ao modelo User, você precisará fornecer um valor padrão para o campo role. Isso é feito adicionando um valor @default ao campo role no modelo User:

prisma/schema.prisma
+ enum Role {
+   USER
+   ADMIN
+ }

  model User {
    ...
+   role Role @default(USER)
  }

Uso com o middleware Next.js

Uso de NextAuth.js com middleware Next.js requer o uso da estratégia de sessão JWT↗ para autenticação. Isso ocorre porque o middleware só consegue acessar o cookie da sessão se for um JWT. Por padrão, create-t3-app é configurado para usar a estratégia de banco de dados padrão, em combinação com o Prisma como o adaptador de banco de dados.

Configurando o DiscordProvider padr√£o

  1. V√° para a se√ß√£o Aplicativos no Portal do desenvolvedor do Discord‚Üó e clique em ‚ÄúNovo aplicativo‚ÄĚ
  2. No menu de configura√ß√Ķes, v√° para ‚ÄúOAuth2 => Geral‚ÄĚ
  • Copie o Client ID e cole-o em DISCORD_CLIENT_ID em .env.
  • Em Client Secret, clique em ‚ÄúReset Secret‚ÄĚ e copie essa string para DISCORD_CLIENT_SECRET em .env. Tenha cuidado, pois voc√™ n√£o poder√° ver esse segredo novamente e redefini-lo far√° com que o existente expire.
  • Clique em ‚ÄúAdd Redirect‚ÄĚ e cole em <app url>/api/auth/callback/discord (exemplo para desenvolvimento local: http://localhost:3000/api/auth/callback/discord‚Üó)
  • Salve suas altera√ß√Ķes
  • √Č poss√≠vel, mas n√£o recomendado, usar o mesmo aplicativo Discord tanto para desenvolvimento quanto para produ√ß√£o. Voc√™ tamb√©m pode considerar mockar o Provider‚Üó durante o desenvolvimento.

Recursos √öteis

RecursoLink
Documentação do NextAuth.jshttps://next-auth.js.org/↗
GitHub do NextAuth.jshttps://github.com/nextauthjs/next-auth‚Üó
tRPC Kitchen Sink - com NextAuthhttps://kitchen-sink.trpc.io/next-auth‚Üó