🔥

【Next14(App Router)×Prism×Supabase Google,Github認証の実装メモ】

2023/11/08に公開

公式ドキュメントに殆ど書いてありますが自分用のメモ程度に書き起こしておきます

Next14構築

下記のコマンドを打ってnext14の環境を整えます

npx create-next-app@latest --ts

【Next14 必要実行環境】

現在のnodeバージョン確認

node -v

※足りていない場合はnodebrewかnvmからバージョンアップをしてください

√ What is your project named? ... zen1
√ Would you like to use ESLint? ... No / Yes
√ Would you like to use Tailwind CSS? ... No / Yes
√ Would you like to use `src/` directory? ... No / Yes
√ Would you like to use App Router? (recommended) ... No / Yes
√ Would you like to customize the default import alias (@/*)? ... No / Yes

Would you like to customize the default import alias (@/*)?以外すべてYes

必要なライブラリをインストールします

npm install next-auth @next-auth/prisma-adapter

src/app/page.tsxの中身を下記の通りに書き換えます

src/app/page.tsx
"use client"
import { signIn, signOut, useSession } from "next-auth/react"
const IndexPage = () => {
  const { data: session } = useSession()

  return (
    <>
     <div className="flex justify-center">
      {!session && (
            <button
              onClick={() => signIn()}
              className='flex w-full justify-center border-2 border-b border-red-300 hover:border-red-400 bg-red-200 hover:bg-red-300 pb-6 pt-8 backdrop-blur-2xl dark:border-red-800 dark:hover:border-red-900 dark:bg-red-800/50 dark:hover:bg-red-900/30 lg:static lg:w-auto lg:rounded-xl lg:p-4'
            >
              Sign In
            </button>
          )}
          {session && (
            <button
              onClick={() => signOut()}
              className='flex w-full justify-center border-2 border-b border-green-300 bg-green-200 pb-6 pt-8 backdrop-blur-2xl dark:border-green-800 dark:bg-green-800/30 lg:static lg:w-auto lg:rounded-xl lg:p-4 hover:border-green-400 hover:bg-green-300 dark:hover:border-green-900 dark:hover:bg-green-900/30'
            >
              Sign Out
            </button>
          )}
      </div>
      </>
  )
}

export default IndexPage

src/app/globals.cssの不要箇所を削除し下記の通りに書き換えます

src/app/globals.css
@tailwind base;
@tailwind components;
@tailwind utilities;

【認証の作成】

次にsrc/app/api/auth/[...nextauth]/route.tsを作成します
GoogleとGithubの認証Providerを設定します

src/app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth'
import GithubProvider from 'next-auth/providers/github'
import GoogleProvider from 'next-auth/providers/google'

export const authOptions = {
  secret: process.env.NEXTAUTH_SECRET,
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID ?? '',
      clientSecret: process.env.GITHUB_CLIENT_SECRET ?? '',
    }),
    GoogleProvider({
        clientId: process.env.Google_CLIENT_ID ?? '',
        clientSecret: process.env.Google_CLIENT_SECRET ?? '',
      }),
  ],
}

const handler = NextAuth(authOptions)

export { handler as GET, handler as POST }

ルートディレクトリにenvファイルを作成します
NEXTAUTH_SECRETは秘密鍵を作成し入力してください
下記のサイトは自動で秘密鍵を生成してくれます
https://generate-secret.vercel.app/32

env
NEXTAUTH_URL="http://localhost:3000"
NEXTAUTH_SECRET=""

GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""


GOOGLE_CLIENT_ID=""
GOOGLE_CLIENT_SECRET=""

DATABASE_URL=""

Github ID生成

Github公式
公式の手順が一番わかりやすいのでこちらを見て作成してみてください
Authorization callback UrlはURLの後ろに必ず/api/auth/callback/githubを付けます
例)http:localhost:3000/api/auth/callback/github
https://docs.github.com/ja/apps/oauth-apps/building-oauth-apps/creating-an-oauth-app

作成し終えると下記の画像の通りClientIDが表示されます
Client secretsの作成はGenerate a new client secretsから行って下さい
ClienIDとClient secretsは先ほど作成したenvファイルに記載します
説明1

Google ID生成

GoogleConsole
まずはGoogleConsoleに行きAPIとサービス→認証情報→プロジェクトを作成で作成してください
説明2
1.OAuth 同意画面で必要に応じて入力して下さい(メールアドレスとアプリ名だけで可能)
2.+認証情報を作成からOAuthクライアントIDを作成します
3.自身の作成するアプリケーションに選択して下さい
4.作成が完了すると下記のような画面が表示されIDとキーが取得できます
説明3
ClienIDとClient secretsは先ほど作成したenvファイルに記載します

【プロバイダーの作成】

クライアント側でAuthを使用できるようにするため
src/providers/NextAuth.tsxを作成します

src/providers/NextAuth.tsx
'use client'

import { SessionProvider } from 'next-auth/react'
import { ReactNode } from 'react'

const NextAuthProvider = ({ children }: { children: ReactNode }) => {
  return <SessionProvider>{children}</SessionProvider>
}

export default NextAuthProvider

作成したNextAuthProviderをlayout.tsxに記述します

src/app/layout.tsx
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import NextAuthProvider from '@/providers/NextAuth'
import './globals.css'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}> 
        <NextAuthProvider>{children}</NextAuthProvider>
      </body>
    </html>
  )
}

ここまでで一度ターミナルでnpm run devで実行すると下記のように認証が出来ます

npm run dev

ログイン前
説明4
認証
説明5
ログイン後
説明6

Prismaアダプターの連携

認証は完成しましたがDBにデータの格納が出来ていないためアダプターの連携をし
DBに認証データを保存します。今回はPrismaを使用しますが、それ以外のアダプターについても
NextAuthの公式ドキュメントに記述してあります。
https://next-auth.js.org/adapters
必要なライブラリをインストールします

npm install @prisma/client @next-auth/prisma-adapter
npm install prisma --save-dev

src/app/api/auth/[...nextauth]/route.tsにインストールしたライブラリをimportし追加します

src/app/api/auth/[...nextauth]/route.ts
import NextAuth from 'next-auth'
import GithubProvider from 'next-auth/providers/github'
import GoogleProvider from 'next-auth/providers/google'
+ import { PrismaAdapter } from "@auth/prisma-adapter"
+ import { PrismaClient } from "@prisma/client"

+ const prisma = new PrismaClient()

export const authOptions = {
  secret: process.env.NEXTAUTH_SECRET,
+ adapter: PrismaAdapter(prisma),
  providers: [
    GithubProvider({
      clientId: process.env.GITHUB_CLIENT_ID ?? '',
      clientSecret: process.env.GITHUB_CLIENT_SECRET ?? '',
    }),
    GoogleProvider({
        clientId: process.env.Google_CLIENT_ID ?? '',
        clientSecret: process.env.Google_CLIENT_SECRET ?? '',
      }),
  ],
}

const handler = NextAuth(authOptions)

export { handler as GET, handler as POST }

Prismaスキーマの作成

続いてNextAuthのスキーマを作成していきます

npx prisma init

上記のコマンドを実行するとルートディレクトリにprisma/schema.prismaファイルが作成されます

prisma/schema.prismaファイルをNextAuthの公式ドキュメントにのっとって書き換えます

prisma/schema.prisma
datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
  shadowDatabaseUrl = env("SHADOW_DATABASE_URL") // Only needed when using a cloud provider that doesn't support the creation of new databases, like Heroku. Learn more: https://pris.ly/d/migrate-shadow
}

generator client {
  provider        = "prisma-client-js"
  previewFeatures = ["referentialActions"] // You won't need this in Prisma 3.X or higher.
}

model Account {
  id                 String  @id @default(cuid())
  userId             String
  type               String
  provider           String
  providerAccountId  String
  refresh_token      String?  @db.Text
  access_token       String?  @db.Text
  expires_at         Int?
  token_type         String?
  scope              String?
  id_token           String?  @db.Text
  session_state      String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       String
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model User {
  id            String    @id @default(cuid())
  name          String?
  email         String?   @unique
  emailVerified DateTime?
  image         String?
  accounts      Account[]
  sessions      Session[]
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

Supabaseにデータを格納

次に格納先のDBとしてSupabaseを使用します。
Supabase公式に飛びアカウントがない場合は作成してください

1.newProjectからプロジェクトを作成してください
※Databaseパスワードは後で使うのでメモしておいてください又、作成には数分かかる可能性があります
2.作成が完了したら左のメニューバーのProgectSetting(一番下)から2個目の左のメニュバーの中のDatabaseに行きます
URIをクリックし表示されたURIを.envのDETABASE_URLに記載してください
※[password]には1で作成したときに入力したpasswordに置き換えてください
説明6
supabaseのデータベースに追加します

npx prisma db push

【動作確認】

ログインしたときに実際にトークンや情報が入っているかを確認します

npm run dev

npm run devで実行しログインを行います

npx prisma studio

PrismaStudioでログインユーザーのデータが格納されている確認します
説明7
上記のようにデータがあれば以上で実装完了です

Discussion