1+ import httpx
12from typing import Any , Dict , List , Optional , cast
23from flask import g
34from propelauth_py import (
45 TokenVerificationMetadata ,
56 init_base_auth ,
7+ init_base_async_auth ,
68 SamlIdpMetadata ,
79 StepUpMfaGrantType ,
810 StepUpMfaVerifyTotpResponse ,
@@ -507,6 +509,362 @@ def verify_step_up_grant(self, action_type: str, user_id: str, grant: str) -> bo
507509 return self .auth .verify_step_up_grant (action_type , user_id , grant )
508510
509511
512+ class FlaskAuthAsync ():
513+ def __init__ (
514+ self ,
515+ auth_url : str ,
516+ integration_api_key : str ,
517+ token_verification_metadata : Optional [TokenVerificationMetadata ],
518+ debug_mode : bool ,
519+ httpx_client : Optional [httpx .AsyncClient ] = None ,
520+ ):
521+ self .auth_url = auth_url
522+ self .integration_api_key = integration_api_key
523+ self .token_verification_metadata = token_verification_metadata
524+ self .debug_mode = debug_mode
525+ self .httpx_client = httpx_client
526+ self .auth = init_base_async_auth (auth_url , integration_api_key , token_verification_metadata , self .httpx_client )
527+
528+ @property
529+ def require_user (self ):
530+ return _get_user_credential_decorator (
531+ self .auth .validate_access_token_and_get_user , True , self .debug_mode
532+ )
533+
534+ @property
535+ def optional_user (self ):
536+ return _get_user_credential_decorator (
537+ self .auth .validate_access_token_and_get_user , False , self .debug_mode
538+ )
539+
540+ @property
541+ def require_org_member (self ):
542+ return _get_require_org_decorator (
543+ self .auth .validate_access_token_and_get_user_with_org , self .debug_mode
544+ )
545+
546+ @property
547+ def require_org_member_with_minimum_role (self ):
548+ return _require_org_member_with_minimum_role_decorator (
549+ self .auth .validate_access_token_and_get_user_with_org_by_minimum_role ,
550+ self .debug_mode ,
551+ )
552+
553+ @property
554+ def require_org_member_with_exact_role (self ):
555+ return _require_org_member_with_exact_role_decorator (
556+ self .auth .validate_access_token_and_get_user_with_org_by_exact_role ,
557+ self .debug_mode ,
558+ )
559+
560+ @property
561+ def require_org_member_with_permission (self ):
562+ return _require_org_member_with_permission_decorator (
563+ self .auth .validate_access_token_and_get_user_with_org_by_permission ,
564+ self .debug_mode ,
565+ )
566+
567+ @property
568+ def require_org_member_with_all_permissions (self ):
569+ return _require_org_member_with_all_permissions_decorator (
570+ self .auth .validate_access_token_and_get_user_with_org_by_all_permissions ,
571+ self .debug_mode ,
572+ )
573+
574+ def validate_access_token_and_get_user (self , authorization_header : str ) -> User :
575+ return self .auth .validate_access_token_and_get_user (
576+ authorization_header = authorization_header
577+ )
578+
579+ async def fetch_user_metadata_by_user_id (self , user_id : str , include_orgs : bool = False ):
580+ return await self .auth .fetch_user_metadata_by_user_id (user_id , include_orgs )
581+
582+ async def fetch_user_metadata_by_email (self , email : str , include_orgs : bool = False ):
583+ return await self .auth .fetch_user_metadata_by_email (email , include_orgs )
584+
585+ async def fetch_user_metadata_by_username (self , username : str , include_orgs : bool = False ):
586+ return await self .auth .fetch_user_metadata_by_username (username , include_orgs )
587+
588+ async def fetch_user_signup_query_params_by_user_id (self , user_id : str ):
589+ return await self .auth .fetch_user_signup_query_params_by_user_id (user_id )
590+
591+ async def fetch_batch_user_metadata_by_user_ids (self , user_ids : List [str ], include_orgs : bool = False ):
592+ return await self .auth .fetch_batch_user_metadata_by_user_ids (user_ids , include_orgs )
593+
594+ async def fetch_batch_user_metadata_by_emails (self , emails : List [str ], include_orgs : bool = False ):
595+ return await self .auth .fetch_batch_user_metadata_by_emails (emails , include_orgs )
596+
597+ async def fetch_batch_user_metadata_by_usernames (self , usernames : List [str ], include_orgs : bool = False ):
598+ return await self .auth .fetch_batch_user_metadata_by_usernames (usernames , include_orgs )
599+
600+ async def fetch_org (self , org_id : str ):
601+ return await self .auth .fetch_org (org_id )
602+
603+ async def fetch_org_by_query (
604+ self , page_size : int = 10 , page_number : int = 0 , order_by : OrgQueryOrderBy = OrgQueryOrderBy .CREATED_AT_ASC ,
605+ name : Optional [str ] = None , legacy_org_id : Optional [str ] = None , domain : Optional [str ] = None
606+ ):
607+ return await self .auth .fetch_org_by_query (page_size , page_number , order_by , name , legacy_org_id , domain )
608+
609+ async def fetch_custom_role_mappings (self ):
610+ return await self .auth .fetch_custom_role_mappings ()
611+
612+ async def fetch_pending_invites (self , page_number : int = 0 , page_size : int = 10 , org_id : Optional [str ] = None ):
613+ return await self .auth .fetch_pending_invites (page_number , page_size , org_id )
614+
615+ async def fetch_users_by_query (
616+ self , page_size : int = 10 , page_number : int = 0 , order_by : UserQueryOrderBy = UserQueryOrderBy .CREATED_AT_ASC ,
617+ email_or_username : Optional [str ] = None , include_orgs : bool = False , legacy_user_id : Optional [str ] = None
618+ ):
619+ return await self .auth .fetch_users_by_query (page_size , page_number , order_by , email_or_username , include_orgs , legacy_user_id )
620+
621+ async def fetch_users_in_org (
622+ self , org_id : str , page_size : int = 10 , page_number : int = 0 , include_orgs : bool = False , role : Optional [str ] = None
623+ ):
624+ return await self .auth .fetch_users_in_org (org_id , page_size , page_number , include_orgs , role )
625+
626+ async def create_user (
627+ self , email : str , email_confirmed : bool = False , send_email_to_confirm_email_address : bool = True ,
628+ ask_user_to_update_password_on_login : bool = False , password : Optional [str ] = None , username : Optional [str ] = None ,
629+ first_name : Optional [str ] = None , last_name : Optional [str ] = None , properties : Optional [Dict [str , Any ]] = None , ignore_domain_restrictions : bool = False
630+ ):
631+ return await self .auth .create_user (
632+ email , email_confirmed , send_email_to_confirm_email_address , ask_user_to_update_password_on_login ,
633+ password , username , first_name , last_name , properties , ignore_domain_restrictions
634+ )
635+
636+ async def invite_user_to_org (self , email : str , org_id : str , role : str , additional_roles : List [str ] = []):
637+ return await self .auth .invite_user_to_org (email , org_id , role , additional_roles )
638+
639+ async def resend_email_confirmation (self , user_id : str ):
640+ return await self .auth .resend_email_confirmation (user_id )
641+
642+ async def logout_all_user_sessions (self , user_id : str ):
643+ return await self .auth .logout_all_user_sessions (user_id )
644+
645+ async def update_user_email (self , user_id : str , new_email : str , require_email_confirmation : bool ):
646+ return await self .auth .update_user_email (user_id , new_email , require_email_confirmation )
647+
648+ async def update_user_metadata (
649+ self ,
650+ user_id : str ,
651+ username : Optional [str ] = None ,
652+ first_name : Optional [str ] = None ,
653+ last_name : Optional [str ] = None ,
654+ metadata : Optional [Dict [str , Any ]] = None ,
655+ properties : Optional [Dict [str , Any ]] = None ,
656+ picture_url : Optional [str ] = None ,
657+ update_password_required : Optional [bool ] = None ,
658+ legacy_user_id : Optional [str ] = None ,
659+ ):
660+ return await self .auth .update_user_metadata (
661+ user_id , username , first_name , last_name , metadata , properties , picture_url , update_password_required , legacy_user_id
662+ )
663+
664+ async def clear_user_password (self , user_id : str ):
665+ return await self .auth .clear_user_password (user_id )
666+
667+ async def update_user_password (self , user_id : str , password : str , ask_user_to_update_password_on_login : bool = False ):
668+ return await self .auth .update_user_password (user_id , password , ask_user_to_update_password_on_login )
669+
670+ async def create_magic_link (
671+ self ,
672+ email : str ,
673+ redirect_to_url : Optional [str ] = None ,
674+ expires_in_hours : Optional [str ] = None ,
675+ create_new_user_if_one_doesnt_exist : Optional [bool ] = None ,
676+ user_signup_query_parameters : Optional [Dict [str , Any ]] = None ,
677+ ):
678+ return await self .auth .create_magic_link (
679+ email , redirect_to_url , expires_in_hours , create_new_user_if_one_doesnt_exist , user_signup_query_parameters
680+ )
681+
682+ async def create_access_token (self , user_id : str , duration_in_minutes : int , active_org_id : Optional [str ] = None ):
683+ return await self .auth .create_access_token (user_id , duration_in_minutes , active_org_id )
684+
685+ async def migrate_user_from_external_source (
686+ self ,
687+ email : str ,
688+ email_confirmed : bool ,
689+ existing_user_id : Optional [str ] = None ,
690+ existing_password_hash : Optional [str ] = None ,
691+ existing_mfa_base32_encoded_secret : Optional [str ] = None ,
692+ ask_user_to_update_password_on_login : bool = False ,
693+ enabled : Optional [bool ] = None ,
694+ first_name : Optional [str ] = None ,
695+ last_name : Optional [str ] = None ,
696+ username : Optional [str ] = None ,
697+ picture_url : Optional [str ] = None ,
698+ properties : Optional [Dict [str , Any ]] = None ,
699+ ):
700+ return await self .auth .migrate_user_from_external_source (
701+ email , email_confirmed , existing_user_id , existing_password_hash ,
702+ existing_mfa_base32_encoded_secret , ask_user_to_update_password_on_login ,
703+ enabled , first_name , last_name , username , picture_url , properties
704+ )
705+
706+ async def migrate_user_password (
707+ self ,
708+ user_id : str ,
709+ password_hash : str ,
710+ ):
711+ return await self .auth .migrate_user_password (user_id , password_hash )
712+
713+ async def create_org (
714+ self ,
715+ name : str ,
716+ enable_auto_joining_by_domain : bool = False ,
717+ members_must_have_matching_domain : bool = False ,
718+ domain : Optional [str ] = None ,
719+ max_users : Optional [str ] = None ,
720+ custom_role_mapping_name : Optional [str ] = None ,
721+ legacy_org_id : Optional [str ] = None ,
722+ ):
723+ return await self .auth .create_org (
724+ name , enable_auto_joining_by_domain , members_must_have_matching_domain ,
725+ domain , max_users , custom_role_mapping_name , legacy_org_id
726+ )
727+
728+ async def update_org_metadata (
729+ self ,
730+ org_id : str ,
731+ name : Optional [str ] = None ,
732+ can_setup_saml : Optional [bool ] = None ,
733+ metadata : Optional [Dict [str , Any ]] = None ,
734+ max_users : Optional [str ] = None ,
735+ can_join_on_email_domain_match : Optional [bool ] = None ,
736+ members_must_have_email_domain_match : Optional [bool ] = None ,
737+ domain : Optional [str ] = None ,
738+ require_2fa_by : Optional [str ] = None ,
739+ extra_domains : Optional [List [str ]] = None ,
740+ ):
741+ return await self .auth .update_org_metadata (
742+ org_id , name , can_setup_saml , metadata , max_users ,
743+ can_join_on_email_domain_match , members_must_have_email_domain_match , domain , require_2fa_by , extra_domains
744+ )
745+
746+ async def subscribe_org_to_role_mapping (self , org_id : str , custom_role_mapping_name : str ):
747+ return await self .auth .subscribe_org_to_role_mapping (org_id , custom_role_mapping_name )
748+
749+ async def delete_org (self , org_id : str ):
750+ return await self .auth .delete_org (org_id )
751+
752+ async def revoke_pending_org_invite (self , org_id : str , invitee_email : str ):
753+ return await self .auth .revoke_pending_org_invite (org_id , invitee_email )
754+
755+ async def add_user_to_org (self , user_id : str , org_id : str , role : str , additional_roles : List [str ] = []):
756+ return await self .auth .add_user_to_org (user_id , org_id , role , additional_roles )
757+
758+ async def remove_user_from_org (self , user_id : str , org_id : str ):
759+ return await self .auth .remove_user_from_org (user_id , org_id )
760+
761+ async def change_user_role_in_org (self , user_id : str , org_id : str , role : str , additional_roles : List [str ] = []):
762+ return await self .auth .change_user_role_in_org (user_id , org_id , role , additional_roles )
763+
764+ async def delete_user (self , user_id : str ):
765+ return await self .auth .delete_user (user_id )
766+
767+ async def disable_user (self , user_id : str ):
768+ return await self .auth .disable_user (user_id )
769+
770+ async def enable_user (self , user_id : str ):
771+ return await self .auth .enable_user (user_id )
772+
773+ async def disable_user_2fa (self , user_id : str ):
774+ return await self .auth .disable_user_2fa (user_id )
775+
776+ async def enable_user_can_create_orgs (self , user_id : str ):
777+ return await self .auth .enable_user_can_create_orgs (user_id )
778+
779+ async def disable_user_can_create_orgs (self , user_id : str ):
780+ return await self .auth .disable_user_can_create_orgs (user_id )
781+
782+ async def allow_org_to_setup_saml_connection (self , org_id : str ):
783+ return await self .auth .allow_org_to_setup_saml_connection (org_id )
784+
785+ async def disallow_org_to_setup_saml_connection (self , org_id : str ):
786+ return await self .auth .disallow_org_to_setup_saml_connection (org_id )
787+
788+ async def fetch_api_key (self , api_key_id : str ):
789+ return await self .auth .fetch_api_key (api_key_id )
790+
791+ async def fetch_current_api_keys (
792+ self ,
793+ org_id : Optional [str ] = None ,
794+ user_id : Optional [str ] = None ,
795+ user_email : Optional [str ] = None ,
796+ page_size : Optional [int ] = None ,
797+ page_number : Optional [int ] = None ,
798+ api_key_type : Optional [str ] = None ,
799+ ):
800+ return await self .auth .fetch_current_api_keys (
801+ org_id , user_id , user_email , page_size , page_number , api_key_type
802+ )
803+
804+ async def fetch_archived_api_keys (
805+ self ,
806+ org_id : Optional [str ] = None ,
807+ user_id : Optional [str ] = None ,
808+ user_email : Optional [str ] = None ,
809+ page_size : Optional [int ] = None ,
810+ page_number : Optional [int ] = None ,
811+ api_key_type : Optional [str ] = None ,
812+ ):
813+ return await self .auth .fetch_archived_api_keys (
814+ org_id , user_id , user_email , page_size , page_number , api_key_type
815+ )
816+
817+ async def create_api_key (
818+ self ,
819+ org_id : Optional [str ] = None ,
820+ user_id : Optional [str ] = None ,
821+ expires_at_seconds : Optional [str ] = None ,
822+ metadata : Optional [Dict [str , Any ]] = None
823+ ):
824+ return await self .auth .create_api_key (org_id , user_id , expires_at_seconds , metadata )
825+
826+ async def update_api_key (self , api_key_id : str , expires_at_seconds : Optional [str ] = None , metadata : Optional [Dict [str , Any ]] = None ):
827+ return await self .auth .update_api_key (api_key_id , expires_at_seconds , metadata )
828+
829+ async def delete_api_key (self , api_key_id : str ):
830+ return await self .auth .delete_api_key (api_key_id )
831+
832+ async def validate_personal_api_key (self , api_key_token : str ):
833+ return await self .auth .validate_personal_api_key (api_key_token )
834+
835+ async def validate_org_api_key (self , api_key_token : str ):
836+ return await self .auth .validate_org_api_key (api_key_token )
837+
838+ async def validate_api_key (self , api_key_token : str ):
839+ return await self .auth .validate_api_key (api_key_token )
840+
841+ async def fetch_saml_sp_metadata (self , org_id : str ):
842+ return await self .auth .fetch_saml_sp_metadata (org_id )
843+
844+ async def set_saml_idp_metadata (self , org_id : str , saml_idp_metadata : SamlIdpMetadata ):
845+ return await self .auth .set_saml_idp_metadata (org_id = org_id , saml_idp_metadata = saml_idp_metadata )
846+
847+ async def saml_go_live (self , org_id : str ):
848+ return await self .auth .saml_go_live (org_id )
849+
850+ async def delete_saml_connection (self , org_id : str ):
851+ return await self .auth .delete_saml_connection (org_id )
852+
853+ async def verify_step_up_totp_challenge (
854+ self ,
855+ action_type : str ,
856+ user_id : str ,
857+ code : str ,
858+ grant_type : StepUpMfaGrantType ,
859+ valid_for_seconds : int ,
860+ ) -> StepUpMfaVerifyTotpResponse :
861+ return await self .auth .verify_step_up_totp_challenge (
862+ action_type , user_id , code , grant_type , valid_for_seconds
863+ )
864+
865+ async def verify_step_up_grant (self , action_type : str , user_id : str , grant : str ) -> bool :
866+ return await self .auth .verify_step_up_grant (action_type , user_id , grant )
867+
510868def init_auth (
511869 auth_url : str ,
512870 api_key : str ,
@@ -520,3 +878,13 @@ def init_auth(
520878 token_verification_metadata = token_verification_metadata ,
521879 debug_mode = debug_mode ,
522880 )
881+
882+ def init_auth_async (
883+ auth_url : str ,
884+ api_key : str ,
885+ token_verification_metadata : Optional [TokenVerificationMetadata ] = None ,
886+ debug_mode = False ,
887+ httpx_client : Optional [httpx .AsyncClient ] = None ,
888+ ) -> FlaskAuthAsync :
889+ """Fetches metadata required to validate access tokens and returns auth decorators and utilities"""
890+ return FlaskAuthAsync (auth_url = auth_url , integration_api_key = api_key , token_verification_metadata = token_verification_metadata , debug_mode = debug_mode , httpx_client = httpx_client )
0 commit comments