14
14
15
15
"""Firebase auth MFA management sub module."""
16
16
17
- import requests
18
17
import typing as _t
19
-
18
+ import requests
20
19
from firebase_admin import _auth_client
21
20
from firebase_admin import _utils
22
21
from firebase_admin import exceptions
23
22
24
- _AUTH_ATTRIBUTE = '_auth'
23
+ _AUTH_ATTRIBUTE = "_auth"
24
+
25
25
26
26
class MfaError (exceptions .FirebaseError ):
27
27
"""Represents an error related to MFA operations."""
28
+
28
29
def __init__ (self , message , cause = None , http_response = None ):
29
- exceptions .FirebaseError .__init__ (self , 'MFA_ERROR' , message , cause , http_response )
30
+ exceptions .FirebaseError .__init__ (
31
+ self , "MFA_ERROR" , message , cause , http_response
32
+ )
30
33
31
- def _to_text (b : _t .Union [str , bytes ]) -> str :
32
- return b .decode ("utf-8" ) if isinstance (b , (bytes , bytearray )) else str (b )
33
34
35
+ def _to_text (byte_or_str : _t .Union [str , bytes ]) -> str :
36
+ if isinstance (byte_or_str , (bytes , bytearray )):
37
+ return byte_or_str .decode ("utf-8" )
38
+ return str (byte_or_str )
34
39
35
- def _signin_with_custom_token (* , api_key : str , custom_token : str , tenant_id : str | None ) -> str :
36
- """
37
- Exchange a Custom Token for an ID token.
40
+
41
+ def _signin_with_custom_token (
42
+ * , api_key : str , custom_token : str , tenant_id : str | None
43
+ ) -> str :
44
+ """Exchange a Custom Token for an ID token.
38
45
39
46
Uses: POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key=API_KEY
40
47
"""
41
48
if not api_key :
42
- raise ValueError ("api_key must be provided (Web API key from Firebase project settings)." )
49
+ raise ValueError (
50
+ "api_key must be provided (Web API key from Firebase project settings)."
51
+ )
43
52
44
53
url = f"https://identitytoolkit.googleapis.com/v1/accounts:signInWithCustomToken?key={ api_key } "
45
54
payload = {
@@ -50,15 +59,15 @@ def _signin_with_custom_token(*, api_key: str, custom_token: str, tenant_id: str
50
59
payload ["tenantId" ] = tenant_id
51
60
52
61
try :
53
- r = requests .post (url , json = payload , timeout = 30 )
54
- r .raise_for_status ()
55
- data = r .json ()
62
+ response = requests .post (url , json = payload , timeout = 30 )
63
+ response .raise_for_status ()
64
+ data = response .json ()
56
65
if "idToken" not in data :
57
- raise MfaError (f "Failed to exchange custom token for ID token: { data . get ( 'error' , 'Unknown error' ) } " , http_response = r )
66
+ raise MfaError ("Failed to exchange custom token" , http_response = response )
58
67
return data ["idToken" ]
59
- except requests .exceptions .RequestException as e :
60
- message = f"Failed to exchange custom token for ID token: { e } "
61
- raise MfaError (message , cause = e , http_response = e .response ) from e
68
+ except requests .exceptions .RequestException as error :
69
+ message = f"Failed to exchange custom token for ID token: { error } "
70
+ raise MfaError (message , cause = error , http_response = error .response ) from error
62
71
63
72
64
73
def withdraw_mfa_enrollment (
@@ -69,18 +78,17 @@ def withdraw_mfa_enrollment(
69
78
tenant_id : str | None = None ,
70
79
app = None ,
71
80
) -> dict :
72
- """
73
- Withdraw (reset) a user's enrolled second factor by enrollment ID.
81
+ """Withdraw (reset) a user's enrolled second factor by enrollment ID.
74
82
75
83
Args:
76
- uid: Firebase Auth UID of the user to act on.
84
+ uid: Firebase Auth UID of the user to act on.
77
85
mfa_enrollment_id: Enrollment ID of the second factor to revoke.
78
- api_key: Web API key (from Firebase console) used by signInWithCustomToken.
79
- tenant_id: Optional Tenant ID if using multi-tenancy.
80
- app: Optional firebase_admin App instance.
86
+ api_key: Web API key (from Firebase console) used by signInWithCustomToken.
87
+ tenant_id: Optional Tenant ID if using multi-tenancy.
88
+ app: Optional firebase_admin App instance.
81
89
82
90
Returns:
83
- dict response from accounts.mfaEnrollment:withdraw (typically contains updated user info).
91
+ dict response from accounts.mfaEnrollment:withdraw (contains updated user info).
84
92
85
93
Raises:
86
94
MfaError on failure.
@@ -95,21 +103,24 @@ def withdraw_mfa_enrollment(
95
103
custom_token = _to_text (client .create_custom_token (uid ))
96
104
97
105
# 2) Exchange Custom Token → ID token (requires API key)
98
- id_token = _signin_with_custom_token (api_key = api_key , custom_token = custom_token , tenant_id = tenant_id )
106
+ id_token = _signin_with_custom_token (
107
+ api_key = api_key , custom_token = custom_token , tenant_id = tenant_id
108
+ )
99
109
100
110
# 3) Withdraw MFA with the ID token
101
- withdraw_url = "https://identitytoolkit.googleapis.com/v2/accounts/mfaEnrollment:withdraw"
102
- if api_key :
103
- withdraw_url += f"?key={ api_key } " # optional, but fine to append
111
+ base_url = (
112
+ "https://identitytoolkit.googleapis.com/v2/accounts/mfaEnrollment:withdraw"
113
+ )
114
+ withdraw_url = f"{ base_url } ?key={ api_key } " if api_key else base_url
104
115
105
116
payload = {"idToken" : id_token , "mfaEnrollmentId" : mfa_enrollment_id }
106
117
if tenant_id :
107
118
payload ["tenantId" ] = tenant_id
108
119
109
120
try :
110
- r = requests .post (withdraw_url , json = payload , timeout = 30 )
111
- r .raise_for_status ()
112
- return r .json ()
113
- except requests .exceptions .RequestException as e :
114
- message = f"Failed to withdraw MFA enrollment: { e } "
115
- raise MfaError (message , cause = e , http_response = e .response ) from e
121
+ response = requests .post (withdraw_url , json = payload , timeout = 30 )
122
+ response .raise_for_status ()
123
+ return response .json ()
124
+ except requests .exceptions .RequestException as error :
125
+ message = f"Failed to withdraw MFA enrollment: { error } "
126
+ raise MfaError (message , cause = error , http_response = error .response ) from error
0 commit comments