# Migrating to FCM v1 endpoint Sinch currently requests FCM push notifications using the FCM legacy endpoint, which is deprecated and will reach End of Life in June 2024 (see [Firebase FAQ](https://firebase.google.com/support/faq#fcm-23-deprecation)). To continue using FCM, your Sinch application must be migrated to use the FCM v1 API instead, which is the current supported method from Firebase/Google. If you want Sinch to keep sending FCM push notifications to your Android devices after June 2024, you **must** follow this migration guide. If you don't, Sinch won't be able to request FCM push messages on your behalf. ## Overview The new FCM endpoint requires a different type of credentials ("short-lived access tokens", more details in [next section](#oauth20-authentication-in-fcm-v1)), and Sinch has to adjust its authentication flow and interact with your backend to fetch such credentials. From your perspective, performing the migration is essentially a 2 steps process: 1. you have to implement 2 new public endpoints ("Authorization server", "Resource server"), that Sinch will contact to fetch the FCM credentials; 2. you have to share with Sinch the URL of these endpoints, together with credentials to access them, and trigger the migration; this step is performed via [Sinch Dashboard](https://dashboard.sinch.com/voice/apps). Note: You can find a sample implementation of an authorization server, together with a tutorial on how to configure it for Sinch usage, as a [public repo in Sinch's GitHub](https://github.com/sinch/rtc-sample-oauth-server-for-fcm-v1). ## OAuth2.0 authentication in FCM v1 The main difference between the FCM legacy endpoint and FCM v1 is the authentication method, as FCM v1 only supports short-lived access tokens, according to the OAuth2 security mode. This means you'll have to provide Sinch with those access tokens, which will then in turn be used by Sinch to authenticate with FCM v1 API. Compared with the current authentication method (that requires you to share a private key with Sinch), this is a more secure approach because: * your FCM private key is stored privately in your backend, and it's never shared with anyone * in case an access token is leaked, it can only be used by malicious actors until it expires Sinch will request you short-lived access tokens for FCM using *OAuth 2.0 Client Credentials* flow (see [overview of Client Credential flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow)). ## Providing FCM tokens to Sinch In broad terms, the key steps you have to follow to provide FCM tokens are: 1. Implement an *OAuth2.0 Authorization Server* endpoint (your organization might already have one in place that you can leverage). 2. Implement another endpoint, protected by a standard *OAuth2.0 Client Credentials* flow, that provides FCM tokens ("FCM token endpoint") valid for FCM v1 API 3. Provide Sinch with: * *OAuth2.0 Client Credentials* (`client_id`, `client_secret`, `scope`) that are valid within **your own** OAuth domain * URL of your Auth Server * URL of the FCM tokens endpoint ### Overview The desired flow after the migration is complete is the following: ![Sinch - FCM v1 OAuth Flow](/assets/20242201-fcm-v1-migration.cce89dd401236cdb023be4aececd57b3d69f277511f9ddd4f33efbac9c872f9d.5f3ff73a.png) #### Key takeaways from the diagram above 1. When Sinch needs a new `access_token_FCM` (required to request a push message via FCM v1 API), it will first make a request to your *Authorization Server* to obtain a `access_token_RO` valid for your security domain (*RO* as in *Resource Owner*). 2. Having obtained an `access_token_RO`, Sinch will make a subsequent request to your FCM access token endpoint, providing `access_token_RO` as a *Bearer* token. 3. Your *Resource Server* should pass the `access_token_FCM` (as received from Firebase) in the response back to Sinch. 4. Sinch will only make requests to "Your Auth Server" endpoint and "Your FCM Token endpoint" as needed, not for every push message sent. Sinch will cache the FCM access token in accordance to the value of `expires_in`. 5. See [Implementing the FCM Token Endpoint](#implementing-the-fcm-token-endpoint) section for details on how to mint `access_token_FCM`. #### Contextualizing the diagram in the OAuth2.0 standard 1. The component labeled "Your FCM Token endpoint" is your [*OAuth2.0 Resource Server*](https://www.oauth.com/oauth2-servers/the-resource-server/), with the resource being the FCM tokens. 2. The `scope` mentioned in the diagram is [*OAuth2.0 Scope*](https://www.oauth.com/oauth2-servers/scope/), and its default value is `https://www.googleapis.com/auth/firebase.messaging`. 3. The tokens provided by "Your Auth server" and "Your FCM token endpoint" are [*OAuth2.0 Access Tokens*](https://www.oauth.com/oauth2-servers/access-tokens/access-token-response/). 4. The requests to "Your Auth server" and "Your FCM Token endpoint" will have `Content-Type: application/x-www-form-urlencoded`, according to [OAuth2 standard](https://datatracker.ietf.org/doc/html/rfc6749). ### Providing OAuth configuration to Sinch Select your app in the [Sinch Dashboard](https://dashboard.sinch.com/voice/apps), and the **In-app Voice & Video SDKs** tab. The configuration for FCM consists of the following fields in the "Google FCM Identification" section: | Field name | Field value | | --- | --- | | **Access token URL** | URL of your Auth Server endpoint | | **FCM token URL** | URL of your FCM token endpoint | | **Client ID** | Your `client_id` | | **Client Secret** | Your `client_secret` | | **Scope** | An OAuth *scope* (optional, will default to `https://www.googleapis.com/auth/firebase.messaging`) | ### Implementing the Authorization server Endpoint As described in the overview, Sinch will make a request to your *Authorization server*, to request an access token valid for the "FCM token endpoint". The request will be populated with the fields from the OAuth configuration you provided (see [Providing OAuth configuration to Sinch](#providing-oauth-configuration-to-sinch) section), and it will be of the following form: ```text POST / Content-Type: application/x-www-form-urlencoded grant_type=client_credentials client_id= client_secret= scope= ``` Example response to Sinch: ```text HTTP/1.1 200 OK Content-Type: application/json;charset=utf-8 { "access_token": "", "expires_in": 3600, "token_type": "Bearer" } ``` The `access_token` included in the response will then be used by Sinch as Bearer token in the subsequent call to the "FCM token endpoint". ### Implementing the FCM Token Endpoint As described in the overview, Sinch will make a request to your *Resource Server* FCM token endpoint, requesting an FCM access token. The request will be of the following form: ```text POST / Authorization: Bearer Content-Type: application/x-www-form-urlencoded grant_type=client_credentials fcm_project_number= ``` Example response to Sinch: ```text HTTP/1.1 200 OK Content-Type: application/json;charset=utf-8 { "access_token": "", "expires_in": 3600, "token_type": "Bearer" } ``` Notes: * Sinch will be able to use this `access_token` to send push messages to your end-user devices until the token expires, upon which Sinch will issue a new token request to your *Authorization Server* and *Resource Server*; the recommendation is that you obtain a new FCM access token every time Sinch requests it. * Sinch will cache the `access_token` according to its `expires_in` value; the default value for `expires_in` in Google Auth Library is 1 hour (3600 seconds) and maximum value is 86400 (24h) * Your implementation of this resource endpoint should obtain an FCM `access_token` using one of the methods recommended by the [Firebase documentation](https://firebase.google.com/docs/cloud-messaging/auth-server) - see also [Google API Client Libraries](https://developers.google.com/api-client-library/) for a list of implementations of the Google Auth Library. * You might have to provide a list of permissions when creating an FCM private key; in such case, only `cloudmessaging.messages.create` (see [GCP's Permissions reference](https://cloud.google.com/iam/docs/permissions-reference)) is required. * `FcmProjectNumber` is an unique identifier of your Firebase project; note that every Firebase project has [2 unique identifiers](https://firebase.google.com/docs/projects/learn-more#project-identifiers): "project ID" and "project number", and both [are supported](https://firebase.google.com/docs/reference/fcm/rest/v1/projects.messages/send#path-parameters) in the context of FCM v1. However, Sinch will use `fcmProjectNumber` because it's already available in Sinch backend: whenever a Sinch client is created, this value is provided as `senderId`. See: * Sinch Android SDK [reference docs](https://download.sinch.com/android/6.7.11/reference/sinch-rtc/com.sinch.android.rtc/-fcm-push-configuration-builder/sender-i-d.html), and keep in mind that "sender ID" has the same value of "FCM project number"; * Sinch Android public docs about [acquiring FCM push configuration](https://developers.sinch.com/docs/in-app-calling/android/push-notifications/#fcm-step-4-acquire-fcm-push-configuration). ## Resources * [FCM documentation](https://firebase.google.com/docs/cloud-messaging) * [OAuth2.0 official website](https://oauth.net/2/) * [OAuth2.0 RFC](https://datatracker.ietf.org/doc/html/rfc6749) * [Client Credentials flow](https://auth0.com/docs/get-started/authentication-and-authorization-flow/client-credentials-flow) * [Google client libraries](https://developers.google.com/api-client-library/), to support FCM token generation