Google Analytics API access with a service account - javascript

Can I access Google Analytics data using a service account in a client-side application? If not, are there other ways of achieving the same outcome?
Must be entirely client-side, and must not require users to authenticate (hence the desire to use a service account).

Yes you can in https://code.google.com/apis/console make sure you say that its a Service account it will give you a key file to download. With that you dont need a user to click ok to give you access.
For a service acccount to work you need to have a key file. Anyone that has access to that key file will then be able to access your Analytics data. Javascript is client sided which means you will need to send the key file. See the Problem? You are handing everyone access to your account. Even if you could get a service account to work using javascript for security reasons its probably not a very good idea.

You can use the official (and alpha) Google API for Node.js to generate the token. It's helpful if you have a service account.
On the server:
npm install -S googleapis
ES6:
import google from 'googleapis'
import googleServiceAccountKey from '/path/to/private/google-service-account-private-key.json' // see docs on how to generate a service account
const googleJWTClient = new google.auth.JWT(
googleServiceAccountKey.client_email,
null,
googleServiceAccountKey.private_key,
['https://www.googleapis.com/auth/analytics.readonly'], // You may need to specify scopes other than analytics
null,
)
googleJWTClient.authorize((error, access_token) => {
if (error) {
return console.error("Couldn't get access token", e)
}
// ... access_token ready to use to fetch data and return to client
// even serve access_token back to client for use in `gapi.analytics.auth.authorize`
})
If you went the "pass the access_token back to client" route:
gapi.analytics.auth.authorize({
'serverAuth': {
access_token // received from server, through Ajax request
}
})

Related

Using Google Sheet's v4 JSON Endpoint with my API but still getting "Unauthorized" message

I am trying to get a simple JSON package from putting the URL of my Google spreadsheet so I can use it on my webpage; I am using my Google Cloud Console API as it is said on the documentation of the v4 Google API format, but I still get the error of "Unauthorized API"
Documentation: https://developers.google.com/sheets/api/guides/migration#v4-api
I am using this URL:
https://sheets.googleapis.com/v4/spreadsheets/SHEET_ID/values/Sheet1?key=API_KEY
My google sheet is set as published on the web. And also I am the creator of the google sheet.
What could I be missing? I am new to API's!
First Edit:
Answering the comment of ABDULLOKH MUKHAMMADJONOV
Here is the code I am using to make a GET request to the google sheet, you can see the Sheet ID is there, and also the API of the google cloud platform.
fetch("https://sheets.googleapis.com/v4/spreadsheets/1S652uS2FLVoZ1m3apb6R4H783v6GkV58HbQ6Idec5aY/values/Sheet1?key=AIzaSyCpFZ7mcqMNc6Q_bP6h1kCEfAi6c_fd8AM", {"method": "get"})
.then( (httpResponse) => {
if (httpResponse.ok) {
console.log(httpResponse.json());
return httpResponse.json();
} else {
return Promise.reject("Fetch did not succeed");
}
} )
.then(json => console.log(json.someKey))
.catch(err => console.log(err));
This code is from the Wix code editor.
The caller doesnt not have permissions
Means that the user you are authenticated as does not have permission to do what it is you are trying to do.
The method
https://sheets.googleapis.com/v4/spreadsheets/SHEET_ID/values/Sheet1?key=API_KEY
I believe is this method spreadsheets.values/get if you check the documentation you will notice that it requires authorization with one of these scopes
You appear to only be sending an api key. You need to be authorized to access that sheet. You cant access it with an API key that only grants access to public data.
Ok, so I investigated about the OAuth 2.0 authentication and authorization for using Google Sheet's REST API. I added one of the needed scopes.
But I am stuck at the point on how to do the authorization process...
I am looking at this google documentation - How to use Google OAuth 2.0 authorization
But I haven't been able to get to the answer I seek. I am stuck at the part where it says "When your application needs access to user data, it asks Google for a particular scope of access." I do now know how to code this request or to do this request through the Insomnia software.
I am trying to do the GET request with a wix testing website, and also with Insomnia, but I haven't been able to achieve it.
These are the images from Insomnia, which tell me "Invalid authorization URL"
Insomnia's OAuth 2.0 authentication parameters
Insomnia's API Query parameter

Best way to check if Twilio authentication is successful with JS SDK

