chrome.identity and YouTube v3 API? - google-chrome-extension

I was wondering if YouTube's v3 API and the OAuth2 support provided via chrome.identity played nicely together?
I can't seem to figure it out. Looking at: https://developers.google.com/youtube/v3/code_samples/javascript they seem to take a CLIENT_ID and scope, much like I am passing into my manifest.json.
Is there anything I can do with my OAuth2 identity token? Or do I have to go completely through YouTube's authorization process?
Update: I can fetch data using YouTube's way now, but not using the way I wanted..
gapi.auth.authorize({
client_id: '{CLIENT ID}.apps.googleusercontent.com',
scope: 'https://www.googleapis.com/auth/youtube',
// Set to false on first run to get pop-up interactivity
immediate: true
}, function (authResult) {
//console.log("Auth Result:", authResult);
gapi.client.load('youtube', 'v3', function () {
var request = gapi.client.youtube.channels.list({
mine: true,
part: 'contentDetails'
});
request.execute(function(response) {
console.log("response:", response);
});
});
});
My manifest.json has:
"oauth2": {
"client_id": "{CLIENT ID}.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/youtube",
"https://www.googleapis.com/auth/youtube.readonly",
"https://www.googleapis.com/auth/youtube.upload",
"https://www.googleapis.com/auth/youtubepartner"
]
},
"permissions": [
"identity"
}
}

OAuth2 via the Google Javascript API is a separate process than the chrome.identity API. The identity API uses the extension id to generate a unique access token.
You have to choose one process over the other, their access tokens won't work with each other.
I'm currently using the JavaScript OAuth2 with the Analytics service because the chrome.identity process requires submitting your extension to the Chrome web store. The downside to the JavaScript process is it requires me to generate the login flow for users.

Related

Azure Functions Easy Auth & Google Access token

I'm trying to add Google authentication to my Azure Functions app which will be used from a Svelte static web app (SWA). The SWA uses Google Identity (https://accounts.google.com/gsi/client) to both authenticate and then retrieve an access_token. Authentication is performed using a standard Google Identity sign in button. I've tried One Tap prompt as well with the same result.
google.accounts.id.initialize({
client_id: googleClientId,
callback: handleCredentialResponse,
});
google.accounts.id.renderButton(
button,
{ theme: 'outline', size: 'large' }, // customization attributes
);
User authenticates, works fine and I get a JWT id_token containing name email image etcetera. It's a bit annoying the user has to then again go through the whole process of selecting their account, but I guess that's the Google experience. Once I'm ready to do function calls I then proceed to authorize:
function getAccessToken() {
return new Promise((resolve, reject) => {
const client = google.accounts.oauth2.initTokenClient({
client_id: googleClientId,
scope: "openid",
callback: (response) => {
if (response.access_token) {
resolve(access_token);
} else {
reject(response?.error);
}
},
});
client.requestAccessToken();
});
}
This also works fine, I retrieve an access_token. I then proceed to call an Azure Function with this token in the header:
Authorization: Bearer <ACCESS_TOKEN>
This always results in a 401 response. I have tried setting all functions to anonymous to no effect.
I'm wondering if this has to do with scope. In the Google Console it's only possible to add Google specific scopes, which is why I retrieve an access_token for the openid scope.
I've also tried setting credentials to include since there might be cookies the Easy Auth layer would like to read from the web app to authenticate the user. CORS on the Azure Functions app is configured correctly for the host names used by the web app and Access-Control-Allow-Credentials is enabled on the Function App. This has no effect either.
Wow this was badly documented. After reading the Azure Functions and App Service Authentication blog post it seems an 'authentication token' needs to be retrieved from the functions app itself instead of an 'access token' from Google. After Google identification the id_token from the first step needs to be POSTed to https://<functions_app>/.auth/login/google with the following as body:
{
"id_token": "<id_token>"
}
This in turn returns something as follows:
{
"authenticationToken": "<authenticationToken>",​
"user": { "userId": "<sid>" }
}
This authenticationToken then needs be be passed in the header to each function call as follows:
X-ZUMO-AUTH: <authenticationToken>
Edit: it seems this was fully documented, somehow I missed this.

How to get a refresh token using the Microsoft Graph Javascript client library?

I am using the Microsoft graph Javascript client library to get a refresh token for a user. I created an app that connects doctors and patients. I want to create and delete events on the doctors' calendars. I first need their authorization to access their outlook account. Unfortunately, when I make the api call to get the refresh token, I get back an access token and an id token but no refresh token. Can someone please help?
Here's my code
const msalConfig = {
auth: {
clientId: process.env.OUTLOOK_OAUTH_CLIENT_ID,
authority: process.env.OUTLOOK_OAUTH_AUTHORITY,
clientSecret: process.env.OUTLOOK_OAUTH_CLIENT_SECRET
},
system: {
loggerOptions: {
loggerCallback(loglevel, message, containsPii) {
console.log(message);
},
piiLoggingEnabled: false,
logLevel: msal.LogLevel.Verbose,
}
}
};
// Create msal application object
const ouathClient = new msal.ConfidentialClientApplication(msalConfig);
const response = await ouathClient.acquireTokenByCode(tokenRequest);
I am using node js.
This method can also be used to get the refresh token, Please refer this Microsoft documentation.To get refresh token
Client Credentials flow does not support user context thus no refresh token is supported in this case.
If you are using MSAL depending on whether you are using Public client (Mobile, Desktop or Single Page apps) where users sign-in to your app then you may need a refresh token and you should be using flows listed here
If you are using a private client like a serveside daemon then you dont need a refresh token.

