NextAuth.js で SessionProvider を利用しユーザ情報を取得する
背景
NextAuth.js でログインしている User の情報を Client side で取得する方法を色々調べながら学んでいました。
参考にしたサイトと私が使っている Next.js のバージョンの違いなどもあり迷走したので、備忘録としてまとめておきます。皆様の助けになれば幸いです。
(Next.js はバージョン違いで結構仕様が異なるのでこの辺は沼ですね)
ソフトウェアのバージョン
npm ls | grep next
├── next-auth@4.23.2
├── next@13.5.6
/** @type {import('next').NextConfig} */
const nextConfig = {
compiler: {
styledComponents: true,
},
experimental: {
appDir: true,
},
}
module.exports = nextConfig
方法
NextAuth.js を用いると簡単に Github や Gmail を利用した認証機能を実装することができます。
さらに認証済みの状態の時に現在ログインしているユーザの名前やその他の情報を取得するのも、(私は少しつまづいてしまいましたが)簡便にできます。
おそらく本来なら簡単にできるところを
- Provider の実装を行う必要があるが初めての実装であった
- 動的ルーティングを行っているページでユーザ情報を取得する
- client side として取得する
と言う状況でやや複雑であったのが原因ではないかなとは思います。
そこで同じ状況で実装する方のために備忘録としてまとめておきます。
1. Provider として SessionProvider を実装する
Client side で NextAuth.js のユーザなどのセッション情報を取得するためには SessionProvider を利用する必要があります。
そこで src/app/context/providers.tsx
を以下のように実装しました。
use client
を先頭につけることで client side で利用することを明示しておきます。
'use client'
import { SessionProvider } from 'next-auth/react'
import { ReactNode } from 'react'
type ProviderProps = {
children: ReactNode
}
function Provider({ children }: ProviderProps) {
return <SessionProvider>{children}</SessionProvider>
}
export default Provider
2. 動的ルーティングを行なっていないページでユーザ情報を取得する
コケた時に変更点がたくさんあるとどこでつまづいたかわかりづらくなるので、まずは動的ルーティングを行っていないページで取得してみます。原因の切り分けは大事です。
例えば src/app/foo/page.tsx
のような適当なディレクトリに page.tsx
を作成し以下のように実装します。
'use client'
import React from 'react'
import Provider from '../../context/providers'
import MyClientComponent from '../../components/MyClientComponent'
export default function page() {
return (
<Provider>
<MyClientComponent />
</Provider>
)
}
ここで先ほど作成した Provider
タグを呼び出し MyClientComponent
タグを挟んでいるので MyClientComponent
コンポーネント内でユーザ情報を取得することができるようになります。
続けて MyClientComponent
コンポーネントを実装します。
'use client'
import React from 'react'
import { useSession } from 'next-auth/react'
export default function MyClientComponent() {
const { data: session, status } = useSession()
console.log('session', session)
console.log('status', status)
if (status === 'loading') {
return <p>Loading...</p>
}
return (
<div>
<h1>My Client Component</h1>
<h2>User ID: {session?.user?.id}</h2>
<h2>status: {status}</h2>
</div>
)
}
useSession
でユーザ情報を取得します。 useSession
は client side のみでしか使えないため providers.tsx
, page.tsx
, MyClientComponent.tsx
で use client
と client side であることを明示している必要があるわけですね (server side の場合は getServerSession
を使いましょう)
ただし、 MyClientComponent
がレンダリングされた瞬間、ユーザなどのセッション情報が取得されるわけではないようなので
if (status === 'loading') {
return <p>Loading...</p>
}
と、 status
が loading
の場合はロード中であることを表示し、取得後 (status
は authenticated
になります) にユーザ情報に基づいたページを表示するよう今回はしてみました。
return (
<div>
<h1>My Client Component</h1>
<h2>User ID: {session?.user?.id}</h2>
<h2>status: {status}</h2>
</div>
)
なお最初に
const { data: session, status } = useSession()
console.log('session', session)
console.log('status', status)
と、 console.log でデバッグライトしているのですが、ここはユーザなどのセッション情報取得前に実行されるので session
= undefined
, status
= loading
と表示され、ここでデバッグライトしていると当たり前ですが値が取得できません。(ここでデバッグライトしてたせいでずっと値が入らなくて他の部分がおかしいのかなーと少しハマってしまいました)
ここまで実装しテストをすると以下のようにユーザなどのセッション情報が取れているのが確認できました。
3. 動的ルーティングを行なってるページでユーザ情報を取得する
では最後に元々の目標であった動的ルーティングを行っているページでユーザ情報を取得してみます。
先ほどと同様に src/app/baz/[title]
に page.tsx
を作成し title
の値を取得したいとします。
動的ルーティングを用いると以下のように title
が取得できます。
'use client'
export default function Page({ params }: { params: { title: string } }) {
const { title } = params
return (
<main>
<h1>My Page</h1>
<p>title: {title}</p>
</main>
)
}
同じようにユーザなどのセッション情報を含めつつ動的ルーティングをするページを src/app/foo/[title]/page.tsx
を実装していきます。本来は別のファイルなのですが 「2. 動的ルーティングを行なっていないページでユーザ情報を取得する」 で実装したページとの差分として表示しておきます。
'use client'
import React from 'react'
import Provider from '../../../context/providers'
import MyClientComponent from '../../../components/MyClientComponent'
- export default function page() {
+ export default function page({ params }: { params: { title: string } }) {
+ const { title } = params
return (
<Provider>
- <MyClientComponent />
+ <MyClientComponent title={title} />
</Provider>
)
}
MyClientComponent
側も title
を受け取り表示するようにアップデートします。
'use client'
import React from 'react'
import { useSession } from 'next-auth/react'
- export default function MyClientComponent() {
+ export default function MyClientComponent({ title }: { title: string }) {
const { data: session, status } = useSession()
console.log('session', session)
console.log('status', status)
if (status === 'loading') {
return <p>Loading...</p>
}
return (
<div>
<h1>My Client Component</h1>
+ <h2>Title: {title} </h2>
<h2>User ID: {session?.user?.id}</h2>
<h2>status: {status}</h2>
</div>
)
}
ここまで実装し、 例えば http://localhost:3000/foo/abc にアクセスすると以下のように title
として abc
が取得され表示されるようになります。また、ユーザなどのセッション情報も引き続き取得されています。
💡 まとめ
- NextAuth.js でログイン中のユーザなどのセッション情報を取得しました
- Session Provider を用いて Client side で利用できるようにしました
- 動的ルーティングも同時に行いました
Discussion