What is the best way to check if Twilio auht_token, account_sid are correct and sms can be sent, number checked? Some call which doesn't cost extra credits?
E.g. I see https://www.twilio.com/docs/api/rest/usage-records on RESTfull documentation but can't find how to get the same thing with JS SDK. Can't see dedicated endpoint for config checking so looking for anything else.
Environment: NodeJS 8.9
Twilio developer evangelist here.
Most API calls to the Twilio REST API don't cost, particularly those where you retrieve a resource or list resources. Since you mentioned SMS you could, for example, list your latest messages like this:
const client = require('twilio')(accountSid, authToken);
client.messages.list({ limit: 10 })
.then(function(messages) {
console.log("Everything is good!");
})
.catch(function(err) {
console.error("Something went wrong: ", err)
})
Take a look through the API reference and pick one that takes your fancy.
Using JS SDK might be insecure here. Because of that I think they didn't include a method in the JS API which may present the user the account_sid and the auth_token, which may be exploited. I assume you can use a server bridge between your client JS and Twilio API. Like this:
Client makes a JS AJAX request to http://my.domain.tld/checkstatus
Server connects to the Twilio API with C#, PHP, NodeJS or whatever tech it uses
Twilio returns that the credentials and tokens are still valid or expired
Server prepares the client response as true/false or 0/1
Client reads the status and continues or redirects somewhere else.
Edit There's a GET method here which you can also use with JS AJAX call:
https://www.twilio.com/docs/api/rest/usage-records#list-get
which is requested by this format:
/2010-04-01/Accounts/{AccountSid}/Usage/Records/{Subresource}

Making server to server request to Google Calendar API

I am building a SPA using vue.js which has a PHP backend server (slim framework 3). These are two separate projects, leave on two different servers and the backend has no front end at all.
SPA (vue.js) makes requests to backend via ajax.
Now I want to implement Google Calendar API to create a calendar and events every time user creates a todo item. To do that I need server to server access to Google Calendar API (I might need to make changes to the event on GCAL even if user is not logged in).
What I am trying to understand, how can I get the access token (and refresh token) using Google JS library using vue.js and save this in the db so that my backend can use it to make offline requests to GCAL Api.
When I use the Oauth v.2 using the JS library, all I get is the access_token which cannot be using for server to server communications.
[UPDATE]
Ok, a little bit more information. I am following the guides from Google and my front end looks like this at the moment
jsbin
So I can successfully authorise user and access their calendar using the javascript sdk. But the token Javascript SDK returns is something like this
{
_aa: "1"
access_token: "xxxxxxx"
client_id: "yyyyyyyyyy"
cookie_policy: undefined
expires_at: "1456400189"
expires_in: "3600"
g_user_cookie_policy: undefined
issued_at: "1456396589"
response_type: "token"
scope: "https://www.googleapis.com/auth/calendar"
state: ""
status: Object
google_logged_in: false
method: "AUTO"
signed_in: true
token_type: "Bearer"
}
I send this token to my backend server and try to make a request to GCAL api as follows
$token = $request->getParam('token');
$client = new Google_Client();
$client->setApplicationName('Web');
$client->setScopes([Google_Service_Calendar::CALENDAR]);
$client->setAuthConfigFile(ROOT_DIR . '/client_secret.json');
$client->setAccessType('offline');
$client->setAccessToken(json_encode($token));
$service = new Google_Service_Calendar($client);
$calendarId = 'primary';
$optParams = array(
'maxResults' => 10,
'orderBy' => 'startTime',
'singleEvents' => TRUE,
'timeMin' => date('c'),
);
$results = $service->events->listEvents($calendarId, $optParams);
And it returns error saying the token is expired. I checked the Google Code and found out the reason it returns this error is because of these lines
public function isAccessTokenExpired()
{
if (!$this->token || !isset($this->token['created'])) {
return true;
}
// If the token is set to expire in the next 30 seconds.
$expired = ($this->token['created']
+ ($this->token['expires_in'] - 30)) < time();
return $expired;
}
As you can see the token that comes from the front end doesn't have created field as well as no refresh_token field.
Thanks for updating the question! I am thinking the issue is that using the client-side flow does not allow you to get a refresh token. From the docs:
OAuth 2.0 client-side flow (AKA Implicit flow) is used to obtain
access tokens (it does not support the issuance of refresh tokens) and
is optimized for public clients known to operate a particular
redirection URI. These clients are typically implemented in a browser
using a scripting language such as JavaScript.
The authorization server MUST NOT issue a refresh token.
see for more: How to get refresh token while using Google API JS Client
You'd need to use the server-auth flow to get a token you can refresh and use long-term. Here's a quickstart guide for PHP.
One other thing to consider is that you will only receive a refresh_token the first time someone authorizes your app. After that, auth attempts will only return an access token. So if you lose the refresh token, you will need to either disable the authorization from your google account, or use the "force re-auth" option in the API.

