はじめに
ひろプリがいいぞ! nikkieです。
最近djoserを触っていたのは、ソーシャルアカウントを使った認証がサポートされているらしいと聞いたためです。
いよいよ本題に切り込みます
目次
djoserのドキュメント「Social Endpoints」
※Social Endpointsはベータとのことです
REST APIの認証系エンドポイントを追加できるライブラリdjoser1。
ソーシャルアカウントで認証できるエンドポイントを触ってみます。
ワークフロー
「Social Endpoints」ドキュメントの中の「Provider Auth」にある箇条書きより
- djoserが追加するエンドポイントに
redirect_uriを渡してアクセス(GET)redirect_uriは私たちが開発しているアプリケーションのエンドポイント
authorization_urlというキーを持つJSONが返る。アプリケーションのユーザをそのURLへリダイレクトauthorization_urlは外部のソーシャルサービスのエンドポイント
- アプリケーションのユーザは外部のソーシャルサービスで認証される。外部のサービスは1の
redirect_uriにGETリクエスト(クエリ文字列のキーにcodeとstateを持つ) - 3の
codeとstateを使って、1のエンドポイントにPOSTリクエスト(application/x-www-form-urlencoded)。私たちのアプリケーションでも認証される
djoserは/o/{{ provider }}/というURLを追加しています。
- 1では
/o/{{ provider }}/にredirect_uriパラメタ(クエリ文字列)を渡してGETリクエスト - 4では
/o/{{ provider }}/にcodeとstateパラメタ(application/x-www-form-urlencoded)を渡してPOSTリクエスト
Google OAuth2の例
Python 3.11.8
- djoser==2.2.2
- django-environ==0.11.2
OAuth 2.0 Client IDを作る
Google CloudのConsoleにて
「APIとサービス」 > 「認証情報」から作ります。
- typeは「Webアプリケーション」
- Authorized redirect URIsに http://127.0.0.1:8000/accounts/profile/ を指定
Djangoの設定
プロジェクトのurls.py
urlpatterns = [
path("api/auth/social/", include("djoser.social.urls")),
path("accounts/profile/", RedirectSocialView.as_view()),
]
social.py(プロジェクトの中に作成)
from django.http import JsonResponse from django.views import View class RedirectSocialView(View): def get(self, request): return JsonResponse( { "code": str(request.GET["code"]), "state": str(request.GET["state"]), } )
settings.py
INSTALLED_APPS = [
# ...
"rest_framework",
"djoser",
"social_django",
# ...
]
MIDDLEWARE = [
"social_django.middleware.SocialAuthExceptionMiddleware",
# ...
]
AUTHENTICATION_BACKENDS = (
"social_core.backends.google.GoogleOAuth2",
)
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY = env("SOCIAL_AUTH_GOOGLE_OAUTH2_KEY")
SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET = env("SOCIAL_AUTH_GOOGLE_OAUTH2_SECRET")
DJOSER = {
"SOCIAL_AUTH_ALLOWED_REDIRECT_URIS": ["http://127.0.0.1:8000/accounts/profile/"]
}
動作確認
Browsable APIで動いた!

authorization_urlが返っています!
これをブラウザの別のタブで開きます。
codeとstateからなるJSONが確認できます(RedirectSocialViewの実装による)。
再びBrowsable APIに戻り、「Raw data」をPOSTします。
- Media typeは「application/x-www-form-urlencoded」
- Contentは「code=...&state=...」

すると、JSONが返ってきます。成功です!(201)
{ "access": "...", "refresh": "...", "user": "Googleアカウントのユーザ名" }
curlではうまくいかない
ずっとcurlでやっていてハマり続けました。
% curl 'http://127.0.0.1:8000/api/auth/social/o/google-oauth2/?redirect_uri=http://127.0.0.1:8000/accounts/profile/'
{"authorization_url":"..."}
authorization_urlにブラウザでアクセス。
codeとstateからなるJSONを確認します。
% curl -L -d 'state=...' -d 'code=...' http://127.0.0.1:8000/api/auth/social/o/google-oauth2/
{"non_field_errors":["Session value state missing."]}
400 Bad Requestです。
breakpointを仕込んでいったところ、どうやら以下で出ているようで、
https://github.com/python-social-auth/social-core/blob/4.5.4/social_core/backends/oauth.py#L100-L101
Browsable APIからだとセッション(cookie)の関係でうまくいっているのではないかと考えています(真偽不明)(curlでもcookieの扱い、できるのかな?)
Browsable APIで動いたものの
ここからどうすればいいかが分かりません。
access, refresh, userからなるJSONで何ができるんでしょう?
アクセストークンが取得できているので、ユーザが認可したGoogleのAPIにリクエストを送れるようですが、accessの値をそのまま使っていいのかな?(宿題事項)
私が気になっていたのは、「Social Endpoints」を使ってDjangoアプリにログインしたことにできるのかということなのですが、この点もよく分かっていません(DjangoアプリのBearerトークンが発行できたらいいが、果たして)
終わりに
curlで実施していたために、djoserの「Social Endpoints」のGoogle OAuth2が通らずハマりました。
Browsable APIでは実行でき、「Social Endpoints」のドキュメントの意味はかなり分かりました。
返ってきたアクセストークンを扱ってソーシャルサービスを利用したり、ソーシャルアカウントを使ってDjangoアプリで認証(DjangoアプリのREST APIを叩くためのトークン発行)したりできるのかが、まだ分かっていません
参照したもの
どちらもドンピシャではなかったです。
あと、どちらの記事もやりたいことに対して扱っているものが余分に思われ(すべてのコードに説明がされておらず、おまじないがある感)、新しい概念が多すぎましたし、最小限の見定めが難しかったです
P.S. 5/18(土) Djangoもくもく会
この記事はもくもくの成果物です。
nibuさんの成果物
次回は6月です。よろしければ!