Skip to content

Commit 056c3e2

Browse files
committed
Migrating Auth API to the new Identity Toolkit endpoint
1 parent 4d01830 commit 056c3e2

File tree

5 files changed

+32
-25
lines changed

5 files changed

+32
-25
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Unreleased
22

3-
-
3+
- [added] Migrated the `FirebaseAuth` user management API to the
4+
new Identity Toolkit endpoint.
45

56
# v2.15.1
67

firebase_admin/_user_mgt.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -394,7 +394,7 @@ def get_user(self, **kwargs):
394394
raise TypeError('Unsupported keyword arguments: {0}.'.format(kwargs))
395395

396396
try:
397-
response = self._client.body('post', 'getAccountInfo', json=payload)
397+
response = self._client.body('post', '/accounts:lookup', json=payload)
398398
except requests.exceptions.RequestException as error:
399399
msg = 'Failed to get user by {0}: {1}.'.format(key_type, key)
400400
self._handle_http_error(INTERNAL_ERROR, msg, error)
@@ -421,7 +421,7 @@ def list_users(self, page_token=None, max_results=MAX_LIST_USERS_RESULTS):
421421
if page_token:
422422
payload['nextPageToken'] = page_token
423423
try:
424-
return self._client.body('post', 'downloadAccount', json=payload)
424+
return self._client.body('get', '/accounts:batchGet', json=payload)
425425
except requests.exceptions.RequestException as error:
426426
self._handle_http_error(USER_DOWNLOAD_ERROR, 'Failed to download user accounts.', error)
427427

