Skip to content

Commit 5657a80

Browse files
committed
Support auth emulator via FIREBASE_AUTH_EMULATOR_HOST
Modeled on firebase/firebase-admin-go#414
1 parent b35abb9 commit 5657a80

File tree

4 files changed

+43
-12
lines changed

4 files changed

+43
-12
lines changed

firebase_admin/_auth_client.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""Firebase auth client sub module."""
1616

17+
import os
1718
import time
1819

1920
import firebase_admin
@@ -25,6 +26,8 @@
2526
from firebase_admin import _user_import
2627
from firebase_admin import _user_mgt
2728

29+
_EMULATOR_HOST_ENV_VAR = 'FIREBASE_AUTH_EMULATOR_HOST'
30+
_DEFAULT_AUTH_URL = 'https://identitytoolkit.googleapis.com'
2831

2932
class Client:
3033
"""Firebase Authentication client scoped to a specific tenant."""
@@ -36,17 +39,39 @@ def __init__(self, app, tenant_id=None):
3639
2. set the project ID explicitly via Firebase App options, or
3740
3. set the project ID via the GOOGLE_CLOUD_PROJECT environment variable.""")
3841

39-
credential = app.credential.get_credential()
42+
credential = None
4043
version_header = 'Python/Admin/{0}'.format(firebase_admin.__version__)
44+
http_headers = {'X-Client-Version': version_header}
45+
# Fallback to default endpoint URLs if an emulator isn't present.
46+
id_toolkit_endpoints = {
47+
"v1": None,
48+
"v2beta1": None,
49+
}
50+
51+
# If an emulator is present, check that the given value matches the expected format and set endpoint URLs to use
52+
# the emulator. Also set a fake authorization token.
53+
emulator_host = os.environ.get(_EMULATOR_HOST_ENV_VAR)
54+
if emulator_host:
55+
if '//' in emulator_host:
56+
raise ValueError(
57+
'Invalid {0}: "{1}". It must follow format "host:port".'.format(
58+
_EMULATOR_HOST_ENV_VAR, emulator_host))
59+
http_headers["Authorization"] = "Bearer owner"
60+
base_url = "http://{0}/identitytoolkit.googleapis.com".format(emulator_host)
61+
id_toolkit_endpoints["v1"] = base_url + "/v1"
62+
id_toolkit_endpoints["v2beta1"] = base_url + "/v2beta1"
63+
else:
64+
credential = app.credential.get_credential()
65+
4166
http_client = _http_client.JsonHttpClient(
42-
credential=credential, headers={'X-Client-Version': version_header})
67+
credential=credential, headers=http_headers)
4368

4469
self._tenant_id = tenant_id
45-
self._token_generator = _token_gen.TokenGenerator(app, http_client)
70+
self._token_generator = _token_gen.TokenGenerator(app, http_client, id_toolkit_endpoints["v1"])
4671
self._token_verifier = _token_gen.TokenVerifier(app)
47-
self._user_manager = _user_mgt.UserManager(http_client, app.project_id, tenant_id)
72+
self._user_manager = _user_mgt.UserManager(http_client, app.project_id, tenant_id, id_toolkit_endpoints["v1"])
4873
self._provider_manager = _auth_providers.ProviderConfigClient(
49-
http_client, app.project_id, tenant_id)
74+
http_client, app.project_id, tenant_id, id_toolkit_endpoints["v2beta1"])
5075

5176
@property
5277
def tenant_id(self):

firebase_admin/_auth_providers.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,9 +166,11 @@ class ProviderConfigClient:
166166

167167
PROVIDER_CONFIG_URL = 'https://identitytoolkit.googleapis.com/v2beta1'
168168

169-
def __init__(self, http_client, project_id, tenant_id=None):
169+
def __init__(self, http_client, project_id, tenant_id=None, provider_config_url=None):
170170
self.http_client = http_client
171-
self.base_url = '{0}/projects/{1}'.format(self.PROVIDER_CONFIG_URL, project_id)
171+
if not provider_config_url:
172+
provider_config_url = self.PROVIDER_CONFIG_URL
173+
self.base_url = '{0}/projects/{1}'.format(provider_config_url, project_id)
172174
if tenant_id:
173175
self.base_url += '/tenants/{0}'.format(tenant_id)
174176

firebase_admin/_token_gen.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,13 @@ class TokenGenerator:
8484

8585
ID_TOOLKIT_URL = 'https://identitytoolkit.googleapis.com/v1'
8686

87-
def __init__(self, app, http_client):
87+
def __init__(self, app, http_client, id_toolkit_url=None):
8888
self.app = app
8989
self.http_client = http_client
9090
self.request = transport.requests.Request()
91-
self.base_url = '{0}/projects/{1}'.format(self.ID_TOOLKIT_URL, app.project_id)
91+
if not id_toolkit_url:
92+
id_toolkit_url = self.ID_TOOLKIT_URL
93+
self.base_url = '{0}/projects/{1}'.format(id_toolkit_url, app.project_id)
9294
self._signing_provider = None
9395

9496
def _init_signing_provider(self):
@@ -198,7 +200,7 @@ def create_session_cookie(self, id_token, expires_in):
198200
url = '{0}:createSessionCookie'.format(self.base_url)
199201
payload = {
200202
'idToken': id_token,
201-
'validDuration': expires_in,
203+
'validDuration': str(expires_in),
202204
}
203205
try:
204206
body, http_resp = self.http_client.body_and_response('post', url, json=payload)

firebase_admin/_user_mgt.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,11 @@ class UserManager:
573573

574574
ID_TOOLKIT_URL = 'https://identitytoolkit.googleapis.com/v1'
575575

576-
def __init__(self, http_client, project_id, tenant_id=None):
576+
def __init__(self, http_client, project_id, tenant_id=None, id_toolkit_url=None):
577577
self.http_client = http_client
578-
self.base_url = '{0}/projects/{1}'.format(self.ID_TOOLKIT_URL, project_id)
578+
if not id_toolkit_url:
579+
id_toolkit_url = self.ID_TOOLKIT_URL
580+
self.base_url = '{0}/projects/{1}'.format(id_toolkit_url, project_id)
579581
if tenant_id:
580582
self.base_url += '/tenants/{0}'.format(tenant_id)
581583

0 commit comments

Comments
 (0)