Firebase gives you complete control over authentication by allowing you to
authenticate users or devices using secure JSON Web Tokens (JWTs). You generate
these tokens on your server, pass them back to a client device, and then use
them to authenticate via the signInWithCustomToken()
method.
To achieve this, you must create a server endpoint that accepts sign-in
credentials—such as a username and password—and, if the credentials are
valid, returns a custom JWT. The custom JWT returned from your server can then
be used by a client device to authenticate with Firebase
(iOS, Android,
web). Once authenticated, this identity will be
used when accessing other Firebase services, such as the Firebase Realtime Database
and Firebase Storage. Furthermore, the contents of the JWT will be
available in the auth
object in your
Firebase Realtime Database Security Rules and the
request.auth
object in your
Firebase Storage Security Rules.
You can create a custom token with the Firebase Server SDKs for Java and Node.js, or you can use a third-party JWT library if your server is written in a language which Firebase does not natively support.
Before you begin
To create custom tokens with the Firebase server SDKs, you must have a service account. Follow the server SDK setup instructions for more information on how to initialize your server SDK with a service account.
Create custom tokens using the Firebase SDK
The Firebase server SDKs have a built-in method for creating custom tokens. At
a minimum, you need to provide a uid
, which can be any string but should
uniquely identify the user or device you are authenticating.
Node.js
var uid = "some-uid";
var customToken = firebase.auth().createCustomToken(uid);
Java
String uid = "some-uid";
String customToken = FirebaseAuth.getInstance().createCustomToken(uid);
You can also optionally specify additional claims to be included in the custom
token. For example, below, a premiumAccount
field has been added to the
custom token, which will be available in the auth
/ request.auth
objects
in your Security Rules:
Node.js
var uid = "some-uid";
var additionalClaims = {
premiumAccount: true
};
var token = firebase.auth().createCustomToken(uid, additionalClaims);
Java
String uid = "some-uid";
HashMap<String, Object> additionalClaims = new HashMap<String, Object>();
additionalClaims.put("premiumAccount", true);
token = FirebaseAuth.getInstance().createCustomToken(uid, additionalClaims);
Sign in using custom tokens on clients
After you create a custom token, you should send it to your client app. The
client app authenticates with the custom token by calling
signInWithCustomToken()
:
iOS
Objective-C
[[FIRAuth auth] signInWithCustomToken:customToken
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error) {
// ...
}];
Swift
FIRAuth.auth()?.signIn(withCustomToken: customToken ?? "") { (user, error) in
// ...
}
Android
mAuth.signInWithCustomToken(mCustomToken)
.addOnCompleteListener(this, new OnCompleteListener<AuthResult>() {
@Override
public void onComplete(@NonNull Task<AuthResult> task) {
Log.d(TAG, "signInWithCustomToken:onComplete:" + task.isSuccessful());
// If sign in fails, display a message to the user. If sign in succeeds
// the auth state listener will be notified and logic to handle the
// signed in user can be handled in the listener.
if (!task.isSuccessful()) {
Log.w(TAG, "signInWithCustomToken", task.getException());
Toast.makeText(CustomAuthActivity.this, "Authentication failed.",
Toast.LENGTH_SHORT).show();
}
}
});
Web
firebase.auth().signInWithCustomToken(token).catch(function(error) {
// Handle Errors here.
var errorCode = error.code;
var errorMessage = error.message;
// ...
});
If the authentication succeeds, your user will be now signed in into your
client app with the account specified by the uid
included in the custom
token. If that account did not previously exist, a record for that user will be
created.
In the same way as with other sign-in methods (such as
signInWithEmailAndPassword()
and signInWithCredential()
) the auth
object
in your Firebase Realtime Database Security Rules and
the request.auth
object in your
Firebase Storage Security Rules will be
populated with the user's uid
. In this case, the uid
will be the one that
you specified when generating the custom token.
Database Rules
{
"rules": {
"adminContent": {
".read": "auth.uid === 'some-uid'"
}
}
}
Storage Rules
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /adminContent/{filename} {
allow read, write: if request.auth.uid == "some-uid";
}
}
}
If the custom token contains additional claims, they can be referenced off of
the auth.token
(Firebase Realtime Database) or request.auth.token
(Firebase Storage) object in your rules:
Database Rules
{
"rules": {
"premiumContent": {
".read": "auth.token.premiumAccount === true"
}
}
}
Storage Rules
service firebase.storage {
match /b/<your-firebase-storage-bucket>/o {
match /premiumContent/{filename} {
allow read, write: if request.auth.token.premiumAccount == true;
}
}
}
Create custom tokens using a third-party JWT library
If your backend is in a language that doesn't have an official Firebase server SDK, you can still manually create custom tokens. First, find a third-party JWT library for your language. Then, use that JWT library to mint a JWT which includes the following claims:
Custom Token Claims | ||
---|---|---|
alg |
Algorithm | "RS256" |
iss |
Issuer | Your project's service account email address |
sub |
Subject | Your project's service account email address |
aud |
Audience | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Issued-at time | The current time, in seconds since the UNIX epoch |
exp |
Expiration time |
The time, in seconds since the UNIX epoch, at which the token expires. It
can be a maximum of 3600 seconds later than the iat .
Note: this only controls the time when the custom token itself expires. But once you sign a user in using signInWithCustomToken() , they will remain signed in into the
device until their session is invalidated or the user signs out.
|
uid |
The unique identifier of the signed-in user must be a string, between 1-36 characters long | |
claims (optional) |
Optional custom claims to include in the Security Rules auth /
request.auth variables
|
Here are some example implementations of how to create custom tokens in a variety of languages for which official Firebase server SDKs do not exist:
PHP
Using php-jwt
:
// Get your service account's email address and private key from the JSON key file
$service_account_email = "abc-123@a-b-c-123.iam.gserviceaccount.com";
$private_key = "-----BEGIN PRIVATE KEY-----...";
function create_custom_token($uid, $is_premium_account) {
global $service_account_email, $private_key;
$now_seconds = time();
$payload = array(
"iss" => $service_account_email,
"sub" => $service_account_email,
"aud" => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"iat" => $now_seconds,
"exp" => $now_seconds+(60*60), // Maximum expiration time is one hour
"uid" => $uid,
"claims" => array(
"premium_account" => $is_premium_account
)
);
return JWT::encode($payload, $private_key, "RS256");
}
Python
Using the python-jwt
and pycrypto
packages:
import jwt # Requires: pip install python-jwt
import Crypto.PublicKey.RSA as RSA # Requires: pip install pycrypto
import datetime
# Get your service account's email address and private key from the JSON key file
service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
private_key = RSA.importKey("-----BEGIN PRIVATE KEY-----\n...")
def create_custom_token(uid, is_premium_account):
try:
payload = {
"iss": service_account_email,
"sub": service_account_email,
"aud": "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
"uid": uid,
"claims": {
"premium_account": is_premium_account
}
}
exp = datetime.timedelta(minutes=60)
return jwt.generate_jwt(payload, private_key, "RS256", exp)
except Exception as e:
print "Error creating custom token: " + e.message
return None
Ruby
Using ruby-jwt
:
require "jwt"
# Get your service account's email address and private key from the JSON key file
$service_account_email = "service-account@my-project-abc123.iam.gserviceaccount.com"
$private_key = OpenSSL::PKey::RSA.new "-----BEGIN PRIVATE KEY-----\n..."
def create_custom_token(uid, is_premium_account)
now_seconds = Time.now.to_i
payload = {:iss => $service_account_email,
:sub => $service_account_email,
:aud => "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit",
:iat => now_seconds,
:exp => now_seconds+(60*60), # Maximum expiration time is one hour
:uid => uid,
:claims => {:premium_account => is_premium_account}}
JWT.encode payload, $private_key, "RS256"
end
After you create the custom token, send it to your client app to use to authenticate with Firebase. See the code samples above for how to do this.