NextAuthを使ってAPIで認証するのに苦戦したので雑にメモ。
環境変数
よくわかってないけど設定しないとうまく動かない。
これが原因と分からずずっと動かなかった。
・NEXTAUTH_URL
認証系のURLの設定
https://next-auth.js.org/configuration/options#nextauth_url
・NEXTAUTH_SECRET
認証してJWTをなんやかんやするのに必要らしい
https://next-auth.js.org/configuration/options#nextauth_secret
.env
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=secret
オプション作る
NextAuthの設定的なもの。
src\lib\nextAuthOptions.ts
import { NextAuthOptions } from "next-auth";
import GithubProvider from "next-auth/providers/github"
import CredentionsProvider from 'next-auth/providers/credentials'
const authOptions: NextAuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
// 必要なプロバイダーは複数設定できる
providers: [
// Githubの認証
GithubProvider({
clientId: process.env.GITHUB_ID || '',
clientSecret: process.env.GITHUB_SECRET || '',
}),
// Credentialsは普通のIDパスワード方式
CredentionsProvider({
name: 'Credentials',
credentials: {
username: {
label: 'Username',
type: 'text',
placeholder: 'username'
},
password: {
label: 'Password',
type: 'password'
}
},
async authorize(credentials, req) {
// ここでユーザー認証を行う
// テスト用のユーザー
const user = { id: '1', name: 'Taro', email: 'test@example.com' }
if (user) {
return user
} else {
return null
}
}
})
],
// ログインページとかのURLを変えたい場合pagesを設定する
// pages: {
// signIn: '/auth/signin',
// signOut: '/auth/signout',
// error: '/auth/error', // Error code passed in query string as ?error=
// verifyRequest: '/auth/verify-request', // (used for check email message)
// newUser: '/auth/new-user'
// }
}
export default authOptions;
ハンドラー作る
AppRouter
を使う場合はRoute Handlerというやつを使うらしい。
src/app/api/auth/[...nextauth]/route.ts
import NextAuth from "next-auth";
import authOptions from "@/lib/nextAuthOptions";
const handler = NextAuth(authOptions);
export { handler as GET, handler as POST }
Provider
アプリ内でセッションが使えるようにする。
NextAuthProvider.tsx
"use client";
import { SessionProvider } from "next-auth/react";
import { Session } from "next-auth";
export const NextAuthProvider = ({
children,
session,
}: {
children: React.ReactNode;
session: Session | null;
}) => {
return (
<SessionProvider session={session} refetchOnWindowFocus={false}>
{children}
</SessionProvider>
);
};
ルートのレイアウトでプロバイダーを使用
src\app\layout.tsx
export default async function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
const session = await getServerSession(authOptions);
return (
<html lang="ja">
<body className={inter.className}>
<NextAuthProvider session={session}>{children}</NextAuthProvider>
</body>
</html>
);
}
ページとか
signIn
には引数でプロバイダーを指定できる。
signIn()
でログインページに飛ぶ
ExampleTopPage.tsx
'use client'
import React from 'react'
import { signIn, signOut } from 'next-auth/react'
function page(req, res) {
const onClickLogin = async () => {
signIn()
};
const onClickLogout = async () => {
signOut()
}
return (
<div>
<div>
<button onClick={onClickLogin}>ログイン</button>
</div>
<div>
<button onClick={onClickLogout}>ログアウト</button>
</div>
</div>
)
}
export default page
API入口
認証で制限をかけたAPI。
ログインできていたらデータが取れる。
Response
ではなくNextResponse
で作成しないとエラーが出る。
api/api-test/route.ts
import { getServerSession } from 'next-auth/next';
import { NextApiRequest, NextApiResponse } from 'next'
import authOptions from '@/NextAuthConfig/Option'
export const GET = async (req: NextApiRequest, res: NextApiResponse) => {
const session = await getServerSession(authOptions)
console.log(session);
if (session) {
return NextResponse.json({ data: "Protected data" })
}
return NextResponse.json({ message: "Not authenticated" }, { status: 401 })
}