Google Client fails to verify token on back-end server - php

I have downloaded project from Try Sign-in for Android, created project on Google API Console. I have successfully configured signin project and run the application in the emulator. I pasted OAuth Web Client ID into strings.xml. Then opened this IdTokenActivity and got idToken.
I copied this token and created request using POSTMAN to my server http://localhost/api/googlesignin/hello
On server I have this code:
public function hello(Request $request)
{
$idToken = $request->get('idToken');
$client = new \Google_Client([
'client_id' => '[SAME CLIENT ID AS THE ONE IN STRINGS.XML]'
]);
$payload = $client->verifyIdToken($idToken);
var_dump($payload)
}
But this returns FALSE meaning it fails to verify $idToken.
But using endpoint token verification like this:
https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={$idToken}
returns status code 200 and all information about this user.
I have no idea why GoogleClient fails to verify token? Am I using wrong Client ID?
EDIT:
I have found the source of the problem: I have accidentally pasted twice ClientID:
'client_id' => 'client-id-tokenclient-id-token'
-.-

Related

Authorising native app user with Google ID token and Laravel Socialite gives 401

I have an issue with Socialite authentication via Google. I have two separate apps: Laravel and React Native. For react native app I use #react-native-community/google-signin and after getting a token on the client I'm sending it to the Laravel app, where I pass this token into Socialite function: Socialite::driver('google')->userFromToken($token); . I get this error:
Client error: GET https://www.googleapis.com/oauth2/v3/userinfo?prettyPrint=false resulted in a 401 Unauthorized response:
{
"error": "invalid_request",
"error_description": "Invalid Credentials"
}
I've rechecked credentials 4 times and I'm sure they are right. I use the same client id as in react native app. What am I doing wrong?
Note: I am using ID token to authorise instead of auth token.
From my research on a similar issue - It looks like Google one tap doesn't work in the same way as oAuth does.
So, you'd have to fetch a user from the $token manually, using the google/apiclient package.
There's an example in Google docs (it's in the android-section, but these particular snippets refer to back-end part, so it should still do the trick)
composer require google/apiclient
// Get $id_token via HTTPS POST.
$client = new Google_Client(['client_id' => $CLIENT_ID]); // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
$userid = $payload['sub'];
// If request specified a G Suite domain:
//$domain = $payload['hd'];
} else {
// Invalid ID token
}
You can find more info on this Google Docs Page

Authentication failure trying to upload Vimeo video

Using the official Vimeo PHP Library (https://github.com/vimeo/vimeo.php)
Attempting to upload a video using the upload() method of the client library return the following http response:
The authentication token is missing a user ID and must be provided when uploading a video.
However the Client Id, Client Secret, and Token are all being set on the client before calling the upload() method:
Client initialization:
$this->setClient(new Vimeo($this->clientId, $this->clientSecret, $this->token));
Call to upload method:
try{
$videoUri = $this->getClient()->upload($path, [
'name' => $name,
'privacy' => [
'view' => 'anybody'
]
]);
return $videoUri;
} catch (\Exception $e) {
dump($e);
return false;
}
There is a tutorial endpoint, which I called using the client created above and got the following response:
{
"message": "Success! You just interacted with the Vimeo API. Your dev environment is configured correctly, and the client ID, client secret, and access token that you provided are all working fine.",
"next_steps_link": "https://developer.vimeo.com/api/guides/videos/upload",
"token_is_authenticated": false
}
Any suggestions welcomed!
The token you are generating is unauthenticated, meaning it can only read metadata public on vimeo.com -- it cannot be used to upload, retrieve data, or perform other actions on an account.
The giveaway is in the last line of the /tutorials response:
"token_is_authenticated": false
Take a look at the authentication docs on the Vimeo Developer Site here: https://developer.vimeo.com/api/authentication#understanding-auth-workflows
The issue was the the token being used was an unauthenticated token. I'd made the assumption that you only needed an authenticated token to upload on behalf of another user. By generating a new authenticated token that had the 'upload' scope I was able to upload the video using the exact code posted above.

How can I get this Google Login ID Token from this Android app to verify server-side?

I'm getting the ID Token in my Android app by initiating like this:
GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.server_client_id))
.requestEmail()
.build();
Where server_client_id is my SERVER's Oauth Client ID. Then later I request the token with googleAccount.getIdToken()
Then on my server (PHP), when I verify the token I verify it like this:
$client = new \Google_Client(['client_id' => getenv("GOOGLE_CLIENT_ID")]);
try {
$payload = $client->verifyIdToken($this->idToken);
} catch (\Exception $e){
throw new BadRequestHttpException($e->getMessage());
}
if($payload){
$this->verifyPayload($payload);
} else {
throw new AccessDeniedHttpException("Invalid ID Token");
}
Where GOOGLE_CLIENT_ID is my ANDROID's Oauth Client ID
I'm following this guide: https://developers.google.com/identity/sign-in/android/start-integrating.
On this page it says: https://developers.google.com/identity/sign-in/android/backend-auth
When you configure Google Sign-in, call the requestIdToken method and pass it your server's web client ID.
Hence why I'm using the server_client_id in my Android app. Is this correct?
// Specify the CLIENT_ID of the app that accesses the backend
And this is why I'm using the ANDROID client ID from my server.
Is this right? To be using each other's Oauth client_id's? Or should they both be using the Android CLIENT_ID?
Thanks in advance
OK I figured it out. Both the Android app and Webserver need to use the SERVER's key. Even though I created a client ID for the app using it's key SHA1 and everything.
Send authorisation request from the app, using client_id and public key
As a response you get a temporary token
Send the token to your API. Use it to make another request (from the API to Google), to get a long lived token
Store the long-lived token. Use it to request data from google, f.e. user information
Important: never use server key inside the app

