【Next.js】Auth.js v5ではどうやってRSCでセッションを取得できているかを追ってみる
モチベーション
v4からv5のマイグレーションをしている中でRSCでセッションを取得するためにはgetServerSessionではなくNextAuthから返されるauthを使ってセッションを取得する方法に変わったようです。
さらにCredential Providerを使っているのですが、v5からJWT session strategyしかサポートしなくなったようなので、これを機にAuth.jsではどのようにRSCでJWTを使ってセッション管理しているか実際にコードを追っていこうと思います。
現状JWTはcookieで管理されていて、RSCでセッションを取得する際はJWTをAuth.js側でデコードして返しているのはずなのでJWTのエンコード、デコードしているコードまでたどりつければこちらのスクラップをクローズさせようと思います。
ちなみにuseSessionを使ってクライアント側でセッションを取得する際はContext APIで用いているようです。(以下参照)
Auth.js v5ではどうやってRSCでセッションを取得できているかを追ってみる
サンプル
サンプルコードはこちらから引用しています
import { auth } from "../auth"
export default async function UserAvatar() {
const session = await auth()
if (!session.user) return null
return (
<div>
<img src={session.user.image} alt="User Avatar" />
</div>
)
}
import NextAuth from "next-auth"
import { ZodError } from "zod"
import Credentials from "next-auth/providers/credentials"
import { signInSchema } from "./lib/zod"
// Your own logic for dealing with plaintext password strings; be careful!
import { saltAndHashPassword } from "@/utils/password"
import { getUserFromDb } from "@/utils/db"
export const { handlers, auth } = NextAuth({
providers: [
Credentials({
// You can specify which fields should be submitted, by adding keys to the `credentials` object.
// e.g. domain, username, password, 2FA token, etc.
credentials: {
email: {},
password: {},
},
authorize: async (credentials) => {
try {
let user = null
const { email, password } = await signInSchema.parseAsync(credentials)
// logic to salt and hash password
const pwHash = saltAndHashPassword(password)
// logic to verify if the user exists
user = await getUserFromDb(email, pwHash)
if (!user) {
throw new Error("User not found.")
}
// return JSON object with the user data
return user
} catch (error) {
if (error instanceof ZodError) {
// Return `null` to indicate that the credentials are invalid
return null
}
}
},
}),
],
})
1, NextAuth(packages/next-auth)
import NextAuth from "next-auth"
から見ていきます。
next-authをインポートしている大元のファイルはこちら。
L385のauthでsessionを受け取れます。
authはinitAuthで生成しているようなので見ていきましょう。
setEnvDefaultsは後回しにして余裕があれば追って見ます。
2, initAuth(packages/next-auth)
initAuthを扱っているファイルはこちら。
L129のコメントアウトの通りRSCのコードをたどりたいのでL134のgetSessionを見ていきます。
3, getSession(packages/next-auth)
getSessionはinitAuthと同じファイルで定義されていて、最終的な成果物はAuthで生成しているのでそちらを見にいきます。
4, Auth(packages/core)
ここからはパッケージが変わります。
configにNEXTAUTH_SECRETが内包されているはずなのでAuthInternalを追ってみます。
5, AuthInternal(packages/core)
ここら辺でSessionStoreが見えてきたのでゴールは近そうです。
Switch文の中でsessionStoreを流しているのはactions.callbackとactions.session(actions.webAuthnOptionsはスキップ)なのでactions.sessionの方を覗いて見ます。
6, actions.session(packages/core)
ようやくここでjwt.encodeを見つけました。
L38でJWTをデコードしてpayloadを取得してようです。
ちなみにsessionStrategy(jwtとdatabase)のコードがこちらにまとまっていました。
まとめ
ざっと見てきましたが、やはりRSCでセッションを取得する際はcookie情報(JWT)をAuth.js側でデコードしているようです。また、全部は見切れていませんがコードを追っていくならpackages/coreを見ていくと良さそうです。
簡単ですが以上です。
補足やメモ書きなどがありましたら追記していきます。
- 例えばjwtから生えているencodeは一旦なんぞや
- sessionStoreの方も追って見たらcookie管理の中身も見れる