@@ -133,6 +133,12 @@ def is_authenticated(self) -> bool:
133133 self ._refresh_token ()
134134 return True
135135 return False
136+
137+ def is_authenticated_token (self , token_value : dict ) -> dict :
138+ if token_value :
139+ if token_value .is_expired ():
140+ return self ._refresh_token_value (token_value )
141+ return None
136142
137143 def create_org (self ) -> str :
138144 return f"{ self .registration_url } &is_create_org=true"
@@ -145,23 +151,50 @@ def get_claim(self, key: str, token_name: str = "access_token") -> Any:
145151 self ._decode_token_if_needed (token_name )
146152 value = self .__decoded_tokens [token_name ].get (key )
147153 return {"name" : key , "value" : value }
154+
155+ def get_claim_token (self , token_value : dict , key : str , token_name : str = "access_token" ) -> Any :
156+ if token_name not in self .TOKEN_NAMES :
157+ raise KindeTokenException (
158+ f"Please use only tokens from the list: { self .TOKEN_NAMES } "
159+ )
160+
161+ decoded_tokens = self ._decode_token_if_needed_value (token_name ,token_value )
162+ value = decoded_tokens [token_name ].get (key )
163+ return {"name" : key , "value" : value }
148164
149165 def get_permission (self , permission : str ) -> Dict [str , Any ]:
150166 return {
151167 "org_code" : self .get_claim ("org_code" )["value" ],
152168 "is_granted" : permission in self .get_claim ("permissions" )["value" ],
153169 }
170+
171+ def get_permission_token (self , token_value : dict , permission : str ) -> Dict [str , Any ]:
172+ return {
173+ "org_code" : self .get_claim_token (token_value , "org_code" )["value" ],
174+ "is_granted" : permission in self .get_claim_token (token_value , "permissions" )["value" ],
175+ }
154176
155177 def get_permissions (self ) -> Dict [str , Any ]:
156178 return {
157179 "org_code" : self .get_claim ("org_code" )["value" ],
158180 "permissions" : self .get_claim ("permissions" )["value" ],
159181 }
182+
183+ def get_permissions_token (self , token_value : dict ) -> Dict [str , Any ]:
184+ return {
185+ "org_code" : self .get_claim_token (token_value , "org_code" )["value" ],
186+ "permissions" : self .get_claim_token (token_value , "permissions" )["value" ],
187+ }
160188
161189 def get_organization (self ) -> Dict [str , str ]:
162190 return {
163191 "org_code" : self .get_claim ("org_code" )["value" ],
164192 }
193+
194+ def get_organization_token (self , token_value : dict ) -> Dict [str , str ]:
195+ return {
196+ "org_code" : self .get_claim_token (token_value , "org_code" )["value" ],
197+ }
165198
166199 def get_user_details (self ) -> Dict [str , str ]:
167200 return {
@@ -171,11 +204,25 @@ def get_user_details(self) -> Dict[str, str]:
171204 "email" : self .get_claim ("email" , "id_token" )["value" ],
172205 "picture" : self .get_claim ("picture" , "id_token" )["value" ],
173206 }
207+
208+ def get_user_details_token (self ,token_value : dict ) -> Dict [str , str ]:
209+ return {
210+ "id" : self .get_claim_token (token_value , "sub" ,"id_token" )["value" ],
211+ "given_name" : self .get_claim_token (token_value , "given_name" , "id_token" )["value" ],
212+ "family_name" : self .get_claim_token (token_value , "family_name" , "id_token" )["value" ],
213+ "email" : self .get_claim_token (token_value , "email" , "id_token" )["value" ],
214+ "picture" : self .get_claim_token (token_value , "picture" , "id_token" )["value" ],
215+ }
174216
175217 def get_user_organizations (self ) -> Dict [str , List [str ]]:
176218 return {
177219 "org_codes" : self .get_claim ("org_codes" , "id_token" )["value" ],
178220 }
221+
222+ def get_user_organizations_token (self , token_value : dict ) -> Dict [str , List [str ]]:
223+ return {
224+ "org_codes" : self .get_claim_token (token_value , "org_codes" , "id_token" )["value" ],
225+ }
179226
180227 def get_flag (
181228 self , code : str , default_value : Any = None , flag_type : str = ""
@@ -205,15 +252,53 @@ def get_flag(
205252 result_flag ["type" ] = FlagType [flag_type ].value
206253
207254 return result_flag
255+
256+ def get_flag_token (
257+ self , token_value : dict , code : str , default_value : Any = None , flag_type : str = ""
258+ ) -> Any :
259+ flags = self .get_claim_token (token_value , "feature_flags" )["value" ] or {}
260+ flag = {}
261+
262+ if code not in list (flags .keys ()):
263+ if default_value is None :
264+ raise KindeRetrieveException (
265+ f"Flag { code } was not found, and no default value has been provided"
266+ )
267+ else :
268+ flag = flags [code ]
269+ if flag_type and flag .get ("t" ) and flag_type != flag .get ("t" ):
270+ raise KindeRetrieveException (
271+ f"Flag { code } is of type { FlagType [flag .get ('t' )].value } - requested type { FlagType [flag_type ].value } "
272+ )
273+
274+ result_flag = {
275+ "code" : code ,
276+ "value" : flag .get ("v" ) if flag else default_value ,
277+ "is_default" : not bool (flag ),
278+ }
279+ flag_type = flag ["t" ] if flag else flag_type
280+ if flag_type :
281+ result_flag ["type" ] = FlagType [flag_type ].value
282+
283+ return result_flag
208284
209285 def get_boolean_flag (self , code : str , default_value : Any = None ) -> bool :
210286 return self .get_flag (code , default_value , "b" )["value" ]
287+
288+ def get_boolean_flag_token (self , token_value : dict , code : str , default_value : Any = None ) -> bool :
289+ return self .get_flag_token (token_value , code , default_value , "b" )["value" ]
211290
212291 def get_string_flag (self , code : str , default_value : Any = None ) -> str :
213292 return self .get_flag (code , default_value , "s" )["value" ]
293+
294+ def get_string_flag_token (self , token_value : dict , code : str , default_value : Any = None ) -> str :
295+ return self .get_flag_token (token_value , code , default_value , "s" )["value" ]
214296
215297 def get_integer_flag (self , code : str , default_value : Any = None ) -> int :
216298 return self .get_flag (code , default_value , "i" )["value" ]
299+
300+ def get_integer_flag_token (self , token_value : dict , code : str , default_value : Any = None ) -> int :
301+ return self .get_flag_token (token_value , code , default_value , "i" )["value" ]
217302
218303 def call_api (self , * args , ** kwargs ) -> Any :
219304 self ._get_or_refresh_access_token ()
@@ -248,6 +333,34 @@ def _decode_token_if_needed(self, token_name: str) -> None:
248333 self .__decoded_tokens [token_name ] = jwt .decode (** decode_token_params )
249334 else :
250335 raise KindeTokenException (f"Token { token_name } doesn't exist." )
336+
337+ def _decode_token_if_needed_value (self , token_name : str , token_value : dict ) -> dict :
338+ if token_name not in token_value :
339+ if not token_value :
340+ raise KindeTokenException (
341+ "Access token doesn't exist.\n "
342+ "When grant_type is CLIENT_CREDENTIALS use fetch_token().\n "
343+ 'For other grant_type use "get_login_url()" or "get_register_url()".'
344+ )
345+ token = token_value .get (token_name )
346+
347+ signing_key = self .jwks_client .get_signing_key_from_jwt (token )
348+
349+ if token :
350+ decode_token_params = {
351+ "jwt" :token ,
352+ "key" : signing_key .key ,
353+ "algorithms" :["RS256" ],
354+ "options" :{
355+ "verify_signature" : True ,
356+ "verify_exp" : True ,
357+ "verify_aud" : False
358+ }
359+ }
360+ return jwt .decode (** decode_token_params )
361+ else :
362+ raise KindeTokenException (f"Token { token_name } doesn't exist." )
363+ return token_value
251364
252365 def fetch_token (self , authorization_response : Optional [str ] = None ) -> None :
253366 if self .grant_type == GrantType .CLIENT_CREDENTIALS :
@@ -274,6 +387,31 @@ def fetch_token(self, authorization_response: Optional[str] = None) -> None:
274387 self .configuration .access_token = self .__access_token_obj .get ("access_token" )
275388 self ._clear_decoded_tokens ()
276389
390+ def fetch_token_value (self , authorization_response : Optional [str ] = None ) -> dict :
391+ if self .grant_type == GrantType .CLIENT_CREDENTIALS :
392+ params = {"grant_type" : "client_credentials" }
393+ if self .audience :
394+ params ["audience" ] = self .audience
395+ else :
396+ if authorization_response is None :
397+ raise KindeConfigurationException (
398+ '"authorization_response" parameter is required when grant_type is different than CLIENT_CREDENTIALS.'
399+ )
400+ params = {"authorization_response" : authorization_response }
401+ if self .grant_type == GrantType .AUTHORIZATION_CODE_WITH_PKCE :
402+ params ["code_verifier" ] = self .code_verifier
403+
404+ access_token_obj = self .client .fetch_token (
405+ self .token_endpoint ,
406+ headers = {
407+ "Content-Type" : "application/x-www-form-urlencoded" ,
408+ "Kinde-SDK" : "/" .join (("Python" , kinde_sdk_version )),
409+ },
410+ ** params ,
411+ )
412+ return access_token_obj
413+
414+
277415 def _get_or_refresh_access_token (self ) -> None :
278416 if self .grant_type == GrantType .CLIENT_CREDENTIALS :
279417 if not self .__access_token_obj or self .__access_token_obj .is_expired ():
@@ -309,6 +447,27 @@ def _refresh_token(self) -> None:
309447 self ._clear_decoded_tokens ()
310448 else :
311449 raise KindeTokenException ('"Access token" and "Refresh token" are invalid.' )
450+
451+ def _refresh_token_value (self , token_value : dict ) -> dict :
452+ refresh_token = token_value .get ("refresh_token" )
453+
454+ if refresh_token :
455+ token_value = self .client .refresh_token (
456+ self .token_endpoint ,
457+ headers = {
458+ "Content-Type" : "application/x-www-form-urlencoded" ,
459+ "Kinde-SDK" : "/" .join (("Python" , kinde_sdk_version )),
460+ },
461+ refresh_token = refresh_token ,
462+ )
463+ if not token_value :
464+ raise KindeTokenException (
465+ '"Access token" and "Refresh token" are invalid.'
466+ )
467+
468+ return token_value
469+ else :
470+ raise KindeTokenException ('"Access token" and "Refresh token" are invalid.' )
312471
313472 def _add_additional_params (self , url : str , additional_params : Optional [Dict [str , str ]] = None ) -> str :
314473
0 commit comments