Django REST Framework + Next.jsでブログ構築 レッスン2 ログインエラー
解決済
回答 5
2022/11/05 06:43
質問内容

実現したいこと

Django REST Framework + Next.js + NextAuth.js(v4)でGoogle認証を行う

背景

上記のチュートリアルではNestAuth.jsのVersion 3が使用されているため、NextAuth公式サイトを参考にv4に書き換えながらチュートリアルを進めています。

発生している問題

Googleログイン画面への移行には成功し、アカウントを選択したところで"Access Denied, You do not have permission to sign in" と表示されます。

ソースコード

[...nextauth.js]

import NextAuth from "next-auth"
import axios from "axios"
import GoogleProvider from "next-auth/providers/google"

export default NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
<!-- ここ以降はチュートリアルとコードは同じ -->
callbacks: {
    async signIn(user, account, profile) {
      if (account.provider === 'google') {
        const { accessToken, idToken } = account

        try {
          const response = await axios.post(
            `${process.env.DJANGO_URL}/api/social/login/google/`,
            {
              access_token: accessToken,
              id_token: idToken,
            }
          )

          const { access_token } = response.data
          user.accessToken = access_token

          return true
        } catch (error) {
          return false
        }
      }
      return false
    },
    async jwt(token, user, account, profile, isNewUser) {
      if (user) {
        const { accessToken } = user

        token.accessToken = accessToken
      }

      return token
    },
    async session(session, user) {
      session.accessToken = user.accessToken
      return session
    },
  }
}

export default (req, res) => NextAuth(req, res, settings)

自分で試したこと

1. DjangoかNextどちらに問題があるか確認

はる先生のgithubからフロントエンドのプログラムをダウンロードし、私がチュートリアルを参考に(完全なコピーで変更箇所はない)したDjangoと動かしてみました。→Googleログインに成功したため、Djangoのエラーはなし、next.jsの方に問題があることがわかりました。

2. Nextのエラーの詳細を確認

[.../nextauth].jsのcallbacks-のasync signIn...の中のtry-catch文に、エラーがある場合エラーを出力するように追記し、再度自分で作成したプログラムを動かし同じエラーを再現したところ、 next側のターミナルで

AxiosError: Request failed with status code 400
    at settle (file:///Users/myuser/Documents/projects/djangonext-googleauth/next/node_modules/axios/lib/core/settle.js:19:12)
    at IncomingMessage.handleStreamEnd (file:///Users/myuser/Documents/projects/djangonext-googleauth/next/node_modules/axios/lib/adapters/http.js:495:11)
    at IncomingMessage.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1358:12)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {

...以下省略(エラーの一部を最後に載せています)

そしてDjang側のターミナル上で

Bad Request: /api/social/login/google/
[04/Nov/2022 20:17:48] "POST /api/social/login/google/ HTTP/1.1" 400 75

が出ていました。

callbacks内の設定に不備があるようです。

3. [../nextauth].jsにconsole.logを足す

 async signIn(user, account, profile) {
      if (account.provider === 'google') {
        const { accessToken, idToken } = account
        console.log("\naccessToken"+accessToken + "\nidToken:"+idToken )

おそらくdjangoへのpostでエラーが発生しているため、その直前で定義している変数を出力する設定を行い、変数が正しく定義されているか確認を行いました。

accessToken:undefined
idToken:undefined

公式ドキュメントによると、accountはプロバイダのことを指しています。

https://next-auth.js.org/configuration/events#events

よって、

const { accessToken, idToken } = account

でgoogleからaccessTokenとidTokenの取得と変数の作成に失敗しているのではないか?というところまで推測できましたが、これ以上はわかりませんでした。

このエラーを解決するために、何をやればいいか見当がつかない 状況です。 手順やプロセスなど、何かアドバイスがあればお伺いしたいです。 長文になってしまいましたが、よろしくお願いいたします。


AxiosError: Request failed with status code 400
    at settle (file:///Users/iamuser/Documents/projects/djangonext-googleauth/next/node_modules/axios/lib/core/settle.js:19:12)
    at IncomingMessage.handleStreamEnd (file:///Users/iamuser/Documents/projects/djangonext-googleauth/next/node_modules/axios/lib/adapters/http.js:495:11)
    at IncomingMessage.emit (node:events:525:35)
    at endReadableNT (node:internal/streams/readable:1358:12)
    at processTicksAndRejections (node:internal/process/task_queues:83:21) {
  code: 'ERR_BAD_REQUEST',
  config: {
    transitional: {
      silentJSONParsing: true,
      forcedJSONParsing: true,
      clarifyTimeoutError: false
    },
    adapter: [Function: httpAdapter],
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    maxBodyLength: -1,
    env: { FormData: [Function], Blob: null },
    validateStatus: [Function: validateStatus],
    headers: AxiosHeaders {
      'Content-Type': 'application/json',
      'User-Agent': 'axios/1.1.3',
      'Content-Length': '2',
      'Accept-Encoding': 'gzip, deflate, br',
      [Symbol(defaults)]: [Object]
    },
    method: 'post',
    url: 'http://127.0.0.1:8000/api/social/login/google/',
    data: '{}'
  },

.....
    config: {
      transitional: [Object],
      adapter: [Function: httpAdapter],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      maxBodyLength: -1,
      env: [Object],
      validateStatus: [Function: validateStatus],
      headers: [AxiosHeaders],
      method: 'post',
      url: 'http://127.0.0.1:8000/api/social/login/google/',
      data: '{}'
    },



      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/api/social/login/google/',
      ....
回答 5
ベストアンサーを選択すると、解決済みとなります。
nodata
まだ回答がありません
回答
nodata
回答するにはログインが必要です