pavel murnikov
pavel murnikov

Reputation: 1

HTTP 403 on FCM HTTP v1 API call from PHP script

Keep receiving 403 when trying to send FCM notification from a PHP script with Google API Client for PHP 7.4 library installed

Warning: file_get_contents(https://fcm.googleapis.com/v1/projects//messages:send): failed to open stream: HTTP request failed! HTTP/1.0 403 Forbidden in file_get_contents()

My code is

require_once libraries_get_path('google-api-php-client') . '/vendor/autoload.php';
$client = new Google_Client();
try {
    $client->setAuthConfig(libraries_get_path('google-api-php-client') . 
        '/....json');
    $client->addScope(Google_Service_FirebaseCloudMessaging::CLOUD_PLATFORM);

        // $accessToken = generateToken($client);
        $client->fetchAccessTokenWithAssertion();
        $accessToken = $client->getAccessToken();    

        $client->setAccessToken($accessToken);
    
    $oauthToken = $accessToken["access_token"];
    $device_token = '...';
    $payload = ["message" => ["token" => $device_token, "notification"=>["title" => 'test message', "body"=> 'message body']]];
    $postdata = json_encode($payload);
    
    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-Type: application/json' . "\r\nAuthorization: Bearer $oauthToken",
            'content' => $postdata
        )
    );

    $context  = stream_context_create($opts);

    $result = file_get_contents('https://fcm.googleapis.com/v1/projects/<project>/messages:send', false, $context);

where service_account.json contains

{
  "type": "service_account",
  "project_id": "",
  "private_key_id": "...",
  "private_key": "...",
  "client_email": "...iam.gserviceaccount.com",
  "client_id": "...",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/...iam.gserviceaccount.com",
  "universe_domain": "googleapis.com"
}

I"m dealing with a legacy Drupal 7.x site so bumping PHP up to 8 is not an option. Sofar my suspicion is that the Google API PHP 7.4 library is the problem.

Any ideas/suggestions will be highly appreciated.

Upvotes: 0

Views: 59

Answers (1)

Yosua Christianov
Yosua Christianov

Reputation: 11

for sending through google you must use authentication method. which means that you must acquire key.json first from firebase console

  1. goto https://console.firebase.google.com/
  2. goto the intended project
  3. click on cogs button
  4. click on service accounts
  5. click on Generate New Private Key button.

it should be contain like this

{
  "type": "",
  "project_id": "",
  "private_key_id": "",
  "private_key": "",
  "client_email": "",
  "client_id": "",
  "auth_uri": "",
  "token_uri": "",
  "auth_provider_x509_cert_url": "",
  "client_x509_cert_url": "",
  "universe_domain": "",
}

then you should use require google library. im using this

composer require google/apiclient

require that on your project like this

require APPPATH . '/libraries/php-google/autoload.php';
use Google\Auth\Credentials\ServiceAccountCredentials;

on my example, i create a function to create a authentication

function getAccessToken() {
    $key = json_decode(file_get_contents('/config/key.json'), true);
    
    $scopes = ['https://www.googleapis.com/auth/cloud-platform']; // Define the scopes you need
    $credentials = new ServiceAccountCredentials($scopes, [
        'client_email' => $key['client_email'],
        'private_key' => $key['private_key']
    ]);
    
    return $credentials->fetchAuthToken()['access_token'];
}

change '/config/key.json' to the path of your key.. best to dont put it on public folder.

here is for send notification function

<?php 
    function send_notification ($token,$title,$body,$link=null) {
        $fcmUrl = "https://fcm.googleapis.com/v1/projects/YOUR PROJECT NAME/messages:send";
        $args = func_get_args();
        $response = ["status" => 0, "message" => "Notification couldn't be sent"];

        $tokenArr = $token;
        $msgNotification = [
            "title" => $title,
            "body" => $body,
        ];
        $extraNotificationData = [
            "notification_id" => "",
            "title" => $title,
            "link" => $link
        ];

        $fcmNotification = [
            "message" => [
                "token" => $tokenArr,
                "notification" => $msgNotification,
                "android" => [
                    "priority" => "normal"
                ],
                "data" => $extraNotificationData
            ]
        ];

        $headers = [
            "Authorization: Bearer ".getAccessToken(),
            "Content-Type: application/json"
        ];

        if ($token == null || $token == '') {
            $result = '';
        }
        else {
            $ch = curl_init();
            curl_setopt($ch, CURLOPT_URL,$fcmUrl);
            curl_setopt($ch, CURLOPT_POST, true);
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $encodedData);
            $result = curl_exec($ch);
            if ($result === FALSE) {
                $result = curl_error($ch);
            }
            curl_close($ch);
        }

        $response = ["status" => 1, "message" => "Notification sent to users", "payload" => $result];

        return [$response,$token];
    }
?>

Upvotes: 0

Related Questions