diff --git a/README.md b/README.md index 1c94329..cc68752 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Requirements - djangorestframework (>=3.1, <4.0) - social-auth-core (>=3.0, <4.0) - social-auth-app-django (>=3.1, <4.0) -- [optional] djangorestframework-jwt (>=1.7.2) +- [optional] djangorestframework-simplejwt (>=4.0.0) - [optional] django-rest-knox (>=3.2.0) Release notes @@ -85,19 +85,33 @@ Quick start 4.1 [session authentication](http://www.django-rest-framework.org/api-guide/authentication/#sessionauthentication) - url(r'^api/login/', include('rest_social_auth.urls_session')), + ```python + url(r'^api/login/', include('rest_social_auth.urls_session')), + ``` 4.2 [token authentication](http://www.django-rest-framework.org/api-guide/authentication/#tokenauthentication) - url(r'^api/login/', include('rest_social_auth.urls_token')), + ```python + url(r'^api/login/', include('rest_social_auth.urls_token')), + ``` + + 4.3 [jwt authentication](https://github.com/davesque/django-rest-framework-simplejwt) - 4.3 [jwt authentication](http://getblimp.github.io/django-rest-framework-jwt/) + ```python + url(r'^api/login/', include('rest_social_auth.urls_jwt_pair')), + ``` - url(r'^api/login/', include('rest_social_auth.urls_jwt')), + or / and + + ```python + url(r'^api/login/', include('rest_social_auth.urls_jwt_sliding')), + ``` 4.4 [knox authentication](https://github.com/James1345/django-rest-knox/) - url(r'^api/login/', include('rest_social_auth.urls_knox')), + ```python + url(r'^api/login/', include('rest_social_auth.urls_knox')), + ``` 5. You are ready to login users @@ -161,14 +175,29 @@ Quick start 5.3 jwt authentication - - POST /api/login/social/jwt/ - - POST /api/login/social/jwt_user/ + - POST /api/login/social/jwt-pair/ + - POST /api/login/social/jwt-pair-user/ Similar to token authentication, but token is JSON Web Token. See [JWT.io](http://jwt.io/) for details. - To use it, [django-rest-framework-jwt](https://github.com/GetBlimp/django-rest-framework-jwt) must be installed. + To use it, [django-rest-framework-simplejwt](https://github.com/davesque/django-rest-framework-simplejwt) must be installed. + + For `jwt-pair`, the response will include additional "refresh" token: + ```json + { + "token": "...", + "refresh": "..." + } + ``` + + ##### Or sliding JWT token: + + - POST /api/login/social/jwt-sliding/ + - POST /api/login/social/jwt-sliding-user/ + + Check [docs of simplejwt](https://github.com/davesque/django-rest-framework-simplejwt#token-types) for pair/sliding token difference. 5.4 knox authentication diff --git a/example_project/config/urls.py b/example_project/config/urls.py index 18430c0..ef3cd87 100644 --- a/example_project/config/urls.py +++ b/example_project/config/urls.py @@ -14,15 +14,15 @@ url(r'^api/login/', include('rest_social_auth.urls_session')), url(r'^api/login/', include('rest_social_auth.urls_token')), - url(r'^api/login/', include('rest_social_auth.urls_simplejwt_pair')), - url(r'^api/login/', include('rest_social_auth.urls_simplejwt_sliding')), + url(r'^api/login/', include('rest_social_auth.urls_jwt_pair')), + url(r'^api/login/', include('rest_social_auth.urls_jwt_sliding')), url(r'^api/login/', include('rest_social_auth.urls_jwt')), url(r'^api/login/', include('rest_social_auth.urls_knox')), url(r'^api/logout/session/$', views.LogoutSessionView.as_view(), name='logout_session'), url(r'^api/user/session/', views.UserSessionDetailView.as_view(), name="current_user_session"), url(r'^api/user/token/', views.UserTokenDetailView.as_view(), name="current_user_token"), - url(r'^api/user/jwt/', views.UserSimpleJWTDetailView.as_view(), name="current_user_jwt"), + url(r'^api/user/jwt/', views.UserJWTDetailView.as_view(), name="current_user_jwt"), url(r'^api/user/jwt-old/', views.UserJWTOldDetailView.as_view(), name="current_user_jwt_old"), url(r'^api/user/knox/', views.UserKnoxDetailView.as_view(), name="current_user_knox"), ] diff --git a/example_project/templates/home_jwt.html b/example_project/templates/home_jwt.html index 6cea508..8baeb07 100644 --- a/example_project/templates/home_jwt.html +++ b/example_project/templates/home_jwt.html @@ -74,16 +74,16 @@

Raw JWT payload

angular.module('JWTApp', ['satellizer']) .config(function($authProvider) { $authProvider.facebook({ - url: "{% url 'login_social_simplejwt_pair_user' provider='facebook' %}", + url: "{% url 'login_social_jwt_pair_user' provider='facebook' %}", clientId: '{{ facebook_key }}' }); $authProvider.google({ - url: "{% url 'login_social_simplejwt_pair_user' provider='google-oauth2' %}", + url: "{% url 'login_social_jwt_pair_user' provider='google-oauth2' %}", clientId: '{{ googleoauth2_key }}', redirectUri: window.location.origin + '/' }); $authProvider.twitter({ - url: "{% url 'login_social_simplejwt_pair_user' provider='twitter' %}", + url: "{% url 'login_social_jwt_pair_user' provider='twitter' %}", }); $authProvider.authToken = 'JWT'; $authProvider.tokenPrefix = 'satellizer_simple_jwt'; // to not collide with regular token auth diff --git a/example_project/users/views.py b/example_project/users/views.py index 14b4458..c3101ba 100644 --- a/example_project/users/views.py +++ b/example_project/users/views.py @@ -63,7 +63,7 @@ class UserJWTOldDetailView(JWTAuthMixin, BaseDetailView): pass -class UserSimpleJWTDetailView(SimpleJWTAuthMixin, BaseDetailView): +class UserJWTDetailView(SimpleJWTAuthMixin, BaseDetailView): pass diff --git a/rest_social_auth/serializers.py b/rest_social_auth/serializers.py index c9bbb8d..ff5349f 100644 --- a/rest_social_auth/serializers.py +++ b/rest_social_auth/serializers.py @@ -43,36 +43,6 @@ class UserTokenSerializer(TokenSerializer, UserSerializer): pass -class JWTSerializer(TokenSerializer): - - def get_token(self, obj): - try: - from rest_framework_jwt.settings import api_settings - except ImportError: - warnings.warn('djangorestframework-jwt must be installed for JWT authentication', - ImportWarning) - raise - - jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER - jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER - - payload = jwt_payload_handler(self.get_jwt_payload(obj)) - token = jwt_encode_handler(payload) - - return token - - def get_jwt_payload(self, obj): - """ - Define here, what data shall be encoded in JWT. - By default, entire object will be encoded. - """ - return obj - - -class UserJWTSerializer(JWTSerializer, UserSerializer): - pass - - class KnoxSerializer(TokenSerializer): def get_token(self, obj): try: @@ -89,7 +59,7 @@ class UserKnoxSerializer(KnoxSerializer, UserSerializer): pass -class SimpleJWTBaseSerializer(serializers.Serializer): +class JWTBaseSerializer(serializers.Serializer): jwt_token_class_name = None @@ -120,7 +90,7 @@ def get_token_payload(self, user): return {} -class SimpleJWTPairSerializer(SimpleJWTBaseSerializer): +class JWTPairSerializer(JWTBaseSerializer): token = serializers.SerializerMethodField() refresh = serializers.SerializerMethodField() @@ -133,7 +103,7 @@ def get_refresh(self, obj): return str(self.get_token_instance()) -class UserSimplePairJWTSerializer(SimpleJWTPairSerializer, UserSerializer): +class UserJWTPairSerializer(JWTPairSerializer, UserSerializer): def get_token_payload(self, user): payload = dict(UserSerializer(user).data) @@ -141,7 +111,7 @@ def get_token_payload(self, user): return payload -class SimpleJWTSlidingSerializer(SimpleJWTBaseSerializer): +class JWTSlidingSerializer(JWTBaseSerializer): token = serializers.SerializerMethodField() jwt_token_class_name = 'SlidingToken' @@ -150,9 +120,45 @@ def get_token(self, obj): return str(self.get_token_instance()) -class UserSimpleJWTSlidingSerializer(SimpleJWTSlidingSerializer, UserSerializer): +class UserJWTSlidingSerializer(JWTSlidingSerializer, UserSerializer): def get_token_payload(self, user): payload = dict(UserSerializer(user).data) payload.pop('id', None) return payload + + +# Depcreated Seraizlisers +class JWTSerializer(TokenSerializer): + + def get_token(self, obj): + warnings.warn( + 'Support of djangorestframework-jwt will be removed in 3.0.0 version. ' + 'Use rest_framework_simplejwt instead.', + DeprecationWarning, + ) + try: + from rest_framework_jwt.settings import api_settings + except ImportError: + warnings.warn('djangorestframework-jwt must be installed for JWT authentication', + ImportWarning) + raise + + jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER + jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER + + payload = jwt_payload_handler(self.get_jwt_payload(obj)) + token = jwt_encode_handler(payload) + + return token + + def get_jwt_payload(self, obj): + """ + Define here, what data shall be encoded in JWT. + By default, entire object will be encoded. + """ + return obj + + +class UserJWTSerializer(JWTSerializer, UserSerializer): + pass diff --git a/rest_social_auth/urls_simplejwt_pair.py b/rest_social_auth/urls_jwt_pair.py similarity index 56% rename from rest_social_auth/urls_simplejwt_pair.py rename to rest_social_auth/urls_jwt_pair.py index ab7730e..3e56738 100644 --- a/rest_social_auth/urls_simplejwt_pair.py +++ b/rest_social_auth/urls_jwt_pair.py @@ -6,10 +6,10 @@ urlpatterns = ( # returns token only url(r'^social/jwt-pair/(?:(?P[a-zA-Z0-9_-]+)/?)?$', - views.SocialSimpleJWTPairOnlyAuthView.as_view(), - name='login_social_simplejwt_pair'), + views.SocialJWTPairOnlyAuthView.as_view(), + name='login_social_jwt_pair'), # returns token + user_data url(r'^social/jwt-pair-user/(?:(?P[a-zA-Z0-9_-]+)/?)?$', - views.SocialSimpleJWTPairUserAuthView.as_view(), - name='login_social_simplejwt_pair_user'), + views.SocialJWTPairUserAuthView.as_view(), + name='login_social_jwt_pair_user'), ) diff --git a/rest_social_auth/urls_simplejwt_sliding.py b/rest_social_auth/urls_jwt_sliding.py similarity index 55% rename from rest_social_auth/urls_simplejwt_sliding.py rename to rest_social_auth/urls_jwt_sliding.py index 4bba74f..60bea24 100644 --- a/rest_social_auth/urls_simplejwt_sliding.py +++ b/rest_social_auth/urls_jwt_sliding.py @@ -6,10 +6,10 @@ urlpatterns = ( # returns token only url(r'^social/jwt-sliding/(?:(?P[a-zA-Z0-9_-]+)/?)?$', - views.SocialSimpleJWTSlidingOnlyAuthView.as_view(), - name='login_social_simplejwt_sliding'), + views.SocialJWTSlidingOnlyAuthView.as_view(), + name='login_social_jwt_sliding'), # returns token + user_data url(r'^social/jwt-sliding-user/(?:(?P[a-zA-Z0-9_-]+)/?)?$', - views.SocialSimpleJWTSlidingUserAuthView.as_view(), - name='login_social_simplejwt_sliding_user'), + views.SocialJWTSlidingUserAuthView.as_view(), + name='login_social_jwt_sliding_user'), ) diff --git a/rest_social_auth/views.py b/rest_social_auth/views.py index b2d3517..ec6245a 100644 --- a/rest_social_auth/views.py +++ b/rest_social_auth/views.py @@ -27,18 +27,18 @@ from requests.exceptions import HTTPError from .serializers import ( + JWTPairSerializer, JWTSerializer, + JWTSlidingSerializer, KnoxSerializer, OAuth1InputSerializer, OAuth2InputSerializer, - SimpleJWTPairSerializer, - SimpleJWTSlidingSerializer, TokenSerializer, UserJWTSerializer, + UserJWTSlidingSerializer, UserKnoxSerializer, + UserJWTPairSerializer, UserSerializer, - UserSimpleJWTSlidingSerializer, - UserSimplePairJWTSerializer, UserTokenSerializer, ) @@ -228,31 +228,6 @@ class SocialTokenUserAuthView(BaseSocialAuthView): authentication_classes = (TokenAuthentication, ) -class JWTAuthMixin(object): - def get_authenticators(self): - warnings.warn( - 'Support of djangorestframework-jwt will be removed in 3.0.0 version. ' - 'Use rest_framework_simplejwt instead.', - DeprecationWarning, - ) - try: - from rest_framework_jwt.authentication import JSONWebTokenAuthentication - except ImportError: - warnings.warn('djangorestframework-jwt must be installed for JWT authentication', - ImportWarning) - raise - - return [JSONWebTokenAuthentication()] - - -class SocialJWTOnlyAuthView(JWTAuthMixin, BaseSocialAuthView): - serializer_class = JWTSerializer - - -class SocialJWTUserAuthView(JWTAuthMixin, BaseSocialAuthView): - serializer_class = UserJWTSerializer - - class KnoxAuthMixin(object): def get_authenticators(self): try: @@ -286,17 +261,43 @@ def get_authenticators(self): return [JWTAuthentication()] -class SocialSimpleJWTPairOnlyAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): - serializer_class = SimpleJWTPairSerializer +class SocialJWTPairOnlyAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): + serializer_class = JWTPairSerializer -class SocialSimpleJWTPairUserAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): - serializer_class = UserSimplePairJWTSerializer +class SocialJWTPairUserAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): + serializer_class = UserJWTPairSerializer -class SocialSimpleJWTSlidingOnlyAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): - serializer_class = SimpleJWTSlidingSerializer +class SocialJWTSlidingOnlyAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): + serializer_class = JWTSlidingSerializer -class SocialSimpleJWTSlidingUserAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): - serializer_class = UserSimpleJWTSlidingSerializer +class SocialJWTSlidingUserAuthView(SimpleJWTAuthMixin, BaseSocialAuthView): + serializer_class = UserJWTSlidingSerializer + + +# Deprecated views +class JWTAuthMixin(object): + def get_authenticators(self): + warnings.warn( + 'Support of djangorestframework-jwt will be removed in 3.0.0 version. ' + 'Use rest_framework_simplejwt instead.', + DeprecationWarning, + ) + try: + from rest_framework_jwt.authentication import JSONWebTokenAuthentication + except ImportError: + warnings.warn('djangorestframework-jwt must be installed for JWT authentication', + ImportWarning) + raise + + return [JSONWebTokenAuthentication()] + + +class SocialJWTOnlyAuthView(JWTAuthMixin, BaseSocialAuthView): + serializer_class = JWTSerializer + + +class SocialJWTUserAuthView(JWTAuthMixin, BaseSocialAuthView): + serializer_class = UserJWTSerializer diff --git a/tests/test_social.py b/tests/test_social.py index a396cc9..357aa20 100644 --- a/tests/test_social.py +++ b/tests/test_social.py @@ -228,33 +228,6 @@ def _check_login_social_token_only(self, url, data): # check user is created self.assertEqual(token.user.email, self.email) - @modify_settings(**jwt_modify_settings) - def _check_login_social_jwt_only(self, url, data): - try: - from rest_framework_jwt.settings import api_settings - except ImportError: - return - jwt_decode_handler = api_settings.JWT_DECODE_HANDLER - resp = self.client.post(url, data) - self.assertEqual(resp.status_code, 200) - # check token valid - jwt_data = jwt_decode_handler(resp.data['token']) - self.assertEqual(jwt_data['email'], self.email) - - @modify_settings(**jwt_modify_settings) - def _check_login_social_jwt_user(self, url, data): - try: - from rest_framework_jwt.settings import api_settings - except ImportError: - return - jwt_decode_handler = api_settings.JWT_DECODE_HANDLER - resp = self.client.post(url, data) - self.assertEqual(resp.status_code, 200) - self.assertEqual(resp.data['email'], self.email) - # check token valid - jwt_data = jwt_decode_handler(resp.data['token']) - self.assertEqual(jwt_data['email'], self.email) - @modify_settings(**jwt_modify_settings) @override_settings(SIMPLE_JWT={ 'AUTH_TOKEN_CLASSES': ( @@ -262,7 +235,7 @@ def _check_login_social_jwt_user(self, url, data): 'rest_framework_simplejwt.tokens.SlidingToken', ), }) - def _check_login_social_simple_jwt_only(self, url, data, token_type): + def _check_login_social_jwt_only(self, url, data, token_type): try: from rest_framework_simplejwt.authentication import JWTAuthentication except ImportError: @@ -281,7 +254,7 @@ def _check_login_social_simple_jwt_only(self, url, data, token_type): 'rest_framework_simplejwt.tokens.SlidingToken', ), }) - def _check_login_social_simple_jwt_user(self, url, data, token_type): + def _check_login_social_jwt_user(self, url, data, token_type): try: from rest_framework_simplejwt.authentication import JWTAuthentication except ImportError: @@ -350,79 +323,58 @@ def test_login_social_token_only_provider_in_url(self): reverse('login_social_token', kwargs={'provider': 'facebook'}), data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}) - def test_login_social_jwt_only(self): + def test_login_social_jwt_pair_only(self): self._check_login_social_jwt_only( - reverse('login_social_jwt'), - data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}) - - def test_login_social_jwt_only_provider_in_url(self): - self._check_login_social_jwt_only( - reverse('login_social_jwt', kwargs={'provider': 'facebook'}), - data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}) - - def test_login_social_jwt_user(self): - self._check_login_social_jwt_user( - reverse('login_social_jwt_user'), - data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}) - - def test_login_social_jwt_user_provider_in_url(self): - self._check_login_social_jwt_user( - reverse('login_social_jwt_user', kwargs={'provider': 'facebook'}), - data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}, - ) - - def test_login_social_simplejwt_pair_only(self): - self._check_login_social_simple_jwt_only( - reverse('login_social_simplejwt_pair'), + reverse('login_social_jwt_pair'), data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='access', ) - def test_login_social_simplejwt_pair_only_provider_in_url(self): - self._check_login_social_simple_jwt_only( - reverse('login_social_simplejwt_pair', kwargs={'provider': 'facebook'}), + def test_login_social_jwt_pair_only_provider_in_url(self): + self._check_login_social_jwt_only( + reverse('login_social_jwt_pair', kwargs={'provider': 'facebook'}), data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='access', ) - def test_login_social_simplejwt_pair_user(self): - self._check_login_social_simple_jwt_user( - reverse('login_social_simplejwt_pair_user'), + def test_login_social_jwt_pair_user(self): + self._check_login_social_jwt_user( + reverse('login_social_jwt_pair_user'), data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='access', ) - def test_login_social_simplejwt_pair_user_provider_in_url(self): - self._check_login_social_simple_jwt_user( - reverse('login_social_simplejwt_pair_user', kwargs={'provider': 'facebook'}), + def test_login_social_jwt_pair_user_provider_in_url(self): + self._check_login_social_jwt_user( + reverse('login_social_jwt_pair_user', kwargs={'provider': 'facebook'}), data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='access', ) - def test_login_social_simplejwt_sliding_only(self): - self._check_login_social_simple_jwt_only( - reverse('login_social_simplejwt_sliding'), + def test_login_social_jwt_sliding_only(self): + self._check_login_social_jwt_only( + reverse('login_social_jwt_sliding'), data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='sliding', ) - def test_login_social_simplejwt_sliding_only_provider_in_url(self): - self._check_login_social_simple_jwt_only( - reverse('login_social_simplejwt_sliding', kwargs={'provider': 'facebook'}), + def test_login_social_jwt_sliding_only_provider_in_url(self): + self._check_login_social_jwt_only( + reverse('login_social_jwt_sliding', kwargs={'provider': 'facebook'}), data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='sliding', ) - def test_login_social_simplejwt_sliding_user(self): - self._check_login_social_simple_jwt_user( - reverse('login_social_simplejwt_sliding_user'), + def test_login_social_jwt_sliding_user(self): + self._check_login_social_jwt_user( + reverse('login_social_jwt_sliding_user'), data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='sliding', ) - def test_login_social_simplejwt_sliding_user_provider_in_url(self): - self._check_login_social_simple_jwt_user( - reverse('login_social_simplejwt_sliding_user', kwargs={'provider': 'facebook'}), + def test_login_social_jwt_sliding_user_provider_in_url(self): + self._check_login_social_jwt_user( + reverse('login_social_jwt_sliding_user', kwargs={'provider': 'facebook'}), data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}, token_type='sliding', ) @@ -505,6 +457,56 @@ def test_user_login_with_no_email(self): self.assertEqual(resp.status_code, 400) self.assertIn('error', resp.data) + # Deprecated tests + + @modify_settings(**jwt_modify_settings) + def _deprecated_check_login_social_jwt_only(self, url, data): + try: + from rest_framework_jwt.settings import api_settings + except ImportError: + return + jwt_decode_handler = api_settings.JWT_DECODE_HANDLER + resp = self.client.post(url, data) + self.assertEqual(resp.status_code, 200) + # check token valid + jwt_data = jwt_decode_handler(resp.data['token']) + self.assertEqual(jwt_data['email'], self.email) + + @modify_settings(**jwt_modify_settings) + def _deprecated_check_login_social_jwt_user(self, url, data): + try: + from rest_framework_jwt.settings import api_settings + except ImportError: + return + jwt_decode_handler = api_settings.JWT_DECODE_HANDLER + resp = self.client.post(url, data) + self.assertEqual(resp.status_code, 200) + self.assertEqual(resp.data['email'], self.email) + # check token valid + jwt_data = jwt_decode_handler(resp.data['token']) + self.assertEqual(jwt_data['email'], self.email) + + def test_deprecated_login_social_jwt_only(self): + self._deprecated_check_login_social_jwt_only( + reverse('login_social_jwt'), + data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}) + + def test_deprecated_login_social_jwt_only_provider_in_url(self): + self._deprecated_check_login_social_jwt_only( + reverse('login_social_jwt', kwargs={'provider': 'facebook'}), + data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}) + + def test_deprecated_login_social_jwt_user(self): + self._deprecated_check_login_social_jwt_user( + reverse('login_social_jwt_user'), + data={'provider': 'facebook', 'code': '3D52VoM1uiw94a1ETnGvYlCw'}) + + def test_deprecated_login_social_jwt_user_provider_in_url(self): + self._deprecated_check_login_social_jwt_user( + reverse('login_social_jwt_user', kwargs={'provider': 'facebook'}), + data={'code': '3D52VoM1uiw94a1ETnGvYlCw'}, + ) + class TestSocialAuth2Error(APITestCase, BaseFacebookAPITestCase): access_token_status = 400