🥋

【Next.js+Vercel】NextAuthでfacebookログインを実装する

2022/08/21に公開

自分の個人開発しているアプリでfacebookログインを実装するために試行錯誤しました。その実装方法をまとめます。

前提

開発環境のバージョンを以下の通りです。

ソフトウェア、アプリ バージョン 確認方法
docker Docker version 20.10.14 コマンドで確認
Node node:14.17.0 Dockerfileで確認
Next.js "next": "12.1.4" package.json
yarn "yarn": "1.22.5” yarn -v で確認
typescript "typescript": "4.6.3" package.json

実装手順

実装は以下の手順で行い、解説していきます。

  • facebookのアプリを作成する
  • next-authでfacebookログインを実装する
  • vercelにデプロイする
  • facebookのアプリにredirect_urlを設定する

facebookのアプリを作成する

facebookログインを実現するにはfacebookの中にアプリとして自分のWEBアプリを登録する必要があります。

↓ここからfacebookアプリを作成できます。

https://developers.facebook.com/apps/create/

facebookのアプリ作成は画面の指示に従えば、特に詰まることはないです。今回は「生活者(Consumer)」を選択します。

これで一旦、facebookのアプリの作成は完了です。

NextAuthでfacebookログインを実装する

facebookログインを実現するために、Next.jsのライブラリであるNextAuth.jsを使います。

next-authをインストールする

next-authをyarnで追加します。npmを使っている人は適宜読み替えてください。

yarn add next-auth

こんなエラーがvscodeに表示されるかもしれません。

【Next.js】Parsing error: Cannot find module 'next/babel'

その時はこの記事の方法で対応することができます。

https://zenn.dev/shimotaroo/articles/c8f2e751cd7877

NextAuthのファイルを作成する

続いて公式のドキュメントに沿って、pages以下にファイルを作っていきます。

[...nextauth].jsでNextAuth.jsの主な設定を記述します。
公式の今回はデフォルトのまま使っています。

pages/api/auth/[...nextauth].js
import NextAuth from "next-auth";
import FacebookProvider from "next-auth/providers/facebook";

export default NextAuth({
  providers: [
    FacebookProvider({
        clientId: process.env.NEXT_PUBLIC_FACEBOOK_CLIENT_ID,
        clientSecret: process.env.NEXT_PUBLIC_FACEBOOK_CLIENT_SECRET
    })
  ],
  secret: process.env.NEXT_PUBLIC_NEXTAUTH_SECRET,
  callbacks: {
    async jwt({ token, account }) {
      if (account) {
        token.accessToken = account.access_token
      }
      return token
    },
    async session({ session, token, user }) {
      session.accessToken = token.accessToken
      return session
    },
    async signIn({ user, account, profile, email, credentials }) {
      return true
    },
  },
  pages: {
    // signIn: '/auth/signin',
    // signOut: '/auth/signout',
  }
})

SSRをする場合は↓このファイルも必要になります。

pages/api/restricted.js
import  authOptions from './auth/[...nextauth]';
import { unstable_getServerSession } from "next-auth/next";

export default async (req, res) => {
  const session = await unstable_getServerSession(req, res, authOptions)
  if (session) {
    res.send({
      content:
        "This is protected content. You can access this content because you are signed in.",
    })
  } else {
    res.send({
      error: "You must be sign in to view the protected content on this page.",
    })
  }
}

https://next-auth.js.org/getting-started/example

ログイン処理を実装する

ここまででNextAuthを使う準備は整いました。次にログイン処理を実装していきます。

NextAuthのsignInメソッドは適当なところで実行すれば、Providerに合わせて適当に処理をしてくれます。今回はfacebookをログインをするため[...nextauth].jsでFacebookをProviderとして指定しています。

実装についてはコンポーネントから直接onClickイベントを検知して、signInメソッドを実行してもいいですし、コンポーネントを作ってイベントを子コンポーネントから検知して実行する方法でもOKです。

今回はsingnInメソッドを予め作っておいたLoginFormコンポーネントのイベントをキャッチしてsignInメソッドを実行します。

また、signInメソッドにはcallbackUrlを設定することができ、signInに成功したら別のページに遷移させることができます。


