Next Authを使って認証周りをよしなにやってもらった(Google・Github版)
最近仕事でNextAuthを触って便利だったので、あとで見返せれるように記事でまとめてみました。
まだ細かいところまでは知らないのですが、最低限の認証処理は実装できたので参考になればと思います。
🐈 Next Authとは
NextAuthは、初心者でも簡単な設定でセキュアな認証機能を提供し、多くのプロバイダーに対応しており、ユーザー管理やセッション管理も手軽に行えます。
🚀 セットアップ
ライブラリのインストール
next-authをインストールする
pmpm add next-auth
ファイルの修正
_app.tsxを以下のように修正する
import type { AppProps } from "next/app";
import { SessionProvider } from "next-auth/react";
export default function App({ Component, pageProps }: AppProps) {
return (
<SessionProvider session={pageProps.session}>
<Component {...pageProps} />
</SessionProvider>
);
}
環境変数の設定
NEXTAUTH_URL=http://localhost:3000
NEXTAUTH_SECRET=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GITHUB_CLIENT_ID=
GITHUB_CLIENT_SECRET=
NEXTAUTH_SECRETは以下のコマンドを叩いて取得する
openssl rand -base64 32
セッションの署名やJWTの署名関連の時に必要になるので用意しておきます
使用するプロバイダー
- Github
pages/api/authに[…nextauth].tsファイルを作成し、プロバイダーのモジュールをインポートする
import GoogleProvider from "next-auth/providers/google";
import GithubProvider from "next-auth/providers/github";
📝 コード解説
ログインページの実装
import { signIn } from "next-auth/react";
return(
{/* Google認証 */}
<button onClick={()=>signIn("google", { callbackUrl: `${process.env.NEXTAUTH_URL}/user`})}>Googleログイン</button>
{/* Github認証 */}
<button onClick={()=>signIn("github", { callbackUrl: `${process.env.NEXTAUTH_URL}/user`})}>Googleログイン</button>
)
signIn()の第1引数にプロバイダー名を設定して、第2引数をcallbackUrlでログイン後にリダイレクトしたいURLを設定する。
callbackUrlを設定することでクリックした際に、よく見る認証画面に飛びます。
Next Auth設定の実装
[…nextauth].tsの実装方法は以下を参考にしてます
import NextAuth, { NextAuthOptions } from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import GithubProvider from "next-auth/providers/github";
import { Provider } from "next-auth/providers/index";
// * 使用するプロバイダーの有効化(環境変数で定義するのがスタンダード)
const IS_GOOGLE_LOGIN_ENABLED = true;
const IS_GITHUB_LOGIN_ENABLED = true;
const providers: Provider[] = [];
if (IS_GOOGLE_LOGIN_ENABLED) {
providers.push(
GoogleProvider({
clientId: process.env.GOOGLE_CLIENT_ID as string,
clientSecret: process.env.GOOGLE_CLIENT_SECRET as string,
authorization: {
params: {
scope: "openid email profile",
access_type: "offline",
},
},
})
);
}
if (IS_GITHUB_LOGIN_ENABLED) {
providers.push(
GithubProvider({
clientId: process.env.GITHUB_CLIENT_ID as string,
clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
authorization: {
params: {
scope: "read:user user:email",
},
},
})
);
}
export const options: NextAuthOptions = {
secret: process.env.NEXTAUTH_SECRET,
pages: {
signIn: "/login",
},
providers: providers,
callbacks: {
async redirect({ url }) {
return url;
},
async jwt({ token, user, account }) {
if (user && account) {
// サインイン時のみ実行
return {
...token,
access_token: account.access_token,
refresh_token: account.refresh_token || null,
id_token: account.id_token || null,
};
}
return token;
},
async session({ session, token, user }) {
return {
...session,
access_token: token.access_token,
refresh_token: token.refresh_token,
id_token: token.id_token,
};
},
},
jwt: {
secret: process.env.NEXTAUTH_SECRET,
},
session: {
strategy: "jwt",
},
};
export default NextAuth(options);
Pages
カスタムしたサインインページやサインアウトページを指定することができます。
redirect
signIn()のcallbackURLで定義した値がurlに渡され、その値をreturnします。
jwt
callbacksのjwtはサインイン時と、getSession()
、getServerSession()
、useSession()
が呼び出された際に実行されるため、その処理を記述しています。
なお、userやaccount情報はサインイン時のみ取得されるため、アクセストークンやリフレッシュトークン、Idトークン等を取得したい場合は、上記のような条件式で実装することで可能です。
※GitHubではリフレッシュトークンおよびIdトークンが存在しないため、nullとなります。
session
jwtセッションを使用している場合、jwtのペイロード(token)の値が渡されるので、jwtで定義したものを受け取れます。
今回の場合だとアクセストークンやIdトークンを取得しています。
ログイン後のユーザーページの実装(サーバー処理のみ)
export const getServerSideProps: GetServerSideProps = async (context) => {
const { req, res } = context;
const token = await getToken({
req: req,
secret: process.env.NEXTAUTH_SECRET,
});
if (!token) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
const session = await getServerSession(req, res, options);
if (!session) {
return {
redirect: {
destination: "/login",
permanent: false,
},
};
}
return {
props: {},
};
};
getServerSidePropsでgetToken
もしくはgetServerSession
を呼び出すことにより、[…nextauth].tsで定義されたユーザー情報を取得できます。
tokenやsessionが取得できない場合は、/loginページにリダイレクトすることでアクセス制御を実装できます。
returnのpropsに、tokenやsessionで取得したユーザー情報を加工し定義することで、クライアント側はそれを受け取り利用できるようになります。
getSession()
を使用して同様のデータを取得することも可能ですが、useEffectの使用などが必要になる場合があります。そのため、個人的にはgetServerSession()を使用した方がスマートだと考えています。
参考ドキュメント
😎 終わり
NextAuthの使いやすさ開発体験が良かったので、今後も採用していきたいなと思いました!
今回使ったプロバイダーはGoogleとGithubですが、他にもAzureADやSlackなど50以上のプロバイダーを使えるのでかなり良きです^^
👀 おまけ
弊社では、スマホやPC1つで完結する網羅的な教材と、無制限で解ける本番と同形式の模試で、短期間での資格取得を目指すことができる簿記のアプリ 『Funda簿記』 を運営しています。
少しでも興味のある方がいれば、リンクよりアクセスしていただくか、メールにてお願いします☺️
Discussion