質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Google Cloud Platform

Google Cloud Platformは、Google社がクラウド上で提供しているサービス郡の総称です。エンドユーザー向けサービスと同様のインフラストラクチャーで運営されており、Webサイト開発から複雑なアプリ開発まで対応可能です。

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

Q&A

0回答

1379閲覧

React と Django ( DRF ) を用いた Google アカウントでのログイン認証機能の実装 {error: 'unsupported_grant_type'}

rokutimpo

総合スコア12

Google Cloud Platform

Google Cloud Platformは、Google社がクラウド上で提供しているサービス郡の総称です。エンドユーザー向けサービスと同様のインフラストラクチャーで運営されており、Webサイト開発から複雑なアプリ開発まで対応可能です。

Django

DjangoはPythonで書かれた、オープンソースウェブアプリケーションのフレームワークです。複雑なデータベースを扱うウェブサイトを開発する際に必要な労力を減らす為にデザインされました。

OAuth 2.0

OAuth 2.0(Open Authorization 2.0)は、APIを通して保護されたリソース(サードパーティのアプリケーション)へアクセスする為のオープンプロトコルです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

React.js

Reactは、アプリケーションのインターフェースを構築するためのオープンソースJavaScriptライブラリです。

0グッド

0クリップ

投稿2022/06/29 03:10

前提

現在、 Django Rest Framework と React を用いた Google アカウントでのOAuth 認証の構築を試みています。
ソーシャルアカウント以外の、通常の認証には JWT 認証を使用しており、こちらは問題なく動作しています。

しかし、ソーシャルアカウント( Google )については、以下のエラーが発生し解決策がわからず頓挫しています。
どなたか解決策のわかる方がいらっしゃいましたらご教示頂けると幸いです。

実現したいこと

☑ フロントエンド側 ( React を使用しています) から 認可サーバーのレスポンスをバックエンドに渡す。

  • バックエンド側で受け取った値を grant_type: "convert_token" で変換したい

発生している問題・エラーメッセージ

バックエンド側のソースコード( django )

python3

