Authorize send requests

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:

  1. 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.

  2. 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.

  3. 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:

  1. In the Firebase console, open Settings > Service Accounts.

  2. Click Generate New Private Key, then confirm by clicking Generate Key.

  3. 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.
    If Content-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>SENDER_ID@fcm.googleapis.com/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.