Verify the integrity of the Google ID token by Php (Laravel)

I'm developing an application which has two sides: mobile side(IOS) and server-side (PHP, Laravel 5.4). I'm using google's own class to generate the google token and send them over to server in json format.
My Json looks like this:
["name": "ali farhangmehr", "email": "ali.farhangmehr#gmail.com", "google_image_url": https://lh5.googleusercontent.com/-6KoifJgUUW0/AAAAAAAAAAI/AAAAAAAAA60/BbWD4fEDvHk/s100/photo.jpg, "googleToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjVlYTZiNzAzYjYzOTVmYzJlNWJkNmUzY2EwZjhiMzcxYTE0ODU5YjMifQ.eyJhenAiOiIyNTk3NjE1MTY5NjEtOXZ0Y3AyZnQ1dXZsaGJkdmxlM2lndDlsbDg3b3FwM2EuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyNTk3NjE1MTY5NjEtOXZ0Y3AyZnQ1dXZsaGJkdmxlM2lndDlsbDg3b3FwM2EuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDU4NzI5MzY5MDEzOTMwNjEyNTEiLCJlbWFpbCI6ImFsaS5mYXJoYW5nbWVockBnbWFpbC5jb20iLCJlbWFpbF92ZXJpZmllZCI6dHJ1ZSwiYXRfaGFzaCI6IkN6S0htamlYOUhDM2JjaGZRTGJ3ZXciLCJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJpYXQiOjE1MDIwNDc4MjAsImV4cCI6MTUwMjA1MTQyMCwibmFtZSI6ImFsaSBmYXJoYW5nbWVociIsInBpY3R1cmUiOiJodHRwczovL2xoNS5nb29nbGV1c2VyY29udGVudC5jb20vLTZLb2lmSmdVVVcwL0FBQUFBQUFBQUFJL0FBQUFBQUFBQTYwL0JiV0Q0ZkVEdkhrL3M5Ni1jL3Bob3RvLmpwZyIsImdpdmVuX25hbWUiOiJhbGkiLCJmYW1pbHlfbmFtZSI6ImZhcmhhbmdtZWhyIiwibG9jYWxlIjoiZW4ifQ.fMbcS3axTumt1hW4_Fss3C3QfLc_Ohhqlj3XfRkDmXixOlnEAV-9GaxI-6IOl0bdh382rJd2Ign4Fjdw8dJ5kGNhMmci9sV-_G50FU3vNH60RptJ04QX7BGrfUOjCJIV5dARJqsCNwqVWItR1F5z-gz9WHA0YKAjMCTWMWSuF03O0yowqzPoajwBLk5VNGOk7Q9fRvKEG7tnTGkckCBSBwWa5KdYnQw-k1OGB9W7qjcQrCelPE8SPzR_GwhHNoAGTOpZXQQSoeDNad8JWbExGZ9MeBDRoaLfLIoV7NRrVaSEwc4wSmga-yqlqjhGaULcdUGOZOasbhDyl28ULEDK2w"]
There is no problem so far. Then I have to check if the Google token is valid so I can register the user or log in the email
This is the link to the Google's own documentation on this matter
https://developers.google.com/identity/sign-in/web/backend-auth
I followed everything and my PHP code looks like this:
$input = $request->all();
$google_token = $input['google_token'] = $request->input('googleToken');
$client_id = $CLIENT_ID; //from my google console
$client=new Google_Client(['client_id' => $client_id]);
$payload=$client->verifyIdToken($google_token);
$client->verifyIdToken($google_token);
if ($payload) {
// do the login or register
} else {
return false;
}
and every time I'm getting this error:
(1/1) SignatureInvalidException
Signature verification failed
in JWT.php (line 112)
this issue because of new JWT for firebase
just use old version on JWT it will work
composer require firebase/php-jwt:4.0

FCM push notification issue: "error":"NotRegistered"

I am getting weird issue of sending push notification to Android using FCM.
Goal :- Having error while sending push notification
Below is the scenario I do have function for sending push notification to Android
public static function SendMultipleNotificationAndroid($groups)
{
//your api key SERVER API KEY
$apiKey = Yii::$app->params['android_api_key'];
$url = 'https://fcm.googleapis.com/fcm/send';
$headers = array(
'Authorization:key=' . $apiKey,
'Content-Type: application/json'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
foreach($groups as $resG){
$users = $resG['users'];
$msg = $resG['message'];
$type = $resG['notification_type'];
$notification_data = $resG['notification_data'];
$deviceTokens = [];
foreach($users as $resUser){
$deviceTokens[] = $resUser['device_token'];
//Add Friend badge count +1
Common::AddRemoveBadgeCount($resUser['user_id']);
}
if(!empty($deviceTokens)){
$fields = array(
'registration_ids' => $deviceTokens,
'priority' => 'high',
'collapse_key' => $resG['notification_type'],
'time_to_live' => 2419200,
"click_action" =>"NotificationListingActivity",
'data' => [
"title" => "ProjectName",
"body" => $resG['message'],
"action_tag" => $resG['notification_type'],
"message" => $resG['message'],
'notification_type' => $type,
'notification_data' => $notification_data,
'sound' => 'default',
]
);
//Print result
p($ch,0);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
curl_exec($ch);
}
}
curl_close($ch);
}
So the issue is when I send single notification it works fine but when I send multiple notification I got error every time
<pre>Resource id #5</pre>{"multicast_id":4818908994630396118,"success":1,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"},{"message_id":"0:1487136045570022%c3bae3c6002e9358"}]}
<pre>Resource id #5</pre>{"multicast_id":5218359780835228544,"success":1,"failure":1,"canonical_ids":0,"results":[{"error":"NotRegistered"},{"message_id":"0:1487136046618669%c3bae3c6002e9358"}]}
As we debug the code we do have device token in our database no firewall which stops sending push notifications.
Every time I call above function I get
"error":"NotRegistered"
According to the doc its because the mobile device testing does not have your app installed anymore
If it is NotRegistered, you should remove the registration ID from
your server database because the application was uninstalled from the
device, or the client app isn't configured to receive messages.
Don't know much about php, but recently I have faced the same issue in another project and I have resolved this way :
Refere this first :
Where can I find the API KEY for Firebase Cloud Messaging?
and get updated API key as shown in below snapshot
This is a client-side (device) issue, not service-side.
Multiple scenarios can cause this:
If the client app unregisters with GCM.
If the client app is automatically unregistered, which can happen if the user uninstalls the application. For example, on iOS, if the APNS Feedback Service
reported the APNS token as invalid.
If the registration token expires (for example, Google might decide to refresh registration tokens, or the APNS token has expired for iOS devices).
If the client app is updated but the new version is not configured to receive messages.
See https://developers.google.com/cloud-messaging/http-server-ref
On app startup I check to see if the token I have stored locally matches the new token. If not then I refresh the token on my servers. I also do this in FirebaseInstanceIDService::onTokenRefresh.
The thing is firebase generates a unique device-ID for your target device when the app is run for the first time, and it will be used as the identity of the device.
If the user uninstalls the app or clears the data of the app then in that case on reinstalling or reopening the app the device-ID will differ. This will result in the ID not be identified by firebase to send the notification. This will result in the error Not Registered
I got this error when i uninstalled and reinstalled my application.
What i think is, when we reinstall application, we cant get a new fcm token every time we install.
So, we must first delete the previous instance id and then create new fcm token. Please see the code below..
Just adding the uncommented line resolved my issue..
See first comment for this solution for code :)
_firebaseRegister() {
// _firebaseMessaging.deleteInstanceID();
_firebaseMessaging.getToken().then((token) => fcmtoken = token);
}
Hope this works for you! :)
In my case, the problem was on the recipient side, not the sender. If you're sending a message to someone who has not run the app for awhile, then their device token is stale. All they need to do is restart the app.
In your case, did you ensure that when you sent multiple notifications all the devices you messaged were up and running and that the app refreshes the token on startup by calling FirebaseMessaging.getInstance().getToken()?
While searching for the "NotRegistered" issue, we found the following ...
At device end, the generation of device notification token was done by following code once, when user first time starts the app after installation.
RegToken = FirebaseInstanceId.getInstance().getToken(senderId, "FCM"); // Old code
We were using other class derived from "FirebaseMessagingService" to create / receive notifications. But the following method was missing in that class.
// New code
#Override
public void onNewToken(String token) {
Log.d(TAG, "Refreshed token: " + token);
// If you want to send messages to this application instance or
// manage this apps subscriptions on the server side, send the
// Instance ID token to your app server.
sendRegistrationToServer(token);
}
We found that, the above method was called by FCM system in device on every start of App. ( The App was not Uninstalled, still the method was giving different token every time. ) So we called our method 'sendRegistrationToServer(token);' to submit the token to our server along with the 'DeviceId' and other identification data. When we sent notification from php server on this token, it returned 'sent' instead of "NotRegistered".
This error appeared in an Android application when sending request to https://fcm.googleapis.com/fcm/send:
...
"results": [
{
"error": "NotRegistered"
}
]
While the application was working well for some time, and push notifications were delivered, then (probably after reauthorization in the app or reauthorization in Play Market) that error started to show.
If I changed push token (added "1", for instance), then I got another error:
"results": [
{
"error": "InvalidRegistration"
}
]
So, Firebase knew about the push token, but didn't deliver a notification.
I uninstalled the Android application and installed again.
My problem was different then all of the above. The Firebase message that we we're trying exceeded the maximum size of 4Kb. Very small chance this triggers an "NotRegistered". But the problem was that I took this log of a moment the app was probably not installed. So also check the size of the Firebase message.
In our case, this issue appears on iOS when we override a production installation of the app using Xcode "Run" (replaces production app with the debug version in-place).
The app still receives the same registration token, but doesn't accept messages (NotRegistered is returned from the FCM).
We've found out that uninstalling the app from the device, and performing a clean install fixes this issue.
In my case, updating the FCM token for the device worked!
I have a 100 percent solution i had fix recently this issue this
error, occurring because you are sending this notification on a device
which does does not contain your firebase setup api key For example
when you registered user that time user registered from different
firebase setup so your android token was different and your sending
request to other firebase setup for which didn't create android token
whom you trying to send notification(message) so you would have to
make sure your user android token generating from same firebase
project of which project you are using firebase api key
In my case, two cloned emulators are the reason.
I think cloned emulators have same device ID, so firebase think they are same device.
So when one device get a push message, the push token may be removed and return not NotRegistered.
If you are in the similar situation, try to remove the emulator and create new one.
A possible solution can be update user push token.
When the client app is updated (new version), old push token is changed.
I got this error after setting firebase and using app for some time.
I updated google-service.json file (look for new file in the user's personal account firebase) and reinstall app. It helps me.
For iOS, I ran into the same issue. We were only saving the token on didRegisterForRemoteNotificationsWithDeviceToken. As mentioned above, you can lose reference to the token for a variety of reasons.
To fix the "NotRegistered" error, I added the following to App Delegate:
extension AppDelegate: MessagingDelegate {
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String) {
print("Firebase registration token: \(String(describing: fcmToken))")
//Notification setup. Token will be available anywhere
let dataDict: [String: String] = ["token": fcmToken ]
NotificationCenter.default.post(
name: Notification.Name("FCMToken"),
object: nil,
userInfo: dataDict
)
// Send token to application server.
if Auth.auth().currentUser?.uid != nil {
guard let userUid = Auth.auth().currentUser?.uid else { return }
let dataBaseRef = Database.database().reference()
let value: [String : Any] = ["pushToken" : fcmToken]
dataBaseRef.child("Your database path here").updateChildValues(value, withCompletionBlock: { (error, ref) in
if error != nil {
print("Error with storing/updating user token", error?.localizedDescription as Any)
}
})
}
}
}
didReceiveRegistrationToken is called anytime the token is updated.
After uninstalling the app in my device, the error occurred. That was because my code wasn't set up to regenerate a new fcm device token. The firebase documentation for this API recommends to call the method at app start and update your backend (or wherever you're using the tokens). I fixed it with the snippet below:
import {Platform} from 'react-native';
import messaging from '#react-native-firebase/messaging';
useEffect(() => {
requestPermission();
messaging()
.getToken()
.then(async token => {
console.log('_token=>>>', token);
if (token) {
setDeviceToken(token);
// update user realtime fdb with device token and userIdToken
const _authDriverIdRef = firebase
.database()
.ref(`users/${user.uid}`);
_authDriverIdRef.update({
fcmDeviceToken: deviceToken,
userIdToken: await user?.getIdToken(true),
});
}
});
});
const requestPermission = async () => {
return Platform.OS === 'ios' && (await messaging().requestPermission());
};
See if you have uninstalled the app and your device token is modified. Update the device token, and your error will be gone

Categories