I'm having issues using the credential manager through chrome extension - google-chrome-extension

I am trying to integrate the credential manager API into my extension so I can save the API credentials using it but am having issues.
Just for testing purposes, I just tried saving the credentials from the popup (Where the user login happens) and when I tried that I got an error saying "NotSupportedError: The user agent does not support public key credentials." I did some googling but didn't find what I was looking for. I thought it might have something to do with the popup so I tried doing the same through the background script but it can't access the window object so that didn't work.
I haven't yet tried doing this though a content script which I would imagine would work but ideally I'd prefer to just store it when the user logs in and then just call it as I need it.
Here is the basic code I'm using for testing that I grabbed from the MDN site;
if ("PasswordCredential" in window) {
let cmAPICredential = new PasswordCredential({
id: "extension",
name: uname,
password: pwd
});
navigator.credentials.store(cmAPICredential).then(() => {
if (isDebugMode) {
chrome.runtime.sendMessage({ message: "debug_log", str: `**LOGIN DEBUGGING** | Credentials stored in the user agent's credential manager.`, cpage: "main.js" }, function(response) {});
}
}, (err) => {
if (isDebugMode) {
chrome.runtime.sendMessage({ message: "debug_log", str: `**LOGIN DEBUGGING** | Error while storing the credential: ${err}`, cpage: "main.js" }, function(response) {});
}
});
} else {
if (isDebugMode) {
chrome.runtime.sendMessage({ message: "debug_log", str: `**LOGIN DEBUGGING** | Password credential isn't supported in this browser`, cpage: "main.js" }, function(response) {});
}
}
Is there any way that I can do what I am attempting? The only thing I really want to secure is the password and this seems to be the only good way to do it through a chrome extension.

Based on #wOxxOm response and some other research, it looks like I can't use the credential management API with chrome extensions.
So the answer to my question is you can't.

Related

Getting "state not found" during msal loginRedirect method

