Impossible to create a device group from android device - android

Since few days my app is not able anymore to create a device group from my android app. According to Firebase docs we should be able to manage device groups from server or client side. I didn't change my app from few years! So I guess something is changed without any reference in the docs. Currently my app does:
JSONObject data = new JSONObject();
data.put("operation", "add");
data.put("notification_key_name", notificationKeyName);
data.put("registration_ids", new
JSONArray(Collections.singletonList(registrationId)));
data.put("id_token", idToken);
RequestBody body = RequestBody.create(MEDIA_TYPE_JSON, data.toString());
Request oreq = new
Request.Builder().url("https://fcm.googleapis.com/fcm/googlenotification")
.addHeader("project_id", projectId)
.addHeader("Content-Type", "application/json")
.addHeader("Accept", "application/json")
.post(body)
.build();
where the notification key name is the user email of Google account the token is retrieved using
String idToken = GoogleAuthUtil.getToken(this, account, scope);
and the registration id is retrieved using
FirebaseMessaging.getInstance().getToken()
When the app now sends the request the result is "sender denied" but as I said I didn't change anything. In the Firebase docs however I can't find anymore any reference to the endpoint https://fcm.googleapis.com/fcm/googlenotification so is it changed anything?
I tracked the web page with firebase doc and I saw that the section relative to the client android app management of device groups has been removed one year ago, on 18th March 2020.

I reply to myself: Firebase support finally replied saying that the client support has been removed without any advice. No solution to this problem. Personal note: don't use anymore Firebase products.

Related

Send Notification specific logged User Using Firebase Cloud Messeging

