Next.jsでAuth.js v5を使ってみる

はじめに

こんにちは、インダストリーワン エンジニアの松崎です。

Auth.jsを使用して、どのように認証認可を実装できるのか調査します。

Auth.jsを使用することによって、簡単に認証機能の実装が可能になります。

現時点では、認証認可としてはまだまだ不十分ですが、Auth.jsの導入から簡単なカスタマイズまで対応しています。

成果物

セットアップ

とりあえず動くところまでを目指します。

1. Auth.jsをインストール

Auth.jsですが、ライブラリ名はnext-authですね。

現時点ではpackage.json"next-auth": "^5.0.0-beta.19"が追加されました。

npm install next-auth@beta

2. シークレットを設定

EnvファイルにAuth.jsで使用するシークレットを設定します。

シークレットの用途はこちら

.env.localを修正(.env.localがない場合は新規作成してください)

# 追記
AUTH_SECRET="your secret" # openssl rand -base64 33 or npx auth secret

3. Configを作成

src/auth/config.tsを作成

GitHub, GoogleclientId/clientSecretは各自でセットしてください。

ここでは仮の値をセットしています。

import NextAuth from "next-auth"
import GitHub from "next-auth/providers/github" 
import Google from "next-auth/providers/google"
 
export const { auth, handlers, signIn, signOut } = NextAuth({
  providers: [
     GitHub({ clientId: 'GITHUB_ID', clientSecret: 'GITHUB_SECRET'}),
     Google({ clientId: 'GOOGLE_ID', clientSecret: 'GOOGLE_SECRET'}),
  ],
})

4. API Routeを作成

src/app/api/[...nextauth]/route.tsを作成

import { handlers } from "@/auth/config"
export const { GET, POST } = handlers

5. Pageを作成

src/app/authjs/page.tsxを作成

'use client'

import { signIn } from "next-auth/react";
    
export default function AuthjsPage() {
    
  return (
    <div>
      <button onClick={() => signIn()}>サインイン</button>
    </div>
  );
}

6. http://localhost:3000/authjsにアクセス

サインインボタンが表示されることを確認

7. サインインボタンをクリック

GitHubGoogleを利用したサインインボタンが表示されるページに遷移することを確認

EmailとPasswordでの認証

ここからは上記をベースに、実験的に動かしてみます。

1. EmailPasswordのフォームを作成

1-1. src/auth/config.tsを修正し、EmailPasswordのフォームを作成

import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import GitHub from "next-auth/providers/github"
import Google from "next-auth/providers/google"

 
export const { auth, handlers, signIn, signOut } = NextAuth({
  providers: [
    GitHub({ clientId: 'GITHUB_ID', clientSecret: 'GITHUB_SECRET'}),
    Google({ clientId: 'GOOGLE_ID', clientSecret: 'GOOGLE_SECRET'}),
    Credentials({
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' },
      },
    })
  ],
})

1-2. EmailPasswordのフォームを確認

ここで、フォームに入力してSign in with Credentialsボタンをクリックしてもエラーになるので認証ロジックを作成します。

2. 認証ロジックの作成

2-1. src/auth/config.tsを修正し、認証ロジックを作成

import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import GitHub from "next-auth/providers/github"
import Google from "next-auth/providers/google"

 
export const { auth, handlers, signIn, signOut } = NextAuth({
  providers: [
    GitHub({ clientId: 'GITHUB_ID', clientSecret: 'GITHUB_SECRET' }),
    Google({ clientId: 'GOOGLE_ID', clientSecret: 'GOOGLE_SECRET' }),
    Credentials({
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' },
      },
      async authorize(credentials) {
        // ここに認証ロジックを作成する
        // とりあえずconsole.logでcredentialsを表示してみる
        console.log(credentials)
        // nullを返すと失敗
        return null
      }
    })
  ],
})

console.logの出力結果

csrfToken, email, passwordが取得できました。

2-2. 簡易なバリデーションを作成し、認証を成功させてみる

authorizeメソッドの中でZodを利用したバリデーションの実装や、バックエンドなどでの認証を実装するべきであるが、今回は省略し、ハードコーディングで値を返します。

成功した場合は、sessionの中にuserとしてデータが保存されます。

import NextAuth from "next-auth"
import Credentials from "next-auth/providers/credentials"
import GitHub from "next-auth/providers/github"
import Google from "next-auth/providers/google"

 
export const { auth, handlers, signIn, signOut } = NextAuth({
  providers: [
    GitHub({ clientId: 'GITHUB_ID', clientSecret: 'GITHUB_SECRET' }),
    Google({ clientId: 'GOOGLE_ID', clientSecret: 'GOOGLE_SECRET' }),
    Credentials({
      credentials: {
        email: { label: 'Email', type: 'email' },
        password: { label: 'Password', type: 'password' },
      },
      async authorize(credentials) {
       // ここに認証ロジックを作成する

       // credentialsには{ csrfToken: string, email: string, password: string }が入っている

       // 簡易的なバリデーション(Zodなどを使うと良い)
       if (!credentials) return null;
       if (typeof credentials.email !== 'string') return null;
       if (typeof credentials.password !== 'string') return null;
        
        
       // 認証成功時はユーザ情報を返す
       return {
          id: "test-test-test",
          email: credentials.email,
          name: "テストユーザ",
        }

      }
    })
  ],
})

2-3. Layoutを作成

src/app/authjs/layout.tsxを作成し、Client Componentsessionを扱えるようにします。

import { SessionProvider } from "next-auth/react";


export default function AuthjsLayout({ children }: { children: React.ReactNode }) {
    return (
        <SessionProvider>
            {children}
        </SessionProvider>
    )
}

2-4. Pageを修正

src/app/authjs/page.tsxを修正し、状態によって表示を分けています。

認証されている場合はsessionの中に格納されているuser情報を表示します。

'use client'

import { signIn, signOut, useSession } from "next-auth/react";

export default function AuthjsPage() {
  const session = useSession()

  if (session.status === 'loading') {
      return <p>loading...</p>
  }

  return (
      <div>
        {session.status === 'authenticated' ?
            <div>
              <p>EMAIL: {session.data.user?.email}</p>
              <p>NAME: {session.data.user?.name}</p>
              <button onClick={() => signOut()}>サインアウト</button>
            </div>
        :
            <button onClick={() => signIn()}>サインイン</button>
        }
      </div>
    );
  }
    

認証に成功した場合の表示を確認

3. サインインボタンの文字列を変更

Sign in with Credentialsではなんかダサいので、src/auth/config.tsを修正し、文字列をIndustry Oneに変更します。

# 省略

Credentials({
  name: 'Industry One',  # この行を追加
  credentials: {
    email: { label: 'Email', type: 'email' },
    password: { label: 'Password', type: 'password' },
  },
  async authorize(credentials) {

# 省略

文字列がCredentialsからIndustry Oneに変更されていることを確認

まとめ

今回はNext.jsでAuth.jsを使用してどのように認証認可を実装できるのか調査しました。

現時点では最低限(とりあえず動く程度)の実装となっているため、今後はバックエンドやDBを介しての認証などにトライしていきたいと考えております。

callbackの実装など、まだまだやることはありますね。

おわりに

IOでは常にエンジニアを積極採用中です!

少しでも興味を持っていただける方がいましたら、是非カジュアル面談からでも!

よろしくお願いします!

herp.careers herp.careers