Requests sent to FCM from your app server or trusted environment must be authorized. Note these important differences between the deprecated legacy HTTP API and HTTP v1 API authorization:
- The FCM HTTP v1 API authorizes requests with a short-lived OAuth 2.0 access token. To mint this token, you can use Google Application Default Credentials (in Google server environments) and/or manually obtain the required credentials from a JSON private key file generated for a service account. If you are using the Firebase Admin SDK to send messages, the library handles the token for you.
- The deprecated legacy protocols can use only long-lived API keys obtained from the Firebase console.
Authorize HTTP v1 send requests
Depending on the details of your server environment, use a combination of these strategies to authorize server requests to Firebase services:
- Google Application Default Credentials (ADC)
- A service account JSON file
- A short-lived OAuth 2.0 access token derived from a service account
If your application is running on Compute Engine, Google Kubernetes Engine, App Engine, or Cloud Functions (including Cloud Functions for Firebase), use Application Default Credentials (ADC). ADC uses your existing default service account to obtain credentials to authorize requests, and ADC enables flexible local testing via the environment variable GOOGLE_APPLICATION_CREDENTIALS. For the fullest automation of the authorization flow, use ADC together with Admin SDK server libraries.
If your application is running on a non-Google server environment, you'll need to download a service account JSON file from your Firebase project. As long as you have access to a file system containing the private key file, you can use the environment variable GOOGLE_APPLICATION_CREDENTIALS to authorize requests with these manually obtained credentials. If you lack such file access, you must reference the service account file in your code— which should be done with extreme care due to the risk of exposing your credentials.
Provide credentials using ADC
Google Application Default Credentials (ADC) checks for your credentials in the following order:
ADC checks whether the environment variable GOOGLE_APPLICATION_CREDENTIALS is set. If the variable is set, ADC uses the service account file that the variable points to.
If the environment variable isn't set, ADC uses the default service account that Compute Engine, Google Kubernetes Engine, App Engine, and Cloud Functions provide for applications that run on those services.
If ADC can't use either of the above credentials, the system throws an error.
The following Admin SDK code example illustrates this strategy. The example doesn't explicitly specify the application credentials. However, ADC is able to implicitly find the credentials as long as the environment variable is set, or as long as the application is running on Compute Engine, Google Kubernetes Engine, App Engine, or Cloud Functions.
Node.js
admin.initializeApp({
credential: admin.credential.applicationDefault(),
});
Java
FirebaseOptions options = FirebaseOptions.builder()
.setCredentials(GoogleCredentials.getApplicationDefault())
.setDatabaseUrl("https://<DATABASE_NAME>.firebaseio.com/")
.build();
FirebaseApp.initializeApp(options);
Python
default_app = firebase_admin.initialize_app()
Go
app, err := firebase.NewApp(context.Background(), nil)
if err != nil {
log.Fatalf("error initializing app: %v\n", err)
}
C#
FirebaseApp.Create(new AppOptions()
{
Credential = GoogleCredential.GetApplicationDefault(),
});
Provide credentials manually
Firebase projects support Google service accounts, which you can use to call Firebase server APIs from your app server or trusted environment. If you're developing code locally or deploying your application on-premises, you can use credentials obtained via this service account to authorize server requests.
To authenticate a service account and authorize it to access Firebase services, you must generate a private key file in JSON format.
To generate a private key file for your service account:
In the Firebase console, open Settings > Service Accounts.
Click Generate New Private Key, then confirm by clicking Generate Key.
Securely store the JSON file containing the key.
When authorizing via a service account, you have two choices for providing the credentials to your application. You can either set the GOOGLE_APPLICATION_CREDENTIALS environment variable, or you can explicitly pass the path to the service account key in code. The first option is more secure and is strongly recommended.
To set the environment variable:
Set the environment variable GOOGLE_APPLICATION_CREDENTIALS to the file path of the JSON file that contains your service account key. This variable only applies to your current shell session, so if you open a new session, set the variable again.
Linux or macOS
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/Downloads/service-account-file.json"
Windows
With PowerShell:
$env:GOOGLE_APPLICATION_CREDENTIALS="C:\Users\username\Downloads\service-account-file.json"
After you've completed the above steps, Application Default Credentials (ADC) is able to implicitly determine your credentials, allowing you to use service account credentials when testing or running in non-Google environments.
Use credentials to mint access tokens
Unless you are using the Admin SDK, which handle authorization automatically, you'll need to mint the access token and add it to send requests.
Use your Firebase credentials together with the Google Auth Library for your preferred language to retrieve a short-lived OAuth 2.0 access token:
node.js
function getAccessToken() {
return new Promise(function(resolve, reject) {
const key = require('../placeholders/service-account.json');
const jwtClient = new google.auth.JWT(
key.client_email,
null,
key.private_key,
SCOPES,
null
);
jwtClient.authorize(function(err, tokens) {
if (err) {
reject(err);
return;
}
resolve(tokens.access_token);
});
});
}
In this example, the Google API client library authenticates the request with a JSON web token, or JWT. For more information, see JSON web tokens.
Python
def _get_access_token():
"""Retrieve a valid access token that can be used to authorize requests.
:return: Access token.
"""
credentials = service_account.Credentials.from_service_account_file(
'service-account.json', scopes=SCOPES)
request = google.auth.transport.requests.Request()
credentials.refresh(request)
return credentials.token
Java
private static String getAccessToken() throws IOException {
GoogleCredentials googleCredentials = GoogleCredentials
.fromStream(new FileInputStream("service-account.json"))
.createScoped(Arrays.asList(SCOPES));
googleCredentials.refresh();
return googleCredentials.getAccessToken().getTokenValue();
}
After your access token expires, the token refresh method is called automatically to retrieve an updated access token.
To authorize access to FCM, request the scope
https://www.googleapis.com/auth/firebase.messaging
.
To add the access token to an HTTP request header:
Add the token as the value of the Authorization
header in the format
Authorization: Bearer <access_token>
:
node.js
headers: {
'Authorization': 'Bearer ' + accessToken
}
Python
headers = {
'Authorization': 'Bearer ' + _get_access_token(),
'Content-Type': 'application/json; UTF-8',
}
Java
URL url = new URL(BASE_URL + FCM_SEND_ENDPOINT);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setRequestProperty("Authorization", "Bearer " + getServiceAccountAccessToken());
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;
Authorize legacy protocol send requests
With the HTTP legacy protocol, each request must contain the server key from the Cloud Messaging tab of the Firebase console Settings pane. For XMPP, you must use the same server key to establish a connection.
Migrate legacy server keys
Starting from March 2020, FCM stopped creating legacy server keys. Existing legacy server keys will continue to work, but we recommend that you instead use the newer version of key labeled Server key in the Firebase console.
If you want to delete an existing legacy server key, you can do so in the Google Cloud console.
Authorize HTTP requests
A message request consists of two parts: the HTTP header and the HTTP body. The HTTP header must contain the following headers:
Authorization
: key=YOUR_SERVER_KEY
Make sure this is the server key, whose value is available in the Cloud Messaging tab of the Firebase console Settings pane. Android, Apple platform, and browser keys are rejected by FCM.Content-Type
:application/json
for JSON;application/x-www-form-urlencoded;charset=UTF-8
for plain text.
IfContent-Type
is omitted, the format is assumed to be plain text.
For example:
Content-Type:application/json Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA { "to" : "bk3RNwTe3H0:CI2k_HHwgIpoDKCIZvvDMExUdFQ3P1...", "data" : { ... }, }
See Build Send Requests for full detail on creating send requests. The Legacy HTTP Protocol Reference provides a list of all the parameters your message can contain.
Checking the validity of a server key
If you receive authentication errors when sending messages, check the validity of your Server key. For example, on Linux, run the following command:
api_key=YOUR_SERVER_KEY curl --header "Authorization: key=$api_key" \ --header Content-Type:"application/json" \ https://fcm.googleapis.com/fcm/send \ -d "{\"registration_ids\":[\"ABC\"]}"
If you receive a 401 HTTP status code, your Server key is not valid.
Authorize an XMPP connection
With XMPP, you can maintain a persistent, asynchronous, bidirectional connection to FCM servers. The connection can be used to send and receive messages between your server and your users' FCM-connected devices.
You can use most
XMPP libraries to manage a long-lived connection to FCM. XMPP endpoint runs at
fcm-xmpp.googleapis.com:5235
. When testing
functionality with non-production users, you should instead connect to the pre-production server at
fcm-xmpp.googleapis.com:5236
(note the different port).
Regular testing on pre-production (a smaller environment where the latest FCM builds run) is
beneficial for isolating real users from test code. Test devices and test code connecting to
fcm-xmpp.googleapis.com:5236
should use a different FCM sender ID to avoid any risks
of sending test messages to production users or sending upstream messages from production traffic
over test connections.
The connection has two important requirements:
- You must initiate a Transport Layer Security (TLS) connection. Note that FCM doesn't currently support the STARTTLS extension.
- FCM requires a SASL PLAIN authentication mechanism using
<your_FCM_Sender_Id>@fcm.googleapis.com
(FCM sender ID) and the Server key as the password. These values are available in the Cloud Messaging tab of the Firebase console Settings pane.
If at any point the connection fails, you should immediately reconnect. There is no need to back off after a disconnect that happens after authentication. For each sender ID, FCM allows 2500 connections in parallel.
The following snippets illustrate how to perform authentication and authorization for an XMPP connection to FCM.
XMPP server
The XMPP server requests a connection to FCM
<stream:stream to="fcm.googleapis.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
FCM
FCM opens the connection and requests an auth mechanism, including the
PLAIN
method.
<stream:features> <mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"> <mechanism>X-OAUTH2</mechanism> <mechanism>X-GOOGLE-TOKEN</mechanism> <mechanism>PLAIN</mechanism> </mechanisms> </stream:features>
XMPP server
The XMPP server must respond using the PLAIN
auth method, providing the server key from the
Cloud Messaging tab of the Firebase console Settings pane.
<auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">MTI2MjAwMzQ3OTMzQHByb2plY3RzLmdjbS5hb mFTeUIzcmNaTmtmbnFLZEZiOW1oekNCaVlwT1JEQTJKV1d0dw==</auth>
FCM
<success xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/>
XMPP server
<stream:stream to="fcm.googleapis.com" version="1.0" xmlns="jabber:client" xmlns:stream="http://etherx.jabber.org/streams">
FCM
<stream:features> <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"/> <session xmlns="urn:ietf:params:xml:ns:xmpp-session"/> </stream:features>
XMPP server
<iq type="set"> <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"></bind> </iq>
FCM
<iq type="result"> <bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"> <jid>[email protected]/RESOURCE</jid> </bind> </iq>
Note: FCM does not use the bound resource while routing messages.
See Build Send Requests for full detail on creating send requests. The Legacy XMPP Protocol Reference provides a list of all the parameters your message can contain.