Firebase Admin SDK libraries provide a function to generate a custom JSON Web Token (JWT) to authenticate users. The generated JWT expiration time is fixed to 60 minutes and Firebase doesn't allow tokens with a higher expiration time than 60 minutes.
But how can we generate tokens with a custom expiration time lesser than 60 minutes? Let's talk about a viable plan.
Anatomy of Firebase JWT
It's not a secret that you can decode any JWT and see the contents.
Try it on JWT
By looking at the decoded contents of the token, we can identify the payload properties responsible for tracking the expiry time. Specifically iat
- (issued-at-time) and exp
- (expiration time) are the keys that track the time of initialization and expiration in seconds since UNIX epoch.
Let's Hack It
The official Admin SDK function to create custom tokens accept three arguments. Here developer_claims
and tenant_id
is optional. developer_claims
is a dictionary where it accepts additional data to be encoded within the JWT generated.
create_custom_token(self, uid, developer_claims, tenant_id)
I tried to tweak the official Admin SDK function to create a custom token with a custom expiration time by passing the same dictionary keys iat
and exp
assuming that will replace the internally generated expiration values.
custom_token = auth.create_custom_token('12345', {'iat': 48784, 'exp': 83733})
But the result wasn't successful at all. The official Admin SDK restricted that returning me an error.
ValueError: Developer claims iat, exp are reserved and cannot be specified.
The Decent Way
So the tweak didn't work as expected. We cannot do that with Firebase Admin SDK. But Firebase documentation suggests a third-party JWT library just in case there's no officially supported Admin SDK for a particular programming language.
Although that is the original intention to depend on a third-party JWT library to generate custom auth tokens. We can use it to create JWT with a custom expiration time. So here, we make use of PyJWT
library in Python to generate a token from the scratch.
import jwt
import time
TOKEN_EXPIRATION_TIME_IN_MINUTES = 2
user_id = 'XXXXXXXXX'
# Refer your admin SDK credential JSON file to replace below values
service_account_email = "firebase-adminsdk-**@***.iam.gserviceaccount.com"
private_key = b"-----BEGIN PRIVATE KEY-----\n*****"
# Current time in seconds
current_time = int(time.time())
payload = {
'iss': service_account_email,
'sub': service_account_email,
'aud': "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
'iat': current_time,
'exp': current_time + (TOKEN_EXPIRATION_TIME_IN_MINUTES*60),
'uid': user_id
}
encoded_token = jwt.encode(payload, private_key, algorithm="RS256")
# Tokens are created as a binary. Decoding with utf-8 will convert it to a String
jwt_token = encoded.decode("utf-8")
Token Refresh
Firebase tokens are created with a maximum of 60 minutes expiration time. You might wonder what happens after the time of token expiration. Should you worry about it?
In general scenarios, short-lived auth tokens are associated with long-lived refresh tokens to exchange for a new auth token when auth token expired. So, we should worry about the mechanism of acquiring a new auth token when it is expired.
But, Firebase client SDKs will handle this token exchange internally and keep you logged in for an indefinite time until a signout
call. So, no need to worry about token management even a custom token generated via a third-party JWT library.