1# mysite/settings.py 2 3(途中省略) 4 5INSTALLED_APPS = [ 6 'django.contrib.admin', 7 'django.contrib.auth', 8 'django.contrib.contenttypes', 9 'django.contrib.sessions', 10 'django.contrib.messages', 11 'django.contrib.staticfiles', 12 'backend', 13 'corsheaders', 14 'rest_framework', 15 'rest_framework.authtoken', 16 'rest_auth', 17 'django.contrib.sites', 18 'rest_auth.registration', 19 'drf_social_oauth2', 20 'social_django', 21 'oauth2_provider', 22 23] 24 25SITE_ID = 1 26REST_USE_JWT = True 27 28SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = "hogehoge.apps.googleusercontent.com"# Google のクライアントID 29SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = "hogehogehogehoge"# Google のクライアントシークレット 30 31SOCIAL_AUTH_GOOGLE_OAUTH2_SCOPE = [ 32 'https://www.googleapis.com/auth/userinfo.email', 33 'https://www.googleapis.com/auth/userinfo.profile', 34] 35 36REST_FRAMEWORK = { 37 'DEFAULT_PERMISSION_CLASSES': ( 38 'rest_framework.permissions.IsAuthenticated', 39 ), 40 'DEFAULT_AUTHENTICATION_CLASSES': ( 41 'rest_framework.authentication.TokenAuthentication', 42 'rest_framework_jwt.authentication.JSONWebTokenAuthentication', 43 44 'oauth2_provider.contrib.rest_framework.OAuth2Authentication',# django-oauth-toolkit >= 1.0.0です 45 'drf_social_oauth2.authentication.SocialAuthentication', 46 ), 47} 48 49JWT_AUTH = { 50 'JWT_ENCODE_HANDLER': 51 'rest_framework_jwt.utils.jwt_encode_handler', 52 53 'JWT_DECODE_HANDLER': 54 'rest_framework_jwt.utils.jwt_decode_handler', 55 56 'JWT_PAYLOAD_HANDLER': 57 'rest_framework_jwt.utils.jwt_payload_handler', 58 59 'JWT_PAYLOAD_GET_USER_ID_HANDLER': 60 'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler', 61 62 'JWT_RESPONSE_PAYLOAD_HANDLER': 63 'rest_framework_jwt.utils.jwt_response_payload_handler', 64 65 'JWT_SECRET_KEY': SECRET_KEY, 66 'JWT_GET_USER_SECRET_KEY': None, 67 'JWT_PUBLIC_KEY': None, 68 'JWT_PRIVATE_KEY': None, 69 'JWT_ALGORITHM': 'HS256', 70 'JWT_VERIFY': True, 71 'JWT_VERIFY_EXPIRATION': True, 72 'JWT_LEEWAY': 0, 73 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=43200), 74 'JWT_AUDIENCE': None, 75 'JWT_ISSUER': None, 76 77 'JWT_ALLOW_REFRESH': True, 78 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=30), 79 'JWT_AUTH_HEADER_PREFIX': 'JWT', 80 'JWT_AUTH_COOKIE': None, 81} 82 83 84ACCOUNT_USERNAME_REQUIRED = False 85ACCOUNT_AUTHENTICATION_METHOD = 'username' 86ACCOUNT_EMAIL_REQUIRED = False 87ACCOUNT_USERNAME_REQUIRED = True 88EMAIL_BACKEND ='django.core.mail.backends.console.EmailBackend' 89 90MIDDLEWARE = [ 91 'django.middleware.security.SecurityMiddleware', 92 'django.contrib.sessions.middleware.SessionMiddleware', 93 'django.middleware.common.CommonMiddleware', 94 'django.contrib.auth.middleware.AuthenticationMiddleware', 95 'django.contrib.messages.middleware.MessageMiddleware', 96 'django.middleware.clickjacking.XFrameOptionsMiddleware', 97 'corsheaders.middleware.CorsMiddleware', 98] 99 100CORS_ORIGIN_WHITELIST = [ 101 'http://localhost:3000', 102] 103 104ROOT_URLCONF = 'mysite.urls' 105 106TEMPLATES = [ 107 { 108 'BACKEND': 'django.template.backends.django.DjangoTemplates', 109 'DIRS': [], 110 'APP_DIRS': True, 111 'OPTIONS': { 112 'context_processors': [ 113 'django.template.context_processors.debug', 114 'django.template.context_processors.request', 115 'django.contrib.auth.context_processors.auth', 116 'django.contrib.messages.context_processors.messages', 117 118 'social_django.context_processors.backends', 119 'social_django.context_processors.login_redirect', 120 ], 121 }, 122 }, 123] 124 125AUTHENTICATION_BACKENDS = ( 126 'social_core.backends.google.GoogleOAuth2', 127 'drf_social_oauth2.backends.DjangoOAuth2', 128 'django.contrib.auth.backends.ModelBackend', 129) 130 131(以下略) 132

python3

1# mysite/urls.py 2 3from django.contrib import admin 4from django.urls import path, include 5from rest_framework_jwt.views import obtain_jwt_token, refresh_jwt_token, verify_jwt_token 6 7urlpatterns = [ 8 path('admin/', admin.site.urls), 9 path('rest-auth/', include('rest_auth.urls')), 10 path('rest-auth/registration/', include('rest_auth.registration.urls')), 11 path('api-token-auth/', obtain_jwt_token), 12 path('api-token-refresh/', refresh_jwt_token), 13 path('api-token-verify/', verify_jwt_token), 14 path('auth/', include('drf_social_oauth2.urls', namespace='drf')), 15 path('', include('backend.urls')), 16]

1. フロント側のコード( React )

React

1// components/Login.js 2 3import React, {useEffect, useState} from 'react' 4import {useNavigate} from 'react-router-dom'; 5import GoogleLogin from 'react-google-login' 6import { gapi } from 'gapi-script' 7import axios from 'axios' 8 9function Login() { 10 11(途中省略) 12 // envから読み込み 13 const googleClientId = process.env.REACT_APP_GOOGLE_CLIENT_ID; 14 const drfClientId = process.env.REACT_APP_DRF_CLIENT_ID; 15 const drfClientSecret = process.env.REACT_APP_DRF_CLIENT_SECRET; 16 17 useEffect (() => { 18 function start() { 19 gapi.client.init({ 20 clientId: googleClientId, 21 scope: 'email', 22 }); 23 } 24 gapi.load('client:auth2', start); 25 }, []) 26 27 const responseGoogle = (response) => { 28 console.log('response.accessToken: ' + response.accessToken)// アクセストークンが出力できることが確認出来ている状態 29 30 axios ({ 31 method: 'post', 32 mode: 'cors', 33 url: 'http://localhost:8000/auth/convert-token/', 34 35 headers: { 36 "Content-Type": "application/x-www-form-urlencoded", 37 }, 38 39 data: { 40 grant_type: "convert_token", 41 client_id: drfClientId, 42 client_secret: drfClientSecret, 43 backend: "google-oauth2", 44 token: response.accessToken, 45 } 46 }) 47 .then(function (res) { 48 const {access_token, refresh_token} = res.data 49 console.log({access_token, refresh_token}) 50 }) 51 .catch((error) => { 52 console.log(error) 53 }) 54 55(以下略) 56

1. エラーレスポンス

bash

1Bad Request: /auth/convert-token/ 2"POST /auth/convert-token/ HTTP/1.1" 400 34

ChromeDeveloperTool(console.logで出力しています)

1AxiosError {message: 'Request failed with status code 400', name: 'AxiosError', code: 'ERR_BAD_REQUEST', config: {…}, request: XMLHttpRequest, …} 2 3<response.dataの内容> 4data: {error: 'unsupported_grant_type'}

2. curlでのアクセス

bash

1curl -X POST -d "grant_type=convert_token&client_id=<django のクライアントID>&client_secret=<django のクライアントシークレット>&backend=google-oauth2&token=<ブラウザコンソールで出力されたGoogleのアクセストークン>" http://localhost:8000/auth/convert-token/

2. エラーレスポンス

bash

1{"error":"invalid_client"}

補足情報

<参考にしたサイト>
https://github.com/anthonyjgrove/react-google-login → react-google-loginの公式リポジトリ
https://pypi.org/project/drf-social-oauth2/ → drf_social_oauth2の公式ページ
https://iamashutoshpanda.medium.com/google-login-with-django-react-part-1-c189bc69a999 → 参考にしたブログ

<ツールのバージョン等>
【 Django側 】
python3.9.9
django==3.2.13
djangorestframework==3.13.1
djangorestframework-jwt==1.11.0
django-cors-headers==3.12.0
pyjwt==2.4.0
drf_social_oauth2==1.0.9
django-oauth-toolkit==2.0.0

【 React側 】
"axios": "^0.27.2",
"gapi-script": "^1.2.0",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-google-login": "^5.2.2",
"react-modal": "^3.15.1",
"react-router-dom": "^6.3.0",
"react-scripts": "^2.1.3",
"web-vitals": "^2.1.4"

公式記載の curl でのアクセスと、 React 側のアクセスでそれぞれエラーメッセージが異なるため、 grant_type がおかしいのが問題なのか、そもそも出力されるアクセストークンが間違っているのか等の見当がつかず、対策がわからない状態です。

React 側からのアクセスの際にユーザプロフィールの出力まで出来ているので、おそらくgrant_typeのエラーだとは思いますが、、、

どなたかわかる方がいらっしゃいましたらご教示頂けると幸いです。
宜しくお願い致します。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問