Migrate from legacy HTTP to HTTP v1

Apps using the FCM legacy HTTP API should consider migrating to the HTTP v1 API using the instructions in this guide. The HTTP v1 API has these advantages over the legacy API:

  • Better security via access tokens The HTTP v1 API uses short-lived access tokens according to the OAuth2 security model. In the event that an access token becomes public, it can only be maliciously used for an hour or so before it expires. Refresh tokens are not transmitted as often as the security keys used in the legacy API, so they are much less likely to be captured.

  • More efficient customization of messages across platforms For the message body, the HTTP v1 API has common keys that go to all targeted instances, plus platform-specific keys that let you customize the message across platforms. This allows you to create "overrides" that send slightly different payloads to different client platforms in a single message.

  • More extendable and future-proof for new client platform versions The HTTP v1 API fully supports messaging options available on iOS, Android and Web. Since each platform has its own defined block in the JSON payload, FCM can extend the API to new versions and new platforms as needed.

Update the server endpoint

The endpoint URL for the HTTP v1 API differs from the legacy endpont in these ways:

  • It is versioned, with /v1 in the path.
  • The path contains the project ID of the Firebase project for your app, in the format /projects/myproject-ID/. This ID is available in the General project settings tab of the Firebase console.
  • It explicitly specifies the specify the send method as :send.

To update the server endpoint for HTTP v1, add these elements to the endpoint in the header of your send requests.

Before

POST https://fcm.googleapis.com/fcm/send

After

POST https://fcm.googleapis.com/v1/projects/myproject-b5ae1/messages:send

Update authorization of send requests

In place of the server key string used in legacy requests, HTTP v1 send requests require an OAuth 2.0 access token. If you are using the Admin SDK to send messages, the library handles the token for you. If you are using the raw protocol, obtain the token as described in this section and add it to the header as Authorization: Bearer <valid Oauth 2.0 token>.

Before

Authorization: key=AIzaSyZ-1u...0GBYzPu7Udno5aA

After

Authorization: Bearer ya29.ElqKBGN2Ri_Uz...HnS_uNreA

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, 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, 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, Kubernetes Engine, App Engine, or Cloud Functions.

Node.js

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

Java

FirebaseOptions options = new 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

Use your Firebase credentials together with the Google API Client 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) {
    var key = require('./service-account.json');
    var 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);
    });
  });
}

Python

def _get_access_token():
  """Retrieve a valid access token that can be used to authorize requests.

  :return: Access token.
  """
  credentials = ServiceAccountCredentials.from_json_keyfile_name(
      'service-account.json', SCOPES)
  access_token_info = credentials.get_access_token()
  return access_token_info.access_token

Java

private static String getAccessToken() throws IOException {
  GoogleCredential googleCredential = GoogleCredential
      .fromStream(new FileInputStream("service-account.json"))
      .createScoped(Arrays.asList(SCOPES));
  googleCredential.refreshToken();
  return googleCredential.getAccessToken();
}

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 " + getAccessToken());
httpURLConnection.setRequestProperty("Content-Type", "application/json; UTF-8");
return httpURLConnection;

Update the payload of send requests

FCM HTTP v1 introduces a significant change in the structuring of the JSON message payload. Primarily, these changes ensure that messages are handled correctly when received on different client platforms; additionally, the changes give you extra flexibility to customize, or "override" message fields per platform.

In addition to inspecting the examples in this section, see Customizing a message across platforms and review the API reference to gain familiarity with HTTP v1.

Example: simple notification message

Here is a comparison of a very simple notification payload— containing title, body and data fields only— demonstrating the fundamental differences in legacy and HTTP v1 payloads.

Before

{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available."
  },
  "data": {
    "story_id": "story_12345"
  }
}

After

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    }
  }
}

Example: targeting multiple platforms

To enable multiple-platform targeting, the legacy API performed overrides in the backend. By contrast, HTTP v1 provides platform-specific blocks of keys that make any differences between platforms explicit and visible to the developer. This allows you to target multiple platforms always with a single request, as demonstrated in the following sample.

Before

// Android
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "TOP_STORY_ACTIVITY"
  },
  "data": {
    "story_id": "story_12345"
  }
}
// iOS
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "HANDLE_BREAKING_NEWS"
  },
  "data": {
    "story_id": "story_12345"
  }
}

After

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    }
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY"
      }
    },
    "aps": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

Example: customizing with platform overrides

In addition to simplifying cross-platform targeting of messages, the HTTP v1 API provides flexibility to customize messages per platform.

Before

// Android
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "Check out the Top Story.",
    "click_action": "TOP_STORY_ACTIVITY"
  },
  "data": {
    "story_id": "story_12345"
  }
}
// iOS
{
  "to": "/topics/news",
  "notification": {
    "title": "Breaking News",
    "body": "New news story available.",
    "click_action": "HANDLE_BREAKING_NEWS"
  },
  "data": {
    "story_id": "story_12345"
  }
}

After

{
  "message": {
    "topic": "news",
    "notification": {
      "title": "Breaking News",
      "body": "New news story available."
    },
    "data": {
      "story_id": "story_12345"
    },
    "android": {
      "notification": {
        "click_action": "TOP_STORY_ACTIVITY",
        "body": "Check out the Top Story"
      }
    },
    "apns": {
      "payload": {
        "aps": {
          "category" : "NEW_MESSAGE_CATEGORY"
        }
      }
    }
  }
}

For more samples and information about the FCM HTTP v1 API, see the Firebase Blog.

Gửi phản hồi về...

Bạn cần trợ giúp? Truy cập trang hỗ trợ của chúng tôi.