IdentityServer3 and JWT ValidateIssuerSigningKey

I'm accessing a standard IdentityServer3 host app (ASP.NET WebApi 2).
I'm using the JavaScript way to get a token from IdSvr link
I then take that JWT add it to the authorisation request header and will attempt to process that in my app.
I use the: app.UseJwtBearerAuthentication middleware to validate this token. Firstly is this correct?
I have tried:
app.UseIdentityServerBearerTokenAuthentication(
new IdentityServerBearerTokenAuthenticationOptions
{
RequiredScopes = new[] { "myscope" },
IssuerName = "My Issuer"
});
But I get an error, "can't read token because it's not a valid base64 format".
With UseJwt... I get an error in our UAT environment about can't validate issuer signing key because I'm trying to use dev test one (which means I need the UAT cert). However, our other apps use app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()) and don't seem to have to worry about this issuer signing key....
Am I missing something in the way I'm trying to read and validate this token or shall I continue down my path with creating a X509SecurityKey() using the public key?
All our apps work with HTTPS so everything is communicated using TLS.
The recommended way is to set the Authority property to point to the identity server base URL. This way the certificate (amongst other things) is downloaded from the discovery document, and the middleware can configure itself automatically.

Get an access token without being connected to facebook

I need to retrieve a facebook page's list of posts (feed) using their javascript SDK, just like they explain in their docs: https://developers.facebook.com/docs/graph-api/reference/v2.4/page/feed
/* make the API call */
FB.api(
"/{page-id}/posts",
function (response) {
if (response && !response.error) {
/* handle the result */
}
}
);
I need it to be my website's "news section", so users should see it even if they are not connected to facebook.
The problem
Cool, but there is a problem... It returns: An access token is required to request this resource.
Holy cow... I'd like to get some access token for you #facebook, but my app doesn't make use of your authentication tools/plugins.
ANYWAY, I tried with FB.getLoginStatus(); but doesn't work, because the only way it can return an access_token is if the user is actually connected to the application. My users may not even be logged to facebook!
So, ¿How can I get an access_token to be stored into a variable, and later be used to get /{my-page}/posts?
I've already payed a look to this SO question, but it doesn't solves my problem, simply because there are no such "generic tokens".
I've also read https://developers.facebook.com/docs/facebook-login/access-tokens/ and that also relies on tokens generated through facebook login methods... So, can't I display a list of fb page's posts in my website, without being connected into facebook, hence an application?
ADD: My app is build with angularJS, I'm not dealing with server-side code. I shall rely purely on javascript methods.
You could either use an page or an app access token, but as you'd be using them on the client-side, neither of them are an option.
See
https://developers.facebook.com/docs/facebook-login/access-tokens#apptokens
https://developers.facebook.com/docs/facebook-login/access-tokens#pagetokens
Note that because this request uses your app secret, it must never be made in client-side code or in an app binary that could be decompiled. It is important that your app secret is never shared with anyone. Therefore, this API call should only be made using server-side code.
I'd strongly recommend to build a simple server-side script (PHP for example) to proxy the request to the Graph API. You could then call this via AJAX for example and load the posts asynchronously (and alse get rid of the FB JS SDK!). There is NO way to handle this in a secure manner if you don't want to use FB Login for all of your users (which also doesn't make much sense IMHO).
I think it's straightforward :)
Since pages' posts are always public, it only needs a valid access token to retrieve page posts.
Quoting what you've written:
So, ¿How can I get an access_token to be stored into a variable, and later be used to get /{my-page}/posts?
You only require an access token.
My suggestion would be;
- Generate an access token for yourself (no extra permission needed)
- request page-id/posts
This way you don't require other users to be connected to facebook, you can simply requests page-id/posts to retrieve posts with access token you generated for yourself.
I hope it solves your problem :D
TIP: As long as posts are public, you only require a valid access token, it doesn't need to be user or page specific.

Categories