// signInをclickNewUserButtonのメソッドとして実装
const clickNewUserButton = () => {
  signIn(undefined, {callbackUrl: '/auth/signInSuccsess'});
}

// onClickNewUserButtonのイベントを検知して、clickNewUserButtonを発火させる
<LoginForm
  session={session}
  nextAuthStatus={status}
  onClickNewUserButton={() => {clickNewUserButton()}}
/>

Vercelにデプロイする

今回のNext.jsのアプリはVercelにホストすることを想定しています。
VercelでNextAuthを実行するのには少しコツがいるので、それについて解説します。

Vercelの環境変数をセットする

Vercel上のアプリがNextAuthを使う場合、NextAuth自体が意図したものであることを保証するためにNextAuthにsecretをセットする必要があります。

今回はVercelの環境変数を使って、このsecretをセットします。

このsecretは適当なランダムな文字列でOKです。

そのため [...nextauth].jsでNextAuthのオブジェクトの中のsecretにprocess.env.NEXT_PUBLIC_NEXTAUTH_SECRET を宣言しています。

pages/api/auth/[...nextauth].js
import NextAuth from "next-auth";
import FacebookProvider from "next-auth/providers/facebook";

export default NextAuth({
  providers: [
    FacebookProvider({
        clientId: process.env.NEXT_PUBLIC_FACEBOOK_CLIENT_ID,
        clientSecret: process.env.NEXT_PUBLIC_FACEBOOK_CLIENT_SECRET
    })
  ],
  secret: process.env.NEXT_PUBLIC_NEXTAUTH_SECRET,
  callbacks: {
    async jwt({ token, account }) {
      if (account) {
        token.accessToken = account.access_token
      }
      return token
    },
    async session({ session, token, user }) {
      session.accessToken = token.accessToken
      return session
    },
    async signIn({ user, account, profile, email, credentials }) {
      return true
    },
  },
  pages: {
    // signIn: '/auth/signin',
    // signOut: '/auth/signout',
  }
})

NEXT_PUBLIC_NEXTAUTH_SECRET に環境変数でNextAuthのシークレットをセットします。

今回は公式にあるコマンドから実行して、vercelの環境変数にセットします。

↓シークレットを生成するコマンドです。

$ openssl rand -base64 32

https://next-auth.js.org/getting-started/client#specifying-a-callbackurl

facebookのredirect_urlをセットする

ローカル環境ではfacebookログインはうまくいきます。しかしVercelにホストするとFacebook側でブロックされうまくいきません。
Vercel上のアプリからfacebookログインを実現するには、facebookのアプリの設定でfacebookログインを許可するURLを設定しておく必要があります。

Vercelではブランチごとにドメインがアサインされるので、developブランチや必要なブランチのドメインをfacebookアプリのURLにセットします。

具体的には以下のようなURLになります。

// hogehogeというプロジェクト名だった場合
https://hogehoge.vercel.app/
https://hogehoge.vercel.app/api/auth/callback/facebook

以上でVercelにホストしたアプリからfacebookログインが可能になります。

宣伝

カフェインレスコーヒーを集めたサイトを運営しています。

カフェインレスコーヒーを集めたサイトを作っています。カフェインレスコーヒーは夜に飲んでもぐっすり眠れるので、エンジニアの人にも試してみてほしいな、と思い作りました。よければのぞいてみてください。

これから色々と機能を追加していく予定です。

https://caffeinelessmore.com/

(初期ロード時に15秒くらいかかることがあります)

参考・補足

https://zenn.dev/msy/articles/fe4e7d44e5d095

https://zenn.dev/tkengineer/articles/5eb78800e9cd5f

https://www.youtube.com/watch?v=eTpkgNBmrX8

https://developers.facebook.com/docs/facebook-login/security?locale=ja_JP

https://developers.facebook.com/docs/graph-api/overview/rate-limiting/?translation

NextAuthのバグ?

https://stackoverflow.com/questions/7131909/facebook-callback-appends-to-return-url

callback_urlをスラッシュを指定するとアンダースコア、シャープ、イコールがついたURLに遷移させられる。
バグ?なのかもしれない?

Oriental Coffee Ventures

Discussion