Firebase Cloud Messaging authorization failure - go

I'm currently trying to implement a server in Go working with Firebase Cloud Messaging. I inserted my API key and sender ID (which I both got from the Firebase console at Project Settings -> Cloud Messaging) and did this:
err := gcm.Listen(senderID, apiKey, onMessageReceived, nil)
and all I get is this
error creating xmpp client>error connecting client>auth failure: not-authorized
I'm using the same library Google's using in it's examples. Is the library maybe not working with FCM yet or am I doing something wrong?
If it's the library, how would I implement this without it?

This library will works perfectly with firebase, if you do several things:
Change xmppHost from https://gcm-http.googleapis.com/gcm/send to https://fcm.googleapis.com/fcm/send
Add new const xmppDomain = "gcm.googleapis.com"
Change function xmppUser, it should be like
func xmppUser(senderId string) string {
return senderId + "#" + xmppDomain
}

Related

Gmail API - Oauth2/google: no credentials found (Golang)

​Hello All,
Wanted to do server-side integration for Gmail API. The basic need is using enabling Gmail API I want to read my Gmail inbox for some analytics purpose.
Golang Package - "google.golang.org/api/gmail/v1"
As per documentation, I have followed the below steps.
New Signed up with Gmail
Added billing details to use GCP services
Created test project
Enabled Gmail API
Created Service Account and key inside it. Got credentials.json file
On the backend side, I am using the Golang package to extract the
Gmail inbox.
After successful integration, I am trying to run my code but getting
the below error
{"level":"error","msg":"Error while creating gmail service : oauth2/google: no credentials found","time":"2021-07-25T15:11:23+05:30"}
Can anyone help me to figure out what is missing?
I currently use OAuth with YouTube and the device flow [1], so maybe this can be helpful. First you need to make a one time request like this:
data := url.Values{
"client_id": {"something.apps.googleusercontent.com"},
"scope": {"https://www.googleapis.com/auth/youtube"},
}
res, err := http.PostForm("https://oauth2.googleapis.com/device/code", data)
You'll get a response like this:
type OAuth struct {
Device_Code string
User_Code string
Verification_URL string
}
which you can do a one time prompt to user like this:
1. Go to
https://www.google.com/device
2. Enter this code
HNDN-ZWBL
3. Sign in to your Google Account
Then, after user log in, you can do an exchange request like this:
data := url.Values{
"client_id": {"something.apps.googleusercontent.com"},
"client_secret": {"super secret"},
"device_code": {"device code from above"},
"grant_type": {"urn:ietf:params:oauth:grant-type:device_code"},
}
res, err := http.PostForm("https://oauth2.googleapis.com/token", data)
This will give you an access_token and refresh_token, that you can save locally for reuse. In addition to "device flow", you also have "native app" flow [2], but I found the former to be a simpler process.
https://developers.google.com/identity/sign-in/devices
https://developers.google.com/identity/protocols/oauth2/native-app

Google Cloud identity token oidcToken.GetAccessTokenAsync() fails and without error message

