@@ -11,6 +11,7 @@ class TokenApi:
1111 """
1212
1313 refresh_token_url = "https://identity.xero.com/connect/token"
14+ revoke_token_url = "https://identity.xero.com/connect/revocation"
1415
1516 def __init__ (self , api_client , client_id , client_secret ):
1617 self .api_client = api_client
@@ -50,6 +51,35 @@ def refresh_token(self, refresh_token, scope):
5051 # todo validate response is json
5152 return self .parse_token_response (response )
5253
54+ def revoke_token (self , refresh_token ):
55+ """
56+ Call xero identity API to revoke access tokens and remove all a user's connections using refresh token
57+ :param refresh_token: str auth2 refresh token
58+ :return: status response
59+ """
60+ post_data = {
61+ "token" : refresh_token ,
62+ "client_id" : self .client_id ,
63+ "client_secret" : self .client_secret ,
64+ }
65+ response , status , headers = self .api_client .call_api (
66+ self .revoke_token_url ,
67+ "POST" ,
68+ header_params = {
69+ "Accept" : "application/json" ,
70+ "Content-Type" : "application/x-www-form-urlencoded" ,
71+ },
72+ post_params = post_data ,
73+ auth_settings = None , # important to prevent infinite recursive loop
74+ _preload_content = False ,
75+ )
76+ if status != 200 :
77+ # todo improve error handling
78+ raise Exception (
79+ "refresh token status {} {} {!r}" .format (status , response , headers )
80+ )
81+ return status
82+
5383 def parse_token_response (self , response ):
5484 """
5585 Parse token data from http response
@@ -171,6 +201,30 @@ def refresh_access_token(self, api_client):
171201 api_client .set_oauth2_token (new_token )
172202 return True
173203
204+ def revoke_access_token (self , api_client ):
205+ """
206+ Perform auth2 revoke token call.
207+ :param api_client: ApiClient instance used to perform refresh token API call.
208+ :return: bool - True if success
209+ :raise: http request related errors
210+ """
211+ if not self .can_refresh_access_token ():
212+ return False
213+ token_api = TokenApi (api_client , self .client_id , self .client_secret )
214+ token_api .revoke_token (self .refresh_token )
215+ new_token = {
216+ "access_token" : None ,
217+ "refresh_token" : None ,
218+ "scope" : None ,
219+ "expires_at" : None ,
220+ "expires_in" : None ,
221+ "token_type" : "Bearer" ,
222+ "id_token" : None ,
223+ }
224+ self .update_token (** new_token )
225+ api_client .set_oauth2_token (new_token )
226+ return True
227+
174228 def update_token (
175229 self ,
176230 access_token ,
0 commit comments