I am attempting to implement msal 2 in my React application. I'm using the msal-react-samples/default as the template for my work. I am able to see me login page and login using the loginRedirect method. But upon returning to my application I'm getting the following error. I saw that someone asked a very similar question (65375241). But it looks like the user abandoned it. I have included additional information below.
errorCode: "state_not_found"
errorMessage: "State not found: Cached State"
Additional Information
Authenticating into ADB2C
MsalConfig:
{ auth: { clientId: "REDACTED" authority: "REDACTED" knownAuthorities:["Redacted, Same as authority"], redirectUri: "http://localhost:3000/AuthTest", navigateToLoginRequestUrl: false }, cache: { cacheLocation: "sessionStorage", storeAuthStateInCookie: false, }, system: { loggerOptions: { ...(logger options from sample) } }
Authentication worked previously with MSAL1.
I'm aware that as of 1/7/2021 the msal-react package is not meant for production environments. I could attempt to change to just use just the msal-browser package if that would help.
I was able to figure out my own error by looking at the the MSAL git repo issue
#azure/msal-browser redirect not working correctly
I will describe my issue here to assist anyone else that has this same error.
It was caused because I had used the addEventCallback method improperly.
I had it implemented in my code as a simple function call. But it needs needs to be put into a useEffect and also issue the removeEventCallback method after consuming it.
I had
instance.addEventCallback((message) => {
console.log(message)
})
rather than
useEffect(() => {
const callbackId = instance.addEventCallback((message) => {
console.log(message)
})
return () => {
if (callbackId) {
instance.removeEventCallback(callbackId);
}
}
}, [instance])

Retrieve Gmail access_token

I need to find the google access_token that is sent to the browser after user logs in to GMail. It should be somewhere among cookies or in a browser local storage.
The problem is that the
chrome.identity.launchWebAuthFlow({url: authURL, interactive: true}, cb)
wants from the user to choose the account again even when he is already logged in to GMail.
What I really want is something similar to Microsoft Outlook Office.context.mailbox.getCallbackTokenAsync that allows to the logged user using Microsoft REST API without authenticating again.
P.S. GMail allows the user to be simultaneously logged in to multiple google accounts where each browser tab may show different active mailbox.
P.P.S. It looks like the well known issue that can be googled:
https://jindalsachin.wordpress.com/category/eathical-hacking/eathical-hacking-stuff/steal-gmail-cookiecookie-stealing-part-2/
I don't find the GX cookie in Dev console, may be it is not relevant anymore.
Instead of it the cookie that the most looks like the one is - 'COMPASS', it belongs to google domain, secured and http-only.
I tried to run this code in gmail context but still unsuccessfully:
let actualCode = '(' + function() {
let access_token = '[COMPASS cookie]';
window.fetch('https://www.googleapis.com/oauth2/v1/userinfo?alt=json', {
credentials: "include"
}).then(res => {
return res.text().then(dt => ({text: dt, status: res.status}));
}).then(res => {
console.log(res);
});
window.fetch('https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=' + access_token, {
}).then(res => {
return res.text().then(dt => ({text: dt, status: res.status}));
}).then(res => {
console.log(res);
});
} + ')();';
let script = document.createElement('script');
script.textContent = actualCode;
(document.head||document.documentElement).appendChild(script);
I get 401:Invalid Credentials in both cases.
Follow the steps in this quick start and you will have an example of what you are looking for I think. https://developers.google.com/gmail/api/quickstart/python

Azure Functions - Can it be used with Office Add-in's?

I'm sure there are clever people who can make anything run on Azure functions but does it make sense at all to use it for running Office Add-in's? I read that it's ideal for running small pieces of code and that's what my add-in currently running on Azure as an web app is.
You wouldn't use Azure Functions to build an add-in -- but you absolutely could use it in conjunction with a regular website, for some small server-side processing.
Concrete example: for an Add-in that a colleague and I were building, we needed to obtain a user's GitHub permissions to post Gists on the user's behalf. GitHub uses an "authorization code grant type" flow (see https://developer.github.com/v3/oauth/), so the flow would be as follows:
We pop a dialog (using the recently-introduce Dialog API in Add-ins) to direct the user to https://github.com/login/oauth/authorize, which shows a pretty login UI.
If the user signs in and consents, GitHub sends an authorization code back to us. The code does little good for us in client-side JavaScript, but if we pass it to an Azure Function, we can exchange it for an access token. This must be done in some server-side code (i.e., a web server, or Azure Functions, as a super-lightweight form of a web server) so that we can pass in a Client Secret for the exchange -- which quite naturally wouldn't be secret in sniffable-out client-side JavaScript. Hence putting that code on the server.
If you're curious to see what that code was like, here it is:
var request = require('request');
module.exports = function (context, data) {
context.log('code: ' + data.code);
if ('code' in data) {
request.post({
url: 'https://github.com/login/oauth/access_token',
json: {
client_id: '################',
client_secret: '################',
redirect_uri: '################',
code: data.code
}
}, function (err, httpResponse, body) {
if (err) {
context.log('error: ' + err);
context.res = {
body: {
status: 500,
error: err
}
}
}
else {
context.res = { body: body };
}
context.done();
});
}
else {
context.res = {
status: 400,
body: { error: 'Please pass the GitHub code in the input object' }
};
context.done();
}
}

Chrome Web Store 'You don't have access to licensing data for App ID:'

I have an offline Chrome Web App I want to sell through the web store.
It has a server backend. I'd like the server to check license data. How do I do that?
Here's the API. Here's a Java HowTo. Here's a OAuth-JWT lib for nodejs. I made a new client-id as described in the lib's readme.
I get this response:
{ error:
{ errors: [ [Object] ],
code: 403,
message: 'You don\'t have access to licensing data for App ID: aaaaaaaaaaaaaaaaaaaaaaaaaaaa'
}
}
How do I access license data for my app, in my server?
Mike
Here's the code:
var appId = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';
var userId = '1111111111111111111111';
// obtain a JWT-enabled version of request
var request = require('google-oauth-jwt').requestWithJWT();
request({
url: 'https://www.googleapis.com/chromewebstore/v1.1/licenses/'+appId+'/'+userId,
jwt: {
// use the email address of the service account, as seen in the API console
email: '11111111111-aaaaaaaaaaaaaaaaaaaaaaaa#developer.gserviceaccount.com',
// use the PEM file we generated from the downloaded key
keyFile: 'config/keys/app-11111111111111.pem',
// specify the scopes you wish to access - each application has different scopes
scopes: ['https://www.googleapis.com/auth/chromewebstore.readonly']
}
}, function (err, res, body) {
console.log(JSON.parse(body));
});
I've spent way to much time on this and other small problems with the Chrome Webstore. Going with Stripe.com, Braintree, or similar.

Google+ insert moment with nodejs client

Has anyone been able to get the google-api-nodejs-client to successfully insert a moment?
Whatever I try, I get a generic 400 "Invalid value" error but am unable to narrow down the invalid value because the API Explorer doesn't work either.
Would it be because of the missing data-requestvisibleactions parameter? I'm using passport.js's require('passport-google-oauth').OAuth2Strategy for handling oauth access, and that part is working fine, but I have no idea how to incorporate requestvisibleactions into the oauth request flow since this is definitely not originating from a clientside form.
Here's a snippet of what I'm trying to do (using the latest version of googleapis, v1.0.2):
var google = require('googleapis')
var auth = new google.auth.OAuth2()
auth.setCredentials({
'access_token': user.token
})
google.plus('v1').moments.insert({
collection: 'vault',
userId: 'me',
debug: true,
resource: {
type: "http://schemas.google.com/AddActivity",
target: {
type: "http://schema.org/CreativeWork",
url: "...omitted...",
image: "...omitted...",
description: "test",
name: "test"
}
},
auth: auth
}, function (err, response) {
if (err) {
console.error(err)
res.send(err.code, err)
} else {
console.log(response)
res.send(200)
}
})
ref 1 (out-of-date w.r.t. an older version of googleapis)
ref 2 (client-side, where the use of data-requestvisibleactions is more obvious)
As you speculated, you need the request_visible_actions parameter as part of the URL calling the oauth endpoint.
It looks like the current version of passport-google-oauth doesn't support this parameter. Judging by several of the open issues and pull requests, it isn't clear that the author will respond to requests to add it either. You have two possible options:
Switch to using the OAuth support that is included in google-api-nodejs-client
Patch the passport-google-oauth code. (And possibly submit a pull request in the hopes it will be useful to someone else.)
I don't use passport.js or the passport module in question, so I can't test this, but based on the github repository, I think you can insert the following in lib/passport-google-oauth/oauth2.js after line 136 and before the return statement:
if (options.requestVisibleActions) {
// Space separated list of allowed app actions
// as documented at:
// https://developers.google.com/+/web/app-activities/#writing_an_app_activity_using_the_google_apis_client_libraries
// https://developers.google.com/+/api/moment-types/
params['request_visible_actions'] = options.requestVisibleActions;
}

Resources