When calling a google oauth library method, it fails without error - no amount of try/catch-ing traps any error messages.
I am trying to get an identity token much as I would if I executed gcloud auth print-identity-token from the command line using the gcloud cli.
The reason for wanting the identity token is that another Cloud Function service requires it as Authorization : Bearer [token], and indeed works correctly when I stuff a manually generated identity token in my code. That is not a suitable solution for development or production
The code snippet I wrote, cobbled from numerous sources, to procure an identity token is this:
using (var stream = new FileStream(credentialsFilePath, FileMode.Open, FileAccess.Read))
{
var credentials = GoogleCredential.FromStream(stream);
if (credentials.IsCreateScopedRequired)
{
credentials = credentials.CreateScoped(scopes);
}
OidcToken oidcToken = await credentials.GetOidcTokenAsync(
Options
.FromTargetAudience(scopes[0])
.WithTokenFormat(OidcTokenFormat.Standard));
// this line bombs immediately, jumping out of this method and the calling method.
string token = await oidcToken.GetAccessTokenAsync();
return token;
}
In the above code, scopes[0] is left over code from a previous attempt which contains the endpoint to Cloud Function service. https://subdomain.cloudfunctions.net/cloud-function/v1/ is the general form of the cloud function endpoint I am calling as a part of a web api.
Is this a valid and reasonable way to get the equivalent of gcloud auth print-identity-token? If so, why the epic failure?
I need to use a google service account for service to service authentication. Development environment is visual studio 2019, .net core 3.1, docker/linux
PS - the service account has the cloud function's Cloud Functions Invoker role.
PPS - the issue seems to be related to docker and a set of error messages I get when starting my project in docker. I had ignored them as they were not until now impairing functionality.
at System.Net.Http.CurlHandler.ThrowIfCURLEError(CURLcode error)
at System.Net.Http.CurlHandler.MultiAgent.FinishRequest(StrongToWeakReference`1 easyWrapper, CURLcode messageResult)
running the code on windows works.
The penultimate problem is that I needed to make an upstream method asynchronous and add an await. Now the code above works every time. This change led me to the ultimate problem whose solution is some code refactoring in ConfigureServices() related to AddHttpClient() setup.
The curl exception was due to trying to add logger.loggerFactory.AddGoogle(…) with a bad configuration. this has been a bad hair day.
This question is also an example of what not to do - ie I used too much minimalism to describe the problem.

Is it possible to use gRPC Google APIs from Rust today?

There is a prehistoric example where protobuf crate is used with reqwest HTTP client to call one of the few whitelisted services that can used with permanent API keys instead of OAuth / service accounts. This doesn't work with most of the googleapis zoo.
Furthermore, using OAuth with gRPC doesn't seem as simple as attaching a Authorization: BearerSIGNED_JWT to the request. As seen in all the Authenticate with Google examples on grpc.io, this requires calling the grpc_composite_channel_credentials_create function in the C core library.
It looks like pingcap/grpc-rs doesn't wrap or use this function. However, it does mention Google OAuth suddenly.
What is the truth?
Still not sure what exactly the authorization constitutes on the wire, but
google_default_credentials successfully allows me to call Google APIs.
In fact, it not only works with GOOGLE_APPLICATION_CREDENTIALS env var pointing to the service account key .json but even magically uses my signed in google account from gcloud cli.
For example with pingcap/grpc-rs aka grpcio = "0.5.0-alpha.3" all it took was
let env = Arc::from(EnvBuilder::new().build());
let creds = ChannelCredentials::google_default_credentials().unwrap();
let ch = ChannelBuilder::new(env).secure_connect("firestore.googleapis.com", creds);
let client = FirestoreClient::new(ch);

Golang and gcloud API: how to get an auth token

Because Google AutoML does not have a golang client, I have to use the AutoML http client. To do so, requires an auth token from google which comes from running the following cli command:
gcloud auth application-default print-access-token
I am currently authing my Golang server with a credentials json file that has access to AutoML as well (example usage)
storageClient, err := storage.NewClient(ctx, option.WithCredentialsFile(gcloudCredsJSONPath))
My question is: how would I get an auth token from the Golang Google client if I have a JSON credentials file? Is this even possible?
Thank you for any help!
You can only use API tokens with certain Google Cloud APIs. Using tokens is discourage by Google Cloud as you can read in this article:
https://cloud.google.com/docs/authentication/
If your production environment is also Google Cloud, you might not need to use any JSON file at all. Google Cloud has the concept of "DefaultCredentials" that it injects in your services via the environment. You might be able to simplify your code to:
storageClient, err := storage.NewClient(ctx)
It's also recommended to use a "ServiceAccount" so the credentials that your application use can be scopes to it. You can read more here:
https://cloud.google.com/docs/authentication/getting-started

Server to server OAuth2

I'm trying to implement a Golang application for accessing Google Analytics data. but all the examples uses tokens that dies in one hour.
In the api access i found a "Certificate access" that are designed to be used to access from servers, but i failed to find examples of its implementation in Golang. there is some reading or may you can enlighten my path for this?
I'm using this library.
code.google.com/p/google-api-go-client/
reading some post here I found this Service Applications and Google Analytics API V3: Server-to-server OAuth2 authentication?
but it seems that it will not work directly. is really no way of doing this w/o hacking it around?
have you checked out the OAuth2 package? I've used it for user-authorised calls, and hacked it around a bit to allow it to handle multiple authorisation sources.I haven't tested it with pure server-to-server comms, but you should be able to hack the transport code to get it to do what it needs...
this might be a little late but I havent found a good example to get people started.
Before you start make sure you
install golang 1.5
install google cloud SDK (cloud.google.com/sdk - this will allow for local development)
Create a service account in your google appengine / cloud console and download the json (API's and auth > Credentials )
Once above is setup:
set a path for your security credentials that you downloaded earlier
export GOOGLE_APPLICATION_CREDENTIALS=~/DIRECTORY/CREDENTIALS.json
now you can authenticate with go.
package main
import (
"fmt"
"golang.org/x/net/context"
"golang.org/x/oauth2/google"
analytics "google.golang.org/api/analytics/v3"
)
var (
scope = analytics.AnalyticsReadonlyScope
)
func main() {
// Authentication is provided by the gcloud tool when running locally, and
// by the associated service account when running on Compute Engine.
client, err := google.DefaultClient(context.Background(), scope)
if err != nil {
fmt.Printf("Unable to get default client: %v", err)
}
service, err := analytics.New(client)
if err != nil {
fmt.Printf("Unable to create storage service: %v", err)
}
fmt.Println(service)
}

Resources