@@ -588,6 +588,71 @@ def test_access_token_response_valid_token_type(self):
588588 self .assertEqual (token ['token_type' ], constants .TOKEN_TYPE , token )
589589
590590
591+ @ddt .ddt
592+ class ClientCredentialsAccessTokenTests (BaseOAuth2TestCase ):
593+ """ Tests for issuing access tokens using the client credentials grant. """
594+ fixtures = ['test_oauth2.json' ]
595+
596+ def setUp (self ):
597+ super (ClientCredentialsAccessTokenTests , self ).setUp ()
598+ AccessToken .objects .all ().delete ()
599+
600+ def request_access_token (self , client_id = None , client_secret = None ):
601+ """ Issues an access token request using the client credentials grant.
602+
603+ Arguments:
604+ client_id (str): Optional override of the client ID credential.
605+ client_secret (str): Optional override of the client secret credential.
606+
607+ Returns:
608+ HttpResponse
609+ """
610+ client = self .get_client ()
611+ data = {
612+ 'grant_type' : 'client_credentials' ,
613+ 'client_id' : client_id or client .client_id ,
614+ 'client_secret' : client_secret or client .client_secret ,
615+ }
616+
617+ return self .client .post (self .access_token_url (), data )
618+
619+ def assert_valid_access_token_response (self , access_token , response ):
620+ """ Verifies the content of the response contains a JSON representation of the access token.
621+
622+ Note:
623+ The access token should NOT have an associated refresh token.
624+ """
625+ expected = {
626+ u'access_token' : access_token .token ,
627+ u'token_type' : constants .TOKEN_TYPE ,
628+ u'expires_in' : access_token .get_expire_delta (),
629+ u'scope' : u' ' .join (scope .names (access_token .scope )),
630+ }
631+
632+ self .assertEqual (json .loads (response .content ), expected )
633+
634+ def get_latest_access_token (self ):
635+ return AccessToken .objects .filter (client = self .get_client ()).order_by ('-id' )[0 ]
636+
637+ def test_authorize_success (self ):
638+ """ Verify the endpoint successfully issues an access token using the client credentials grant. """
639+ response = self .request_access_token ()
640+ self .assertEqual (200 , response .status_code , response .content )
641+
642+ access_token = self .get_latest_access_token ()
643+ self .assert_valid_access_token_response (access_token , response )
644+
645+ @ddt .data (
646+ {'client_id' : 'invalid' },
647+ {'client_secret' : 'invalid' },
648+ )
649+ def test_authorize_with_invalid_credentials (self , credentials_override ):
650+ """ Verify the endpoint returns HTTP 400 if the credentials are invalid. """
651+ response = self .request_access_token (** credentials_override )
652+ self .assertEqual (400 , response .status_code , response .content )
653+ self .assertDictEqual (json .loads (response .content ), {'error' : 'invalid_client' })
654+
655+
591656class AuthBackendTest (BaseOAuth2TestCase ):
592657 fixtures = ['test_oauth2' ]
593658
0 commit comments