Skip to content

Commit 0a11d07

Browse files
authored
feat(auth): ability to delete provider in auth (#579)
* [add] ability to delete provider in auth * [fix] pylint * [fix] tests * [fix] tests * fix comments * fix tests * fix lint * [fix] address comments
1 parent f38c5f7 commit 0a11d07

File tree

5 files changed

+42
-2
lines changed

5 files changed

+42
-2
lines changed

firebase_admin/_auth_client.py

+2
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,8 @@ def update_user(self, uid, **kwargs): # pylint: disable=differing-param-doc
336336
valid_since: An integer signifying the seconds since the epoch (optional). This field
337337
is set by ``revoke_refresh_tokens`` and it is discouraged to set this field
338338
directly.
339+
providers_to_delete: The list of provider IDs to unlink,
340+
eg: 'google.com', 'password', etc.
339341
340342
Returns:
341343
UserRecord: An updated UserRecord instance for the user.

firebase_admin/_auth_utils.py

+9
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,15 @@ def validate_action_type(action_type):
266266
Valid values are {1}'.format(action_type, ', '.join(VALID_EMAIL_ACTION_TYPES)))
267267
returnaction_type
268268

269+
defvalidate_provider_ids(provider_ids, required=False):
270+
ifnotprovider_ids:
271+
ifrequired:
272+
raiseValueError('Invalid provider IDs. Provider ids should be provided')
273+
return []
274+
forprovider_idinprovider_ids:
275+
validate_provider_id(provider_id, True)
276+
returnprovider_ids
277+
269278
defbuild_update_mask(params):
270279
"""Creates an update mask list from the given dictionary."""
271280
mask= []

firebase_admin/_user_mgt.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ def create_user(self, uid=None, display_name=None, email=None, phone_number=None
688688

689689
defupdate_user(self, uid, display_name=None, email=None, phone_number=None,
690690
photo_url=None, password=None, disabled=None, email_verified=None,
691-
valid_since=None, custom_claims=None):
691+
valid_since=None, custom_claims=None, providers_to_delete=None):
692692
"""Updates an existing user account with the specified properties"""
693693
payload= {
694694
'localId': _auth_utils.validate_uid(uid, required=True),
@@ -700,6 +700,7 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
700700
}
701701

702702
remove= []
703+
remove_provider=_auth_utils.validate_provider_ids(providers_to_delete)
703704
ifdisplay_nameisnotNone:
704705
ifdisplay_nameisDELETE_ATTRIBUTE:
705706
remove.append('DISPLAY_NAME')
@@ -715,7 +716,7 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
715716

716717
ifphone_numberisnotNone:
717718
ifphone_numberisDELETE_ATTRIBUTE:
718-
payload['deleteProvider'] = ['phone']
719+
remove_provider.append('phone')
719720
else:
720721
payload['phoneNumber'] =_auth_utils.validate_phone(phone_number)
721722

@@ -726,6 +727,9 @@ def update_user(self, uid, display_name=None, email=None, phone_number=None,
726727
custom_claims, dict) elsecustom_claims
727728
payload['customAttributes'] =_auth_utils.validate_custom_claims(json_claims)
728729

730+
ifremove_provider:
731+
payload['deleteProvider'] =list(set(remove_provider))
732+
729733
payload= {k: vfork, vinpayload.items() ifvisnotNone}
730734
body, http_resp=self._make_request('post', '/accounts:update', json=payload)
731735
ifnotbodyornotbody.get('localId'):

integration/test_auth.py

+8
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,14 @@ def test_disable_user(new_user_with_params):
496496
assertuser.disabledisTrue
497497
assertlen(user.provider_data) ==1
498498

499+
deftest_remove_provider(new_user_with_provider):
500+
provider_ids= [provider.provider_idforproviderinnew_user_with_provider.provider_data]
501+
assert'google.com'inprovider_ids
502+
user=auth.update_user(new_user_with_provider, providers_to_delete=['google.com'])
503+
assertuser.uid==new_user_with_params.uid
504+
new_provider_ids= [provider.provider_idforproviderinuser.provider_data]
505+
assert'google.com'notinnew_provider_ids
506+
499507
deftest_delete_user():
500508
user=auth.create_user()
501509
auth.delete_user(user.uid)

tests/test_user_mgt.py

+17
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,23 @@ def test_update_user_valid_since(self, user_mgt_app, arg):
663663
request=json.loads(recorder[0].body.decode())
664664
assertrequest== {'localId': 'testuser', 'validSince': int(arg)}
665665

666+
@pytest.mark.parametrize('arg', [['phone'], ['google.com', 'phone']])
667+
deftest_update_user_delete_provider(self, user_mgt_app, arg):
668+
user_mgt, recorder=_instrument_user_manager(user_mgt_app, 200, '{"localId":"testuser"}')
669+
user_mgt.update_user('testuser', providers_to_delete=arg)
670+
request=json.loads(recorder[0].body.decode())
671+
assertset(request['deleteProvider']) ==set(arg)
672+
673+
@pytest.mark.parametrize('arg', [[], ['phone'], ['google.com'], ['google.com', 'phone']])
674+
deftest_update_user_delete_provider_and_phone(self, user_mgt_app, arg):
675+
user_mgt, recorder=_instrument_user_manager(user_mgt_app, 200, '{"localId":"testuser"}')
676+
user_mgt.update_user('testuser',
677+
providers_to_delete=arg,
678+
phone_number=auth.DELETE_ATTRIBUTE)
679+
request=json.loads(recorder[0].body.decode())
680+
assert'phone'inrequest['deleteProvider']
681+
assertlen(set(request['deleteProvider'])) ==len(request['deleteProvider'])
682+
assertset(arg) -set(request['deleteProvider']) ==set()
666683

667684
classTestSetCustomUserClaims:
668685

0 commit comments

Comments
 (0)
close