Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save juandebravo/d19989f7efbee38606a4929c55f46330 to your computer and use it in GitHub Desktop.
Save juandebravo/d19989f7efbee38606a4929c55f46330 to your computer and use it in GitHub Desktop.
Firebase auth: change the custom token expiration time
import functools
import datetime
import time
from firebase_admin import auth
import google.auth.exceptions
EXP_TIME_GENERIC_TOKEN = int(datetime.timedelta(minutes=15).total_seconds())
RESERVED_CLAIMS = set([
'acr', 'amr', 'at_hash', 'aud', 'auth_time', 'azp', 'cnf', 'c_hash',
'exp', 'firebase', 'iat', 'iss', 'jti', 'nbf', 'nonce', 'sub'
])
FIREBASE_AUDIENCE = ('https://identitytoolkit.googleapis.com/google.'
'identity.identitytoolkit.v1.IdentityToolkit')
def _patch_create_custom_token(self, uid, developer_claims=None, tenant_id=None):
"""Builds and signs a Firebase custom auth token."""
if developer_claims is not None:
if not isinstance(developer_claims, dict):
raise ValueError("developer_claims must be a dictionary")
disallowed_keys = set(developer_claims.keys()) & RESERVED_CLAIMS
if disallowed_keys:
if len(disallowed_keys) > 1:
error_message = (
"Developer claims {0} are reserved and "
"cannot be specified.".format(", ".join(disallowed_keys))
)
else:
error_message = (
"Developer claim {0} is reserved and "
"cannot be specified.".format(", ".join(disallowed_keys))
)
raise ValueError(error_message)
if not uid or not isinstance(uid, str) or len(uid) > 128:
raise ValueError("uid must be a string between 1 and 128 characters.")
# Let define the expiration time but make sure we don't add it as custom claim
expiration_time = developer_claims.pop(
"max_lifetime_seconds", EXP_TIME_GENERIC_TOKEN
)
signing_provider = self.signing_provider
now = int(time.time())
payload = {
"iss": signing_provider.signer_email,
"sub": signing_provider.signer_email,
"aud": FIREBASE_AUDIENCE,
"uid": uid,
"iat": now,
"exp": now + expiration_time,
}
if tenant_id:
payload["tenant_id"] = tenant_id
if developer_claims is not None:
payload["claims"] = developer_claims
try:
return jwt.encode(signing_provider.signer, payload)
except google.auth.exceptions.TransportError as error:
msg = "Failed to sign custom token. {0}".format(error)
raise TokenSignError(msg, error)
def firebase_app():
# implement your way to obtain the Firebase app properly initialized
return None
def create_custom_token(
uid, max_lifetime_seconds=EXP_TIME_GENERIC_TOKEN, **dev_claims: Dict[str, str]
):
fb_app = firebase_app()
token_generator = auth._get_client(app=fb_app)._token_generator
initial_create_custom_token = token_generator.create_custom_token
try:
my_create_custom_token = functools.partial(
_patch_create_custom_token, token_generator
)
token_generator.create_custom_token = my_create_custom_token
return auth.create_custom_token(
uid,
dict(max_lifetime_seconds=max_lifetime_seconds, **dev_claims),
app=fb_app,
)
finally:
token_generator.create_custom_token = initial_create_custom_token
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment