def fetch_tokens(self, client_id=None, client_secret=None, code=None,<EOL>redirect_uri=None, **kwargs):
client_id = client_id or self.client_id<EOL>client_secret = client_secret or self.client_secret<EOL>redirect_uri = redirect_uri or self.redirect_uri<EOL>data = {<EOL>'<STR_LIT>': '<STR_LIT>',<EOL>'<STR_LIT>': client_id,<EOL>'<STR_LIT>': client_secret,<EOL>'<STR_LIT:code>': code,<EOL>'<STR_LIT>': redirect_uri<EOL>}<EOL>r = self._httpclient.request(<EOL>method='<STR_LIT:POST>',<EOL>url=self.token_url,<EOL>json=data,<EOL>path='<STR_LIT>',<EOL>auth=None,<EOL>**kwargs<EOL>)<EOL>if not r.ok:<EOL><INDENT>raise PanCloudError(<EOL>'<STR_LIT>' % (r.status_code, r.reason, r.text)<EOL>)<EOL><DEDENT>try:<EOL><INDENT>r_json = r.json()<EOL><DEDENT>except ValueError as e:<EOL><INDENT>raise PanCloudError("<STR_LIT>" % e)<EOL><DEDENT>else:<EOL><INDENT>if r.json().get(<EOL>'<STR_LIT>'<EOL>) or r.json().get(<EOL>'<STR_LIT:error>'<EOL>):<EOL><INDENT>raise PanCloudError(r.text)<EOL><DEDENT>self.access_token = r_json.get('<STR_LIT>')<EOL>self.jwt_exp = self._decode_exp(self.access_token_)<EOL>self.refresh_token = r_json.get('<STR_LIT>')<EOL>self.write_credentials()<EOL>return r_json<EOL><DEDENT>
Exchange authorization code for token.

        Args:
            client_id (str): OAuth2 client ID. Defaults to ``None``.
            client_secret (str): OAuth2 client secret. Defaults to ``None``.
            code (str): Authorization code. Defaults to ``None``.
            redirect_uri (str): Redirect URI. Defaults to ``None``.

        Returns:
            dict: Response from token URL.