@@ -440,7 +440,7 @@ def create_user(self, uid=None, display_name=None, email=None, phone_number=None
440440
}
441441
payload = {k: v for k, v in payload.items() if v is not None}
442442
try:
443-
response = self._client.body('post', 'signupNewUser', json=payload)
443+
response = self._client.body('post', '/accounts', json=payload)
444444
except requests.exceptions.RequestException as error:
445445
self._handle_http_error(USER_CREATE_ERROR, 'Failed to create new user.', error)
446446
else:
@@ -490,7 +490,7 @@ def update_user(self, uid, display_name=_UNSPECIFIED, email=None, phone_number=_
490490

491491
payload = {k: v for k, v in payload.items() if v is not None}
492492
try:
493-
response = self._client.body('post', 'setAccountInfo', json=payload)
493+
response = self._client.body('post', '/accounts:update', json=payload)
494494
except requests.exceptions.RequestException as error:
495495
self._handle_http_error(
496496
USER_UPDATE_ERROR, 'Failed to update user: {0}.'.format(uid), error)
@@ -503,7 +503,7 @@ def delete_user(self, uid):
503503
"""Deletes the user identified by the specified user ID."""
504504
_auth_utils.validate_uid(uid, required=True)
505505
try:
506-
response = self._client.body('post', 'deleteAccount', json={'localId' : uid})
506+
response = self._client.body('post', '/accounts:delete', json={'localId' : uid})
507507
except requests.exceptions.RequestException as error:
508508
self._handle_http_error(
509509
USER_DELETE_ERROR, 'Failed to delete user: {0}.'.format(uid), error)
@@ -529,7 +529,7 @@ def import_users(self, users, hash_alg=None):
529529
raise ValueError('A UserImportHash is required to import users with passwords.')
530530
payload.update(hash_alg.to_dict())
531531
try:
532-
response = self._client.body('post', 'uploadAccount', json=payload)
532+
response = self._client.body('post', '/accounts:batchCreate', json=payload)
533533
except requests.exceptions.RequestException as error:
534534
self._handle_http_error(USER_IMPORT_ERROR, 'Failed to import users.', error)
535535
else:

firebase_admin/auth.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -466,13 +466,19 @@ def __init__(self, code, message, error=None):
466466
class _AuthService(object):
467467
"""Firebase Authentication service."""
468468

469-
ID_TOOLKIT_URL = 'https://www.googleapis.com/identitytoolkit/v3/relyingparty/'
469+
ID_TOOLKIT_URL = 'https://identitytoolkit.googleapis.com/v1/projects/'
470470

471471
def __init__(self, app):
472472
credential = app.credential.get_credential()
473473
version_header = 'Python/Admin/{0}'.format(firebase_admin.__version__)
474+
475+
if not app.project_id:
476+
raise ValueError("Project ID is required to access the auth service. Use a service account credential or "
477+
+ "set the project ID explicitly via FirebaseOptions. Alternatively you can also "
478+
+ "set the project ID via the GOOGLE_CLOUD_PROJECT environment variable.")
479+
474480
client = _http_client.JsonHttpClient(
475-
credential=credential, base_url=self.ID_TOOLKIT_URL,
481+
credential=credential, base_url=self.ID_TOOLKIT_URL + app.project_id,
476482
headers={'X-Client-Version': version_header})
477483
self._token_generator = _token_gen.TokenGenerator(app, client)
478484
self._token_verifier = _token_gen.TokenVerifier(app)

tests/test_token_gen.py

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ def test_noncert_credential(self, user_mgt_app):
199199
auth.create_custom_token(MOCK_UID, app=user_mgt_app)
200200

201201
def test_sign_with_iam(self):
202-
options = {'serviceAccountId': 'test-service-account'}
202+
options = {'serviceAccountId': 'test-service-account', 'projectId': 'mock-project-id'}
203203
app = firebase_admin.initialize_app(
204204
testutils.MockCredential(), name='iam-signer-app', options=options)
205205
try:
@@ -213,7 +213,7 @@ def test_sign_with_iam(self):
213213
firebase_admin.delete_app(app)
214214

215215
def test_sign_with_iam_error(self):
216-
options = {'serviceAccountId': 'test-service-account'}
216+
options = {'serviceAccountId': 'test-service-account', 'projectId': 'mock-project-id'}
217217
app = firebase_admin.initialize_app(
218218
testutils.MockCredential(), name='iam-signer-app', options=options)
219219
try:
@@ -228,7 +228,9 @@ def test_sign_with_iam_error(self):
228228

229229
def test_sign_with_discovered_service_account(self):
230230
request = testutils.MockRequest(200, 'discovered-service-account')
231-
app = firebase_admin.initialize_app(testutils.MockCredential(), name='iam-signer-app')
231+
options = {'projectId': 'mock-project-id'}
232+
app = firebase_admin.initialize_app(testutils.MockCredential(), name='iam-signer-app',
233+
options=options)
232234
try:
233235
_overwrite_iam_request(app, request)
234236
# Force initialization of the signing provider. This will invoke the Metadata service.
@@ -248,7 +250,9 @@ def test_sign_with_discovered_service_account(self):
248250

249251
def test_sign_with_discovery_failure(self):
250252
request = testutils.MockFailedRequest(Exception('test error'))
251-
app = firebase_admin.initialize_app(testutils.MockCredential(), name='iam-signer-app')
253+
options = {'projectId': 'mock-project-id'}
254+
app = firebase_admin.initialize_app(testutils.MockCredential(), name='iam-signer-app',
255+
options=options)
252256
try:
253257
_overwrite_iam_request(app, request)
254258
with pytest.raises(ValueError) as excinfo:
@@ -409,12 +413,6 @@ def test_project_id_env_var(self, env_var_app):
409413
claims = auth.verify_id_token(TEST_ID_TOKEN, env_var_app)
410414
assert claims['admin'] is True
411415

412-
@pytest.mark.parametrize('env_var_app', [{}], indirect=True)
413-
def test_no_project_id(self, env_var_app):
414-
_overwrite_cert_request(env_var_app, MOCK_REQUEST)
415-
with pytest.raises(ValueError):
416-
auth.verify_id_token(TEST_ID_TOKEN, env_var_app)
417-
418416
def test_custom_token(self, auth_app):
419417
id_token = auth.create_custom_token(MOCK_UID, app=auth_app)
420418
_overwrite_cert_request(auth_app, MOCK_REQUEST)
@@ -515,12 +513,6 @@ def test_project_id_env_var(self, env_var_app):
515513
claims = auth.verify_session_cookie(TEST_SESSION_COOKIE, app=env_var_app)
516514
assert claims['admin'] is True
517515

518-
@pytest.mark.parametrize('env_var_app', [{}], indirect=True)
519-
def test_no_project_id(self, env_var_app):
520-
_overwrite_cert_request(env_var_app, MOCK_REQUEST)
521-
with pytest.raises(ValueError):
522-
auth.verify_session_cookie(TEST_SESSION_COOKIE, app=env_var_app)
523-
524516
def test_custom_token(self, auth_app):
525517
custom_token = auth.create_custom_token(MOCK_UID, app=auth_app)
526518
_overwrite_cert_request(auth_app, MOCK_REQUEST)

tests/test_user_mgt.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,14 @@ def _check_user_record(user, expected_uid='testuser'):
8787
assert provider.provider_id == 'phone'
8888

8989

90+
class TestAuthServiceInitialization(object):
91+
92+
def test_fail_on_no_project_id(self):
93+
app = firebase_admin.initialize_app(testutils.MockCredential(), name='userMgt2')
94+
with pytest.raises(ValueError):
95+
auth._get_auth_service(app)
96+
firebase_admin.delete_app(app)
97+
9098
class TestUserRecord(object):
9199

92100
# Input dict must be non-empty, and must not contain unsupported keys.

0 commit comments

Comments
 (0)