www/src/pages/en/usage/_next-auth-app-router.mdx
import Callout from "../../../components/docs/callout.tsx"; import Tabs from "../../../components/docs/tabs.astro";
<Callout type="warning"> The newest version of NextAuth has migrated to [Auth.js](https://authjs.dev/) </Callout>Sometimes you might want to request the session on the server. To do so, use the auth helper function that create-t3-app provides.
import { auth } from "~/server/auth";
export default async function Home() {
const session = await auth();
...
}
user.id on the SessionCreate T3 App is configured to utilise the session callback in the NextAuth.js config to include the user's ID within the session object.
callbacks: {
session: ({ session, user }) => ({
...session,
user: {
...session.user,
id: user.id,
},
}),
},
This is coupled with a type declaration file to make sure the user.id is typed when accessed on the session object. Read more about Module Augmentation on NextAuth.js's docs.
import { DefaultSession } from "next-auth";
declare module "next-auth" {
interface Session extends DefaultSession {
user: {
id: string;
} & DefaultSession["user"];
}
The same pattern can be used to add any other data to the session object, such as a role field, but should not be misused to store sensitive data on the client.
When using NextAuth.js with tRPC, you can create reusable, protected procedures using middleware. This allows you to create procedures that can only be accessed by authenticated users. create-t3-app sets all of this up for you, allowing you to easily access the session object within authenticated procedures.
This is done in a two step process:
import { auth } from "~/server/auth";
import { db } from "~/server/db";
export const createTRPCContext = async (opts: { headers: Headers }) => {
const session = await auth();
return {
db,
session,
...opts,
};
};
protectedProcedure. Any caller to these procedures must be authenticated, or else an error will be thrown which can be appropriately handled by the client.export const protectedProcedure = t.procedure
.use(({ ctx, next }) => {
if (!ctx.session?.user) {
throw new TRPCError({ code: "UNAUTHORIZED" });
}
return next({
ctx: {
session: { ...ctx.session, user: ctx.session.user },
},
});
});
The session object is a light, minimal representation of the user and only contains a few fields. When using the protectedProcedures, you have access to the user's id which can be used to fetch more data from the database.
const userRouter = router({
me: protectedProcedure.query(async ({ ctx }) => {
const user = await prisma.user.findUnique({
where: {
id: ctx.session.user.id,
},
});
return user;
}),
});
When adding new fields to any of the User, Account, Session, or VerificationToken models (most likely you'd only need to modify the User model), you need to keep in mind that the Prisma adapter automatically creates fields on these models when new users sign up and log in. Therefore, when adding new fields to these models, you must provide default values for them, since the adapter is not aware of these fields.
If for example, you'd like to add a role to the User model, you would need to provide a default value to the role field. This is done by adding a @default value to the role field in the User model:
+ enum Role {
+ USER
+ ADMIN
+ }
model User {
...
+ role Role @default(USER)
}
With Next.js 12+, the easiest way to protect a set of pages is using the middleware file. You can create a middleware.ts file in your root pages directory with the following contents.
export { auth as middleware } from "@/auth"
Then define authorized callback in your auth.ts file. For more details check out the reference docs.
async authorized({ request, auth }) {
const url = request.nextUrl
if(request.method === "POST") {
const { authToken } = (await request.json()) ?? {}
// If the request has a valid auth token, it is authorized
const valid = await validateAuthToken(authToken)
if(valid) return true
return NextResponse.json("Invalid auth token", { status: 401 })
}
// Logged in users are authenticated, otherwise redirect to login page
return !!auth.user
}
DISCORD_CLIENT_ID in .env.DISCORD_CLIENT_SECRET in .env. Be careful as you won't be able to see this secret again, and resetting it will cause the existing one to expire.<app url>/api/auth/callback/discord (example for local development: <code class="break-all">http://localhost:3000/api/auth/callback/discord</code>)| Resource | Link |
|---|---|
| NextAuth.js Docs | https://authjs.dev/ |
| NextAuth.js GitHub | https://github.com/nextauthjs/next-auth |
| tRPC Kitchen Sink - with NextAuth | https://kitchen-sink.trpc.io/next-auth |