Azure EasyAuth: Getting Unauthorized error when try to login with a Microsoft account

This has been baffling me for hours now, so I have been trying to get EasyAuth working using different providers.
I am using this on Azure Functions, so let's say my function address is
https://xxx.azurewebsites.net
If I want to login into the service using a Google account I send my post request along with token received from Google to the following address
https://xxx.azurewebsites.net/.auth/login/google
This gives me a converted token back.
However if I do the same thing with a Microsoft account using the following details
Request Body:
{ "access_token": "token-string-value" }
Endpoint:
https://xxx.azurewebsites.net/.auth/login/microsoftaccount
It gives me the following error instead of a converted token
401 Unauthorized You do not have permission to view this directory or page.
--
I am using Msal JavaScript library to get my authentication token. Also I am testing these in Postman which makes it easy to understand what the problem is before I deal with the code and other stuff.
-- Update 1.0
This does seem like a bug, as even if I try to navigate to the
https://xxx.azurewebsites.net/.auth/login/microsoftaccount
It shows me the following
This URL works for other providers, Google, Facebook and Twitter. For all of them it redirects the user to the provider's login page.
According to the error page and the address bar contents, the client doesn't exist which could be referring to the application created on Azure to allow my website access the API. But everything has been setup correctly.
It would be helpful if someone from Azure We App Services can take a look at this.
I have created the Application and added the application ID and Secret int eh App Services page.
-- Update 2.0
So after hours of investigation, I managed to get the URL working, shockingly it was due to wrong information given on Azure portal. The link in Authorization and Authentication section of App Service is pointing to a new platform to register applications, which is purely for Azure AD based users.
For the external users to be able to login the application need to be registered in the following portal
https://apps.dev.microsoft.com
After registering the application here, and added the details in the App Service blade, the URL to EasyAuth is working.
However this doesn't resolve my issue. I still need a JavaScript library that gives me valid token which I can pass to EasyAuth endpoint.
Strangely the token taken from MSAL is not valid for Microsoft account. It just gives me the same error that my access is unauthorised. This means I probably need to use a different library to get a different token. I'd appreciate it if still someone can help me with this.
Below is a short sample code I am using to retrieve token and pass it to another function n which call EasyAuth endpoint and post the token along.
var applicationConfig = {
clientID: "xxxx-xxx-xxxx-xxxx",
authority: "https://login.microsoftonline.com/9fc1061d-5e26-4fd5-807e-bd969d857223",
graphScopes: ["user.read"],
graphEndpoint: "https://graph.microsoft.com/v1.0/me"
};
var myMSALObj = new Msal.UserAgentApplication(applicationConfig.clientID, applicationConfig.authority, acquireTokenRedirectCallBack,
{ storeAuthStateInCookie: true, cacheLocation: "localStorage" });
function signIn() {
myMSALObj.loginPopup(applicationConfig.graphScopes).then(function (idToken) {
//Login Success
acquireTokenPopupAndCallMSGraph();
}, function (error) {
console.log(error);
});
}
function signOut() {
myMSALObj.logout();
}
function acquireTokenPopupAndCallMSGraph() {
//Call acquireTokenSilent (iframe) to obtain a token for Microsoft Graph
myMSALObj.acquireTokenSilent(applicationConfig.graphScopes).then(function (accessToken) {
// accessToken
}, function (error) {
console.log(error);
});
}
I managed to find what was causing the problem.
So basically only Live Connect SDK generated tokens are valid on
https://xxx.azurewebsites.net/.auth/login/microsoftaccount
We were using MSAL which was generating tokens valid only on Azure Active Directory. I have been in touch with Azure Support, and have asked them to update the documentation. It currently is very confusing as none of these have been explained in the EasyAuth documentations.
We decided to go with Azure AD B2C, as it's more reliable and turns out cheaper for us.
In case anyone would like to use EasyAuth with Microsoft Account, the following is showing how to get access token from Live SDK
WL.Event.subscribe("auth.login", onLogin);
WL.init({
client_id: "xxxxxx",
redirect_uri: "xxxxxx",
scope: "wl.signin",
response_type: "token"
});
WL.ui({
name: "signin",
element: "signin"
});
function onLogin(session) {
if (!session.error) {
var access_token = session.session.access_token;
mobileClient.login('microsoftaccount', { 'access_token': access_token }, false)
.then(function () {
console.log('TODO - could enable/disable functionality etc')
}, function (error) {
console.log(`ERROR: ${error}`);
});
}
else {
console.log(`ERROR: ${session.error_description}`);
}
}
Reference to
< script src="//js.live.net/v5.0/wl.js">

