I'm getting 500 error when testing the ChromeWebStore API - google-chrome-extension

I'm getting a 500 error when testing the User License API
Manifest
"oauth2": {
"client_id": "clientidobv",
"scopes": [
"https://www.googleapis.com/auth/chromewebstore.readonly"
]
},
"key": "*****keyobvhere",
"permissions": [
"identity",
"https://www.googleapis.com/"
After grabbing the token with a userflow, I run:
var req = new XMLHttpRequest();
req.open('GET', 'https://www.googleapis.com/chromewebstore/v1.1/userlicenses/' + chrome.runtime.id);
req.setRequestHeader('Authorization', 'Bearer ' + token);
console.log(req.responseText)
req.send()
I get Failed to load resource: the server responded with a status of 500 ()
Chrome Runtime ID is the same as the one in the API console
The token was checked & is valid
I'm testing locally but with a user who has an active licence in production
Any ideas?

Related

Redirect URI from this request does not match one from the authorize request even though they're the same

So I am using ORY/Hydra to host an OAuth 2.0 Server and am in the process of building a sample client to demonstrate the flow. I call the /oauth2/auth endpoint with the redirect_uri in the query params, and I use simple-oauth2 to later call /oauth2/token to fetch the access tokens.
I can create a client through my API into the Hydra server and the response is a valid JSON with the one of the callback URL's being `http://localhost:3000/callback'
{
"id": "cbf09258-7f8e-4147-93c1-aa7e2e7b99b3",
"name": "Test App 1",
"clientId": "515e7876-881e-4f3a-b489-20ed7300c745",
"clientSecret": "deleted",
"clientSecretExpiresAt": 0,
"token":
"$2a$08$bWZMUf5wgEpOcoUjsJ5l/uS5LaTmqrC40FTnfegzelE69H8JAFrMW",
"callbackUrl": [
"127.0.0.1:3000",
"localhost:3000/callback",
"http://localhost:3000/callback"
],
"url": "",
"imageBanner": "",
"imageIcon": "",
"createdAt": "2019-02-04T19:14:22.193152Z",
"updatedAt": "2019-02-04T19:14:22.193152Z"
}
The flow starts at localhost:3000/callback as well and my jade file renders a link to call /oauth2/auth as follows
block content
h1 Whew
a(href="http://localhost:4444/oauth2/auth?client_id=" + clientid + "&scope=openid offline&response_type=code&redirect_uri=http://localhost:3000/callback&state=haardik123") Authorize
Finally, the handler includes code to call /oauth2/token if a code param is present in the query as follows: (callback.js)
const oauth2 = simpleOauthModule.create({
client: {
id: process.env.CLIENT_ID,
secret: process.env.CLIENT_SECRET,
},
auth: {
tokenHost: 'http://localhost:4444',
tokenPath: '/oauth2/token',
authorizePath: '/oauth2/auth',
},
});
// Authorization uri definition
const authorizationUri = oauth2.authorizationCode.authorizeURL({
redirect_uri: 'http://localhost:3000/callback',
scope: 'openid offline',
state: 'haardik123',
});
router.get('/', async function (req, res, next) {
var query = url.parse(req.url, true).query;
var clientid = process.env.CLIENT_ID;
var code = query.code;
const options = {
code,
};
if (code) {
try {
const result = await oauth2.authorizationCode.getToken(options);
console.log('The resulting token: ', result);
const token = oauth2.accessToken.create(result);
return res.status(200).json(token)
} catch(error) {
console.error('Access Token Error', error.message);
return res.status(500).json('Authentication failed');
}
}
res.render('callback', {
clientid: clientid
});
});
The flow goes normally until I get redirected back to localhost:3000/callback with a code in the query params but then it says Status 400: Bad request - Authentication Failed
Hydra logs show that
time="2019-02-04T19:16:05Z" level=info msg="started handling request" method=POST remote="172.29.0.1:35130" request=/oauth2/token
time="2019-02-04T19:16:05Z" level=error msg="An error occurred" description="The request is missing a required parameter, includes an invalid parameter value, includes a parameter more than once, or is otherwise malformed" error=invalid_request hint="The \"redirect_uri\" from this request does not match the one from the authorize request."
time="2019-02-04T19:16:05Z" level=info msg="completed handling request" measure#http://localhost:4444.latency=60183900 method=POST remote="172.29.0.1:35130" request=/oauth2/token status=400 text_status="Bad Request" took=60.1839ms
I'm not sure why the redirect_uri won't match as it seems like I did everything fine -- would love any insight on this, thanks!
This was solved by adding a redirect_uri to the options object being passed to oauth2.authorizationCode.getToken(options)
Changing the object to
const options = {
code,
redirect_uri: "http://localhost:3000/callback",
};
worked!

not able to get user info

bellow is my node js script to get google user details using accessToken
var accessToken = req.body.accessToken;
console.log(accessToken)
var google = require('googleapis');
//google api
var plus = google.plus('v1');
var OAuth2 = google.auth.OAuth2;
var oauth2Client = new OAuth2(
config.google.clientID,
config.google.clientSecret,
config.google.redirect_uri
);
oauth2Client.setCredentials({access_token: accessToken});
plus.people.get({
userId: 'me',
auth: oauth2Client
}, function (err, response) {
// handle err and response
if (err) {
reject(err)
} else {
console.log(response);
resolve(response)
}
});
need to get google login user details using accessToken. what is wrong in code?
The most likely cause is the user in question has not created a google+ profile. Here are a few more options.
I am not sure what information you are trying to get but the best way to get user info is to authecate a user using the profile scope then request the data directly of the user info endpoint
Request
GET /userinfo/v2/me HTTP/1.1
Host: www.googleapis.com
Content-length: 0
Authorization: Bearer uzG4XqnvucBFk3jylgxnbtNhoOt2wCc3QvUcjk7PZhJ5m6G7ibtlBwbAQntJjJtLsxZfoDjhbASpzLmcFnlZ9o4qoMd2fCV2eRb4O5XrKRAXC
Response
{
"family_name": "Lawton",
"name": "Linda Lawton",
"picture": "https://lh5.googleusercontent.com/-a1CWlFnA5xE/AAAAAAAAAAI/AAAAAAAAl1I/UcwPajZOuN4/photo.jpg",
"locale": "en",
"gender": "female",
"link": "https://plus.google.com/+LindaLawton",
"given_name": "Linda",
"id": "117200475532672775346"
}
You can also go though the google people api using the same profile scope
GET /v1/people/me HTTP/1.1
Host: people.googleapis.com
Content-length: 0
Authorization: Bearer NuzG4XqnvucBFk3jylgxnbtNhoOt2wCc3QvUcjk7PZhJ5m6G7ibtlBwbAQntJjJtLsxZfoDjhbASpzLmcFnlZ9o4qoMd2fCV2eRb4O5XrKRAXC
But this endpoint reads from Google+ so if the user has not filled anything out on their Google+ profile you wont see much data here.
You can use request module to get the user detail on your node server.
But Before requesting the user data, make sure you have authorized the API by giving it the desired scope. In your case, you need to give https://www.googleapis.com/auth/userinfo.profile in the scope.
When you receive your accessToken, use that token to call this google api
https://www.googleapis.com/oauth2/v1/userinfo
const request = require('request');
// use any api you want to call.
request({
url: 'https://www.googleapis.com/oauth2/v1/userinfo',
method: 'GET',
headers: {
'Authorization': `Bearer ${YourAccessToken}`,
'Accept': 'application/json'
}
}, function(err, response, _user) {
console.log('User Data', _user);
})
I hope this will solve your problem. If still there is some problem, you can test your Google APIs on OAuth 2.0 Playground

Access Google Container builder logs with a service account - 403 Forbidden Error

I have a service account that triggers builds on Google Container Builder. This works fine but now I would like to retrieve build logs using that service account.
Here is the code that fetches the log (the token is obtained using google-auto-auth package and this part works well in other places, so I really don't think this is the issue):
var url = logsBucket + '/log-' + buildId + '.txt';
debug('Requesting log at %s', url);
request
.get(url)
.set('Authorization', 'Bearer ' + token)
.end(function(err, res) {
if (err) return cb(err);
var log = res.body;
debug('Received build log : %o', log);
cb(null, log);
});
Currently, this fails with 401 Unauthorized although the service account has access to the following roles:
Admin kubernetes engine
Admin storage
Admin objects in storage
Cloud container builder
Reader Cloud container builder
Reader storage objects
This is the error:
{
"message": "Forbidden",
"stack": "Error: Forbidden\n at Request.callback (/app/node_modules/superagent/lib/node/index.js:696:15)\n [...]",
"status": 403,
"response": {
"req": {
"method": "GET",
"url": "https://storage.googleapis.com/{PROJECT_ID}.cloudbuild-logs.googleusercontent.com/log-42602b35-af02-4e75-8100-8a3bd0e720fb.txt",
"headers": {
"user-agent": "node-superagent/3.8.2",
"authorization": "Bearer {BEARER_TOKEN}"
}
},
"header": {
"x-guploader-uploadid": "{SOME-UPLOAD-ID}",
"content-type": "application/xml; charset=UTF-8",
"content-length": "337",
"date": "Wed, 10 Jan 2018 11:06:54 GMT",
"expires": "Wed, 10 Jan 2018 11:06:54 GMT",
"cache-control": "private, max-age=0",
"server": "UploadServer",
"alt-svc": "...",
"connection": "close"
},
"status": 403
}
}
Any idea why the request fails with 403 ? Could it come from a missing scope ? I only set scopes: 'https://www.googleapis.com/auth/cloud-platform' so far.
GCS permissions predate IAM and thus work a little differently.
To view the build logs, the Service Account in question needs to be a Viewer on the project in addition to have the Builder Editor role.
role/viewer includes role role/cloudbuild.builds.viewer
role/cloudbuild.builds.editor
As a last step you may want to: (Not necessary)
Disable the Container Builder API and re-enable it. Doing so should give your service account access to your project again.
Please also look at: docs

$http request in ionic app to a simple node server throws "statusText": "" error

I've stripped down an $http request to the bones and it's still failing without a helpful error message. Within my Angular factory I have:
var url = "http://localhost:3000";
var deferred = $q.defer();
$http.get(url)
.then(function (success) {
deferred.resolve(success)
})
.catch(function (err) {
deferred.reject(err)
})
return deferred.promise;
Inside my node routes I have:
router.get('/', function(req, res, next) {
res.json({test: 'hi from node index.js'})
});
The full error I'm receiving within my ionic app is:
{
"data": null,
"status": -1,
"config": {
"method": "GET",
"transformRequest": [
null
],
"transformResponse": [
null
],
"url": "http://localhost:3000",
"headers": {
"Accept": "application/json, text/plain, */*"
}
},
"statusText": ""
I've tried to catch the error inside my node server and I receive
TypeError: Cannot read property 'type' of undefined
I've disabled cors within my node app.js. I've tried to make a connection with sockets, but still haven't had any luck. I'm running my ionic app with ionic run.
Any help would be appreciated. Thanks.
Solution: naturally the device has it's own localhost, so when I'm sending an $http.get request from my ionic app, it's not sending it to the same localhost my node server is running on. The solution is to target your deployed server or your local machine.

Is it possible to get an Id token with Chrome App Indentity Api?

I can't get a user's id_token (https://developers.google.com/accounts/docs/CrossClientAuth) from the Chrome identity api (https://developer.chrome.com/apps/identity).
I can get an access_token using the chrome identity sample when the oauth section in the manifest is:
"oauth2": {
"client_id": "<chrome-app-client-id>.apps.googleusercontent.com",
"scopes": ["https://www.googleapis.com/auth/plus.login"]
}
But when I try to get the id_token the same way I get it on my android client a get the error:
"OAuth2 request failed: Service responded with error: 'invalid scope: {0}'"}
The manifest section is now:
"oauth2": {
"client_id": "<chrome-app-client-id>.apps.googleusercontent.com",
"scopes": ["audience:server:client_id:<app-engine-client-id>.apps.googleusercontent.com"]
}
On Android I get the id_token by passing the same scope string to android.gms.auth.GoogleAuthUtil.getToken(), but I can't get it to work with the chrome identity api.
Is it possible to get an id_token with Chrome App Indentity Api? If not, how can I get an id_token for my Chrome app?
Thanks for your help!
I've came to the same problem yesterday and since I've found a solution, I might as well share it, as it wasn't that obvious. As far as i know Google does not provide a direct and documented way to do this, but you can use the chrome.identity.launchWebAuthFlow() function.
First you should create an Web application credentials in google console and add the following url as a valid Authorized redirect URI: https://<EXTENSION_OR_APP_ID>.chromiumapp.org. The URI does not have to exist, chrome will just catch the redirect to this URL and call your callback function later.
manifest.json:
{
"manifest_version": 2,
"name": "name",
"description": "description",
"version": "0.0.0.1",
"background": {
"scripts": ["background.js"]
},
"permissions": [
"identity"
],
"oauth2": {
"client_id": "<CLIENT_ID>.apps.googleusercontent.com",
"scopes": [
"openid", "email", "profile"
]
}
}
background.js:
// Using chrome.identity
var manifest = chrome.runtime.getManifest();
var clientId = encodeURIComponent(manifest.oauth2.client_id);
var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
var redirectUri = encodeURIComponent('https://' + chrome.runtime.id + '.chromiumapp.org');
var url = 'https://accounts.google.com/o/oauth2/auth' +
'?client_id=' + clientId +
'&response_type=id_token' +
'&access_type=offline' +
'&redirect_uri=' + redirectUri +
'&scope=' + scopes;
chrome.identity.launchWebAuthFlow(
{
'url': url,
'interactive':true
},
function(redirectedTo) {
if (chrome.runtime.lastError) {
// Example: Authorization page could not be loaded.
console.log(chrome.runtime.lastError.message);
}
else {
var response = redirectedTo.split('#', 2)[1];
// Example: id_token=<YOUR_BELOVED_ID_TOKEN>&authuser=0&hd=<SOME.DOMAIN.PL>&session_state=<SESSION_SATE>&prompt=<PROMPT>
console.log(response);
}
}
);
Google OAuth2 API (for OpenID Connect) documentation can be found here: https://developers.google.com/identity/protocols/OpenIDConnect#authenticationuriparameters
PS: If you don't need the oauth2 section in your manifest. You can safely omit it, and provide the identifiers and scopes in code only.
EDIT:
For those interested, you don't need the identity API. You can even access the token using a little trick with tabs API. The code is a little longer, but you have better error messages and control. Keep in mind that in the following example, you need to create Chrome App credentials.
manifest.json:
{
"manifest_version": 2,
"name": "name",
"description": "description",
"version": "0.0.0.1",
"background": {
"scripts": ["background.js"]
},
"permissions": [
"tabs"
],
"oauth2": {
"client_id": "<CLIENT_ID>.apps.googleusercontent.com",
"scopes": [
"openid", "email", "profile"
]
}
}
background.js:
// Using chrome.tabs
var manifest = chrome.runtime.getManifest();
var clientId = encodeURIComponent(manifest.oauth2.client_id);
var scopes = encodeURIComponent(manifest.oauth2.scopes.join(' '));
var redirectUri = encodeURIComponent('urn:ietf:wg:oauth:2.0:oob:auto');
var url = 'https://accounts.google.com/o/oauth2/auth' +
'?client_id=' + clientId +
'&response_type=id_token' +
'&access_type=offline' +
'&redirect_uri=' + redirectUri +
'&scope=' + scopes;
var RESULT_PREFIX = ['Success', 'Denied', 'Error'];
chrome.tabs.create({'url': 'about:blank'}, function(authenticationTab) {
chrome.tabs.onUpdated.addListener(function googleAuthorizationHook(tabId, changeInfo, tab) {
if (tabId === authenticationTab.id) {
var titleParts = tab.title.split(' ', 2);
var result = titleParts[0];
if (titleParts.length == 2 && RESULT_PREFIX.indexOf(result) >= 0) {
chrome.tabs.onUpdated.removeListener(googleAuthorizationHook);
chrome.tabs.remove(tabId);
var response = titleParts[1];
switch (result) {
case 'Success':
// Example: id_token=<YOUR_BELOVED_ID_TOKEN>&authuser=0&hd=<SOME.DOMAIN.PL>&session_state=<SESSION_SATE>&prompt=<PROMPT>
console.log(response);
break;
case 'Denied':
// Example: error_subtype=access_denied&error=immediate_failed
console.log(response);
break;
case 'Error':
// Example: 400 (OAuth2 Error)!!1
console.log(response);
break;
}
}
}
});
chrome.tabs.update(authenticationTab.id, {'url': url});
});
First, I assume that in your manifest.json snippet you don't mean that your client_id is literally "<chrome-app-client-id>.apps.googleusercontent.com. It should be something like 9414861317621.apps.googleusercontent.com -- something you got from the Developer Console, or whatever Google site you used to register the app.
Assuming the above is OK, and you have the client_id right, and the scope right, you get what's called an "OAuth2 access token" with a call to chrome.identity.getAuthToken. As you don't show us any JavaScript code, I can't tell if this is what you're doing. The access token you get you need to save for subsequent use when you call an API function. For example:
var access_token;
chrome.identity.getAuthToken(
{
'interactive': true
},
function(token) {
access_token = token;
// do something if you like to indicate
// that the app is authorized
}
);
Then, when you make an API call, you supply that access token, like this:
var url = 'https://www.googleapis.com/' + method;
Ajax.ajaxSend(url, "json",
function (status, response) {
if (response && response.error && response.error.message)
errorCallback(response.error.message);
else if (status == 200)
successCallback(response);
else
errorCallback('Result code: ' + status);
},
function (e) {
if (errorCallback)
errorCallback('Communication error');
},
{
Authorization: 'Bearer ' + access_token
}
);
Ajax.ajaxSend is my own function:
var Ajax = (function () {
var api = {
ajaxSend: function (url, responseType, successCallback, errorCallback, headers) {
var req = new XMLHttpRequest();
req.onload = function (e) {
successCallback(req.status, req.response);
};
req.onerror = errorCallback;
req.responseType = responseType ? responseType : "text";
req.open("get", url);
if (headers)
for (var v in headers)
req.setRequestHeader(v, headers[v]);
req.send();
}
};
return api;
})();
The other undefined functions also are what you'd expect. The third argument to Ajax.ajaxSend is a header to be sent along. (Sorry, I don't have time to develop standalone code just for this answer.)
I hope the above is useful.
I guess it depends on why one would want token id, but in my case
access_token was enough to authorize user - by pulling user info from https://www.googleapis.com/oauth2/v2/userinfo?alt=json ( with Authorization header = access_token).

Resources