On my android app have many users but I want to send notification only specific user who is suitable. I don't want to send all users. if a user is already logged on app notification will pop up on the screen.
Need help, Suggestion will be highly appreciatable.
When the device firebase initialized, it will return a device token, which we normally send it the backend so it will be stored in the backend database together with the user id, then later can used for your purpose.
When a user first runs your app Firebase generates a Token for that user and his device. Each time user deletes the app and reinstalls it will re-generate this Token. This also includes new devices of course since that is just like the first installation ever.
What I did with this is that I used the Firebase Realtime database in which I stored this Token for each user I have. Then when I need to send the notification to that user I just get that token and send it within my application. This is one old example on how I did that:
OkHttpClient client = new OkHttpClient();
Logger.getLogger(OkHttpClient.class.getName()).setLevel(Level.FINE);
JSONObject json = new JSONObject();
JSONObject notifJson = new JSONObject();
JSONObject dataJson = new JSONObject();
notifJson.put("text", body);
notifJson.put("title", title);
dataJson.put("customId", "02");
json.put("notification", notifJson);
json.put("data", dataJson);
json.put("to", firebase_token);
RequestBody body = RequestBody.create(MediaType.parse("application/json"), json.toString());
.header("Authorization", "key="+server_key)
.url("https://fcm.googleapis.com/fcm/send")
.post(body)
.build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) { //do something if notification is sent successfully }
You can do this using your code to send notifications to a specific user. This is, of course, if you want to send a notification from your code. If you want to use a server or something there is documentation you can follow here: https://firebase.google.com/docs/cloud-messaging/android/send-multiple
What I used in this example:
notifJson - notification part
dataJson - data part of notification
body - the body of my notification
title - the title of my notification
firebase_token - Token of user I am sending a notification to, this is retrieved earlier with Firebase real-time database
server_key - Server key from Firebase configuration
In the IF statement below if the response was successful I add some data to my real-time database but you can do anything else you want.

Send sms from client android Twilio?

Hi would like to send an sms verification to users phone numbers.I have done it in ios by calling the rest Api and it works.
But can anyone help me with android I get an error :
code=401, message=UNAUTHORIZED.
Any help would be apreciated?
url = https://{AccountSid}:{AuthToken}#api.twilio.com/2010-04-01/AccountsAccountSid}/SMS/Messages
private OkHttpClient mClient2 = new OkHttpClient();
Call post(String url, Callback callback) throws IOException {
Random rand = new Random();
randomNum = 1000 + rand.nextInt((100000 - 1000) + 1);
RequestBody formBody = new FormBody.Builder()
.add("To", etNumber.getText().toString())
.add("From", "+mynum")
.add("Body", "Your confirmation code for United taxi is" + randomNum)
.build();
Request request = new Request.Builder()
.url(url)
.post(formBody)
.build();
Call response = mClient2.newCall(request);
System.out.println(request.url());
response.enqueue(callback);
return response;
}
The WWW-Authenticate header is:
WWW-Authenticate: Basic realm="Twilio API"
Twilio Developer Evangelist here.
I actually happen to have written a blog post explaining why you shouldn't make requests like this directly from the device, but have a server in the middle. It will not only make your account more secure, but make it much easier to debug.
Best of all, even if you don't wanna build a backend yourself, my blog post shows you how to deploy one with the click of a button.
Check it out here or get started with your server-side language of choice and finish up with the post.
As for the error you're getting, UNAUTHORIZED implies you're not passing the correct AccountSid & AuthToken. If you still want to go down the route of making the request directly from the device, which again, we don't recommend, I would suggest trying to make the request from something like Postman for example, to make sure you've got your credentials right, and then moving that to the device using OkHttp.

Android app with Google+ API: Client ID or Android ID?

I'm trying to develop an application that makes use of some basic Google+ Apis. The app request a token from Google that then upload on my server and my server check for its validation with Google. What I don't understand (I'm a bit confused) is what's the difference between Client ID for Web application and Client ID for Android application in Google Developers Console. I've tried both of them on the Android app and both work (successfully obtained a token). Obviously, when using the Web Client ID, my SCOPE that I pass using GoogleAuthUtil.getToken() is different from the one using Android Client ID. So, what's the difference between them? I think that I should go for the Android Client ID, but I'd like to know the really differences.
On client side I use:
final String token = GoogleAuthUtil.getToken(mContext, userEmail, G_PLUS_SCOPE);
Where G_PLUS_SCOPE = oauth2:https://www.googleapis.com/auth/plus.me
On server side, I check with Google with this code:
GoogleIdToken token = GoogleIdToken.parse(mJFactory, getRequest().getAuthToken());
if (mVerifier.verify(token)) {
GoogleIdToken.Payload tempPayload = token.getPayload();
if (!tempPayload.getAudience().equals(mAudience)) {
problem = "Audience mismatch";
errorMessage = new ErrorMessage(ErrorCodes.AUDIENCE_MISMATCH,problem,null);
mResponse = new ErrorResponse( errorMessage);
}
else if (!mClientIDs.contains(tempPayload.getAuthorizedParty())) {
problem = "Client ID mismatch";
errorMessage = new ErrorMessage(ErrorCodes.CLIENT_ID_MISMATCH,problem,null);
mResponse = new ErrorResponse(errorMessage);
}
I also don't understand what's the exact value of mAudience. Do I need to put the Client ID as mAudience? And, is the mClientIDs the array containing all the key (Including the Android client ID key)?
Thanks for your help
EDIT: Following http://android-developers.blogspot.it/2013/01/verifying-back-end-calls-from-android.html I've read that the Audience is the Client ID for Web Application and the mIds are all the ID for installed application (1 for me because I've only Android). But I'm not sure if this is the right way of thinking it for every case.
I don't have answer to your question but I found this blog which can help you out:
http://www.androidhive.info/2014/02/android-login-with-google-plus-account-1/
I hope this helps you.
Technically the audience is the client ID which the ID token is intended to authenticate the user to, where the authorized party is the client ID which the ID token was issued to:
http://openid.net/specs/openid-connect-core-1_0.html#IDToken
You should verify both when both are provided. When requesting an ID Token from your Android app, you should use the Client ID of your server to make the request. Your server should then verify that it is the audience for the token when it receives it from your Android client.

Am I getting the steps right for verifying a user's Android in-app subscription?

I am making an app that does not require a user account/login, and allows the user to purchase a subscription. I want to use the Google Play Developer API to verify whether or not a user has a purchased/active subscription. From all of the documentation, I've gathered the following steps.
Are they correct, and could you answer the two questions in them?
Create a Service Account in the Google APIs Console.
Save the private key that is given to me (where? surely not in my code/on the device as this sample code suggests)
Use Google APIs Client Library for Java to create and sign a JWT with the private key (how? the docs give me this, but that is not Java code... What do I do with it?)
Construct an access token request, and get access to the API
Application can now send a GET request to the API to find out whether or not the
user has a subscription
When the access token expires, go back to step 3.
Also, I have a web service, though I know nothing about web services or web service programming... I only know enough to be aware that it is probably necessary to use here.
EDIT: These steps were not correct. See my answer below for the correct steps. However, note that this only applies to using a service account (because I did not want to require a user to have to explicitly allow API access)
As it turns out, my steps were not correct. It took me weeks to figure this out and it doesn't seem to be documented anywhere else. You're welcome:
Create a Web Application account in the Google APIs Console. Put any website as a "redirect URI"; it doesn't matter since you will not really be using it. You will get a client id and client secret when you create the account.
In a browser on your computer go to https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=[YOUR REDIRECT URI]&client_id=[YOUR CLIENT ID] and allow access when prompted.
Look in the address bar. At the end of the URI you entered originally will be your refresh token. It looks like 1/.... You will need this "code" in the next step. The refresh token never expires.
Convert this "code" to a "refresh token" by going to https://accounts.google.com/o/oauth2/token?client_id=[YOUR CLIENT ID]&client_secret=[YOUR CLIENT SECRET]&code=[CODE FROM PREVIOUS STEP]&grant_type=authorization_code&redirect_uri=[YOUR REDIRECT URI]. You can save the resulting value right in your program; it never expires unless explicitly revoked. (this step inserted by #BrianWhite -- see comments)
Make sure you are using POST.(inserted by Gintas)
In your code, send an HttpPost request to https://accounts.google.com/o/oauth2/token with the BasicNameValuePairs "grant_type","refresh_token", "client_id",[YOUR CLIENT ID], "client_secret",[YOUR CLIENT SECRET], "refresh_token",[YOUR REFRESH TOKEN]. For an example look here. You will need to do this in a separate thread, probably using AsyncTask. This will return a JSONObject.
Get the access token from the returned JSONObject. For an example look here. You will need to get the string "access_token". The access token expires in 1 hour.
In your code, send an HttpGet request to https://www.googleapis.com/androidpublisher/v1/applications/[YOUR APP'S PACKAGE NAME]/subscriptions/[THE ID OF YOUR PUBLISHED SUBSCRIPTION FROM YOUR ANDROID DEVELOPER CONSOLE]/purchases/[THE PURCHASE TOKEN THE USER RECEIVES UPON PURCHASING THE SUBSCRIPTION]?accesstoken="[THE ACCESS TOKEN FROM STEP 4]". For an example look here.
.NET Users: I hope this answer saves someone a ton of grief.
As #Christophe Fondacci noted on 2015, the accepted solution worked great a few years ago.
Now it's 2017 2020 and the process is far easier and faster.
My use case is to validate in-app subscriptions, where my mobile app sends subscription purchase information to my RESTful server, which in turn contacts Google to validate a subscription purchase.
The strategy is to create a Service Account that will operate on your behalf.
Sign into your Google Play Dev Console and click the app you're setting up.
Visit Settings->API access
Under Service Accounts, hit the Create Service Account button.
As of Jan 2017 a dialog with directions on setting up a service account appears. The dialog takes you to the Google API Console; from there,
A) Click Create Service Account
B) Create the service account name that makes sense. Since we're interested in accessing Android Publisher Services, I chose "publisher".
C) For Role, just choose something - you can change this later.
D) Choose "Furnish New private key" and choose P12 for .Net implementations. Don't lose this file!
Now you're done with #4, you'll see your new Service Account listed; click "Grant Access" to enable it.
Tap on the link to "View permissions". You should modify permissions based on your needs and API.
To validate in-app purchases, visit the Cog->Change Permissions and enable the GLOBAL "Visibility" and "Manage Orders" permissions.
OK at this point you have configured everything on Google's end. Now to setup your server to server stuff. I recommend creating
a .Net Console App to test out your implementation then offload it where needed.
Add the Android Publisher Client Library from Nuget[1]
PM> Install-Package Google.Apis.AndroidPublisher.v3
Add the P12 file to your project root
Change the P12 Properties so "Build Action" is "Content" and "Copy To Output Directory" to "Copy if newer".
Implement something like this to test your access and fine tune [1] .
using System.Threading.Tasks;
using System.Security.Cryptography.X509Certificates;
using Google.Apis.Services;
using Google.Apis.Auth.OAuth2;
using Google.Apis.AndroidPublisher.v3;
...
public Task<SubscriptionPurchase> GetSubscriptionPurchase(string packageName, string productId, string purchaseToken)
{
var certificate = new X509Certificate2(
"{{your p12 file name}}",
"{{ your p12 secret }}",
X509KeyStorageFlags.Exportable
);
var credentials = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer("{{ your service account email }}")
{
Scopes = new[] { AndroidPublisherService.Scope.Androidpublisher }
}.FromCertificate(certificate));
var service = new AndroidPublisherService(new BaseClientService.Initializer()
{
HttpClientInitializer = credentials,
ApplicationName = "my server app name",
});
return service.Purchases.Subscriptions.Get(packageName, productId, purchaseToken).ExecuteAsync();
}
Good luck, hope this helps someone.
Sources:
Using OAuth 2.0 for Server to Server Applications
.Net Client Library for Google.Apis.AndroidPublisher.v3[1]
1 Updated 04/11/2020 - Google.Apis.AndroidPublisher.v2 EOL'd, use Google.Apis.AndroidPublisher.v3.
If you are like me, and want to do this in PHP, here is the procedure how to do it... Thanks to Kalina's answer it took me only three days to work out how it works :).
Here goes:
go to google developers console https://console.developers.google.com/ and create a web app. Put 'developers.google.com/oauthplayground'as a "redirect URI"; You will use it in step 2. You will get a client id and client secret when you create the account. Make sure you have the Google Play Android Developer API added.
go to the Google oauth2 playground https://developers.google.com/oauthplayground/. This great tool is your best friend for the next few days.
Now go to settings : make sure Use your own OAuth credentials is set. Only then you can fill in your client ID and client secret in the form below.
In Google oauth2 playground go to step 1 Select & authorize APIs fill in the scope in the input field https://www.googleapis.com/auth/androidpublisher. I couldnt find the Google Play Android Developer API in the list, maybe they will add some time later. Hit AUTORIZE APIS. Do the authorisation thing that follows.
In Google oauth2 playground go to step 2 Exchange authorization code for tokens. If all went well you will see a authorization code starting with /4. If something didnt go well check the error message on the right. Now you hit 'refresh access token'. Copy the Refresh token... it will start with /1...
Now you can always get an access token! here is how:
$url ="https://accounts.google.com/o/oauth2/token";
$fields = array(
"client_id"=>"{your client id}",
"client_secret"=>"{your client secret}",
"refresh_token"=>"{your refresh token 1/.....}",
"grant_type"=>"refresh_token"
);
$ch = curl_init($url);
//set the url, number of POST vars, POST data
curl_setopt($ch, CURLOPT_POST,count($fields));
curl_setopt($ch, CURLOPT_POSTFIELDS, $fields);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//execute post
$lResponse_json = curl_exec($ch);
//close connection
curl_close($ch);
Now you have an ACCESS TOKEN hooray... the JSON will look like this:
"access_token" : "{the access token}", "token_type" : "Bearer", "expires_in" : 3600
Finally you're ready to ask google something! Here is how to do it:
$lAccessToken = "{The access token you got in}" ;
$lPackageNameStr = "{your apps package name com.something.something}";
$lURLStr = "https://www.googleapis.com/androidpublisher/v1.1/applications/$lPackageNameStr/subscriptions/$pProductIdStr/purchases/$pReceiptStr";
$curl = curl_init($lURLStr);
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$curlheader[0] = "Authorization: Bearer " . $lAccessToken;
curl_setopt($curl, CURLOPT_HTTPHEADER, $curlheader);
$json_response = curl_exec($curl);
curl_close($curl);
$responseObj = json_decode($json_response,true);
The JSON returned will contain two timestamps, the initiationTimestampMsec and validUntilTimestampMsec the time the subscription is valid. Both are the nr of millisecs to add to the date 1/1/1970!
I don't know in 2012, but in 2015 you should not do any of these steps manually. I had a very hard time to find the documentation so I am posting here in case it helps anyone.
You should only query in-app purchases from your server for security reasons as otherwise you can trust none of the 2 ends of the purchase process.
Now on the server side (I think you could still use the same code from your app if you absolutely need to), include the google-api-services-androidpublisher client library to your project (see https://developers.google.com/api-client-library/java/apis/androidpublisher/v1)
As you mentioned, you need a service account with a P12 file (the client library only accept P12 file).
Then the following code will authenticate and get purchase information nicely:
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
JsonFactory jsonFactory = new JacksonFactory();
List<String> scopes = new ArrayList<String>();
scopes.add(AndroidPublisherScopes.ANDROIDPUBLISHER);
Credential credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setServiceAccountId(googleServiceAccountId)
.setServiceAccountPrivateKeyFromP12File(new File(googleServicePrivateKeyPath))
.setServiceAccountScopes(scopes).build();
AndroidPublisher publisher = new AndroidPublisher.Builder(httpTransport, jsonFactory, credential).build();
AndroidPublisher.Purchases purchases = publisher.purchases();
final Get request = purchases.get(packageName, productId, token);
final SubscriptionPurchase purchase = request.execute();
// Do whatever you want with the purchase bean
Information on Java client authentication can be found here:
https://developers.google.com/identity/protocols/OAuth2ServiceAccount
I may misunderstand your question, but I don't see a reason for you to be using the links you're referencing to get In-App Billing for an Android app working. This page is much more helpful:
http://developer.android.com/guide/google/play/billing/index.html
You can try out the demo application they include (Dungeons -- http://developer.android.com/guide/google/play/billing/billing_integrate.html#billing-download). That uses products (one-time purchases) rather than subscriptions, but you should be able to modify to test for what you want.
I think the key, for you, would be the restoreTransactions method they provide in the sample to see if the Google Play account has any subscriptions for your app:
#Override
public void onRestoreTransactionsResponse(RestoreTransactions request, int responseCode) {
if (responseCode == BillingVars.OK) {
// Update the shared preferences so that we don't perform a RestoreTransactions again.
// This is also where you could save any existing subscriptions/purchases the user may have.
SharedPreferences prefs = getSharedPreferences(my_prefs_file, Context.MODE_PRIVATE);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(DB_INITIALIZED, true);
edit.commit();
} else {
Log.e(TAG, "RestoreTransactions error: " + responseCode);
}
}
If anyone is having issues with the accepted posts final step (#7), i found ?access_token= to work instead of ?accessToken=
Too bad stack overflow won't let me make that comment directly to the thread...
As you have a web service which your app can call, I would recommend storing your private key securely on your server. You should look to moving as much of the in-app stuff to service calls, as possible, see this link. I've implemented in-app subscription, but it was before this part of the API was out. I had to do my own registration and security verification but it looks like this API does most of that for you, using OAuth, although it looks like you are still responsible for storing the subscription request/verification.
Where it talks about signing your JWT's with an existing library, they do appear to provide you with links to a java library, a Python library and a PHP library - it depends what your web service or server component is written in (mine is C#, so I'm using RSACryptoServiceProvider) to verify signed purchases. They're using JSON objects for the actual transfer of data.

How to call https://www.googleapis.com/plus/v1/people/me at google

I am developing an Android application and need to get the "me" info from google but I always ends up in either response code 401 or 403. What am I doing wrong?
Here is my code:
private static final String GOOGLE_AUTH_TOKEN_TYPE = "oauth2:https://www.googleapis.com/auth/plus.me";
I get the oauth token by (note...code below is shortened):
Account googleAccount = (AccountManager) getSystemService(ACCOUNT_SERVICE).getAccountsByType("com.google")[0];
final Bundle bundle = manager.getAuthToken(googleAccount, GOOGLE_AUTH_TOKEN_TYPE, true, null, null).getResult();
String authToken = bundle.getString(AccountManager.KEY_AUTHTOKEN);
So far so good... I now have a token so everything looks good here.
Now get the me info:
String GOOGLE_ME_URL = "https://www.googleapis.com/plus/v1/people/me";
final DefaultHttpClient client = new DefaultHttpClient();
final HttpGet request = new HttpGet(GOOGLE_ME_URL);
request.addHeader("Authorization", "OAuth=" + authToken);
final HttpResponse response = client.execute(request);
This gives response code 401.
I have also tried:
final DefaultHttpClient client = new DefaultHttpClient();
final HttpGet request = new HttpGet(GOOGLE_ME_URL + "?access_token=" + authToken);
final HttpResponse response = client.execute(request);
This gives response code 403 - Something like "Daily limit exceeded. Please sign up".
What am I doing wrong? what have I missed? How should this be done?
Thanks
// Edits below
Some more investigation:
I added a project into code.google.com/apis/console and took the key generated from there and put into the url, like:
https://www.googleapis.com/plus/v1/people/me?key=my_generated_key&access_token=" + authToken.
Now the call works fine and I get a 200 response with the correct info. But I really don´t want to use this method if I don´t have to and according to google I should not need to "•If the request requires authorization (such as a request for an individual's private data), then it must include an OAuth 2.0 token. It may also include the API key, but it doesn't have to." - from developers.google.com/+/api/oauth.
Another thing:
If I try another url like
"https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=" + authToken
it works fine.
The issue is regarding the simple api key passed into the request.
If the key parameter isn't included in the request, or if the Google+ API wasn't activated for that project, you'll get the error:
"Daily limit exceeded. Please sign up".
To solve this problem, you need to do the following:
Visit the Google API Console here: https://code.google.com/apis/console/?api=plus
Under the Services panel, make sure the Google+ API is turned "on".
In the APIs console, click API Access in the left menu.
Copy the API key presented towards the bottom.
Include this API key in your HTTP request.
GOOGLE_ME_URL + "?access_token=" + authToken + "&key=" + MY_SIMPLE_API_KEY
Most of the newer Google APIs have quotas (like daily usage limits) and some even have billing support (where you get billed per API call). These quotas and billing are calculated per developer's project, and not on a per-end-user basis, so Google needs to know which app to assign your API usage.
API clients using Google's OAuth 2.0 are typically required to register and get a client ID and client secret.
This client ID and client secret are returned by the Google APIs console: code.google.com/apis/console.
You then use these values in your application, and this identifies your app and allows Google to assign your API usage to your developer account/project.
In the AccountManger interface you're using, there is no client ID passed by your app, so Google can't identify which developer account/project's quota to deduct for usage. It also doesn't know that the API has been properly enabled (TOS accepted, etc) by you as a developer. That's why it's asking you to "please sign up" and saying the "Daily limit exceeded" (as the unregistered limit is zero requests for many APIs).
In this scenario, it is necessary for you to pass the "key" value as you did in order to access APIs with OAuth 2.0 tokens retrieved from the AccountManager.
Why don't some of you try to go to the Google Console. In this way you will be able to have access to to the tools you need to rectify at least 403 forbidden problems. DMC
Generate a new auth token and secret for your application and try again.
That might solve your problem, but your daily retry limit might be exhausted...
I had the same issue you're having.
You are using HTTP at the moment, but you are actually calling a the site over HTTPS. Either use a secure connection procedure or use the http:// address.
You just need to enable Google+ API in console.

Categories

Resources