Loopback-passport-component Allow single page application Login via Facebook

I have been using loopback-component-passport with facebook login flow. As I'm moving to a single page app, I'm doing the facebook login using the FB sdk as described here: https://developers.facebook.com/docs/facebook-login/web
{
"facebook": {
"provider": "facebook",
"module": "passport-facebook",
"clientID": "<id>",
"clientSecret": "<secret>",
"callbackURL": "/auth/facebook/callback",
"authPath": "/auth/facebook",
"callbackPath": "/auth/facebook/callback",
"successRedirect": "/auth/account",
"failureRedirect": "/login",
"scope": [
"email"
],
"failureFlash": true
}
}
I'm able to retrieve the FB access token with the FB sdk, and sending the response.authResponse.accessToken value to GET http://localhost:3000/auth/facebook/callback?access_token=<token from FB sdk response> but I get an html response.
Am I doing something wrong or loopback does not support this feature?
For that use case, where you get the access token on the client, I think the passport-facebook-token module works better.
I've just been dealing with facebook oAuth, and I found that the best solution. You avoid the oAuth redirections, while still taking advantage of passport for the token validation and permanent session handling.

Can I use chrome.identity with Firebase custom authentication?

I'm building a Chrome extension and would like to use Firebase to persist state shared between users. Firebase authentication doesn't work within Chrome extension because there's no origin domain. The chrome.identity API can be used to ensure that the user is authenticated and to get the access token for OAuth requests.
A couple of considerations:
Use chrome.storage to store a token and use that to authenticate with Firebase. The storage area is not encrypted, so it would be trivial to read a user's token from their disk.
I assume the token returned by chrome.identity.getAuthToken is an OAuth access token and therefore transient - it wouldn't be suitable for a permanent unique identifier for a user.
I could make a request to a Google OAuth API to exchange the access token for the user's profile (https://www.googleapis.com/userinfo/v2/me), which contains an id field, but this is public.
I came across this question on my quest to solve a similar problem. I am sure the question is outdated but maybe my solution helps someone else stumbling over this question.
It is indeed possible to use chrome.identity for Firebase authentication... But the way is not through the custom authentication method. There is another method which accepts the OAuth2 token from chrome.identity.getAuthToken.
Here is everything I did following this tutorial:
(It also mentions a solution for non-Google auth providers that I didn't try)
Identity Permission
First you need permission to use the chrome identity API. You get it by adding this to your manifest.json:
{
...
"permissions": [
"identity"
],
...
}
Consistent Application ID
You need your application ID consistent during development to use the OAuth process. To accomplish that, you need to copy the key in an installed version of your manifest.json.
To get a suitable key value, first install your extension from a .crx file (you may need to upload your extension or package it manually). Then, in your user data directory (on macOS it is ~/Library/Application\ Support/Google/Chrome), look in the file Default/Extensions/EXTENSION_ID/EXTENSION_VERSION/manifest.json. You will see the key value filled in there.
{
...
"key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgFbIrnF3oWbqomZh8CHzkTE9MxD/4tVmCTJ3JYSzYhtVnX7tVAbXZRRPuYLavIFaS15tojlRNRhfOdvyTXew+RaSJjOIzdo30byBU3C4mJAtRtSjb+U9fAsJxStVpXvdQrYNNFCCx/85T6oJX3qDsYexFCs/9doGqzhCc5RvN+W4jbQlfz7n+TiT8TtPBKrQWGLYjbEdNpPnvnorJBMys/yob82cglpqbWI36sTSGwQxjgQbp3b4mnQ2R0gzOcY41cMOw8JqSl6aXdYfHBTLxCy+gz9RCQYNUhDewxE1DeoEgAh21956oKJ8Sn7FacyMyNcnWvNhlMzPtr/0RUK7nQIDAQAB",
...
}
Copy this line to your source manifest.json.
Register your Extension with Google Cloud APIs
You need to register your app in the Google APIs Console to get the client ID:
Search for the API you what to use and make sure it is activated in your project. In my case Cloud Firestore API.
Go to the API Access navigation menu item and click on the Create an OAuth 2.0 client ID... blue button.
Select Chrome Application and enter your application ID (same ID displayed in the extensions management page).
Put this client ID in your manifest.json. You only need the userinfo.email scope.
{
...
"oauth2": {
"client_id": "171239695530-3mbapmkhai2m0qjb2jgjp097c7jmmhc3.apps.googleusercontent.com",
"scopes": [
"https://www.googleapis.com/auth/userinfo.email"
]
}
...
}
Get and Use the Google Auth Token
chrome.identity.getAuthToken({ 'interactive': true }, function(token) {
// console.log("token: " + token);
let credential = firebase.auth.GoogleAuthProvider.credential(null, token);
firebase.auth().signInWithCredential(credential)
.then((result) => {
// console.log("Login successful!");
DoWhatYouWantWithTheUserObject(result.user);
})
.catch((error) => {
console.error(error);
});
});
Have fun with your Firebase Service...

Resources