I have a Chrome Extension that needs to authenticate the user. Once authenticated, I will send that user's email to my server running in Docker and then log them in. I am having trouble getting the token. Here is the code:
chrome.identity.getAuthToken({ 'interactive': true }, function(token) {
if (chrome.runtime.lastError) {
currentSessionAccessToken=token;
alert(chrome.runtime.lastError.message);
//alert("you need to have a gmail account"); //ubuntu
return;
}
currentSessionAccessToken=token;
var x = new XMLHttpRequest();
x.open('GET', 'https://www.googleapis.com/oauth2/v2/userinfo?alt=json&access_token=' + token);
x.onload = function() {
if (x.readyState=200)
{
var data=this.responseText;
jsonResponse = JSON.parse(data);
photo = jsonResponse.picture;
szName=jsonResponse.name;
email=jsonResponse.email;
x.abort(); //done so get rid of it
send_to_backend(request, sender, sendResponse);
};
}
x.send();
}
The problem is that I am not getting back an access token. The backend (at this time) is also on my laptop (localhost) but in a docker container. I don't have an SSL cert for my localhost and I am wondering if that is the issue? I am never getting a token so I never get to send it with the XMLHttpRequest, and thus I never get a ReadyState=200. Any idea what is wrong?
Did you register your app for Google OAuth API access and designate the oauth field in the manifest?
From the documentation on user auth:
Copy key to your manifest
When you register your application in the Google OAuth console, you'll provide your application's ID, which will be checked during token requests. Therefore it's important to have a consistent application ID during development.
To keep your application ID constant, you need to copy the key in the installed manifest.json to your source manifest. It's not the most graceful task, but here's how it goes:
Go to your user data directory. Example on MacOs: ~/Library/Application\ Support/Google/Chrome/Default/Extensions
List the installed apps and extensions and match your app ID on the apps and extensions management page to the same ID here.
Go to the installed app directory (this will be a version within the app ID). Open the installed manifest.json (pico is a quick way to open the file).
Copy the "key" in the installed manifest.json and paste it into your app's source manifest file.
Get your OAuth2 client ID
You need to register your app in the Google APIs Console to get the client ID:
Login to the Google APIs Console using the same Google account used to upload your app to the Chrome Web Store.
Create a new project by expanding the drop-down menu in the top-left corner and selecting the Create... menu item.
Once created and named, go to the "Services" navigation menu item and turn on any Google services your app needs.
Go to the "API Access" navigation menu item and click on the Create an OAuth 2.0 client ID... blue button.
Enter the requested branding information, select the Installed application type.
Select Chrome Application and enter your application ID (same ID displayed in the apps and extensions management page).
Once you register your app you need to add something like this to your manifest:
"oauth2": {
"client_id": "YOUR_CLIENT_ID",
"scopes": ["scope1", ...]
}
Turns out that in order to get "identity" working you must publish to the Google WebStore. The reason I stayed away from that is that it often takes weeks to get a site reviewed. I have had that experience in the past. I haven't really nailed down the new URL that will be using and wanted to get the system working before I did that. Now that I submitted for Review, I guess I have some time, and will "dummy up" the steps needed (ie authentication) to continue the development work. Thanks Micah for pointing out the manual. This led to me realizing that there is no way to get "identity" working without getting approval from Google.
Related
I have a legacy static website that is just plain HTML and simple JavaScript for UI effects. There is no server side code, api, config files or anything in this website - just raw HTML files, CSS, pictures, etc.
The website will not be hosted in Azure. It will be on a local IIS server. If I pull the web site into Visual Studio, the "Configure Azure AD Authentication" wizard shows:
An incompatible authentication configuration was found in this project
().
How can I secure simple HTML files using Azure AD?
The Visual Studio "Configure Azure AD Authentication" wizard is intended for ASP.Net Web Apps and Web APIs.
In your case, what you are building is considered a "Single Page Application" or SPA. Even though you might have multiple pages, this term also applies to client side only web apps with no backend code.
For this, you should follow the Azure AD Javascript Single Page Application sample.
The gist of it is that you should us ADAL.js like shown in this sample's app.js, along the lines of:
// Configure ADAL
window.config = {
instance: 'https://login.microsoftonline.com/',
tenant: '[Enter your tenant here, e.g. contoso.onmicrosoft.com]',
clientId: '[Enter your client_id here, e.g. g075edef-0efa-453b-997b-de1337c29185]',
postLogoutRedirectUri: window.location.origin,
cacheLocation: 'localStorage', // enable this for IE, as sessionStorage does not work for localhost.
};
var authContext = new AuthenticationContext(config);
// Check For & Handle Redirect From AAD After Login
var isCallback = authContext.isCallback(window.location.hash);
authContext.handleWindowCallback();
$errorMessage.html(authContext.getLoginError());
if (isCallback && !authContext.getLoginError()) {
window.location = authContext._getItem(authContext.CONSTANTS.STORAGE.LOGIN_REQUEST);
}
// Check Login Status, Update UI
var user = authContext.getCachedUser();
if (user) {
//Do UI for authenticated user
} else {
//Show UI for unauthenticated user
}
// Register NavBar Click Handlers
$signOutButton.click(function () {
authContext.logOut();
});
$signInButton.click(function () {
authContext.login();
});
Note: There's also a Angular SPA sample.
The solution posted by Saca pointed me in the right direction, but adding the JS to every page was not a valid solution for me. There were thousands of HTML files, lots with no common JS file I could tack that ADAL code into. I would have had to find a way to insert that JS on all those pages.
My first solution was simply creating a normal .NET MVC app with the proper auth configured. Then I simply loaded this legacy content via an iFrame. This worked but was limiting for the users.
As Fei Xue mentioned in another comment, the next solution involved scrapping the iFrame but routing all requests for static files through a controller. Using this as a reference for understanding that: https://weblogs.asp.net/jongalloway/asp-net-mvc-routing-intercepting-file-requests-like-index-html-and-what-it-teaches-about-how-routing-works
The above solutions worked. However, eventually this app ended up as an Azure App Service and I simply turned on authentication at the app service level with just the pure html files.
I am working on some client side web app like a chrome extension that needs access to outlook mail and calendar. I followed the instruction on https://dev.outlook.com/RestGettingStarted and successfully got access and refresh tokens to retrieve data.
However, I cannot find any way of implementing "logout". The basic idea is to let user sign out and login with a different outlook account. In order to do that, I removed cached tokens, requested access tokens in interactive mode. The login window did pop out, but it took any valid email address, didn't let me input password and finally returned tokens for previous account. So I was not able to really use a different account until the old token expired.
Can anyone please tell me if it is possible to send a request to revoke the tokens so people can use a different account? Thanks!
=========================================================
Update:
Actually it is the fault of chrome.identity api. I used chrome.identity.LaunchWebAuthFlow to init the auth flow. It caches user's identity but no way to remove it. So we cannot really "logout" if using this api.
I used two logouts via launchWebAuthFlow - first I called the logout link to my app, then secondly, I called the logout link to Google.
var options = {
'interactive': false,
'url': 'https://localhost:44344/Account/Logout'
}
chrome.identity.launchWebAuthFlow(options, function(redirectUri) {});
options = {
'interactive': false,
'url': 'https://accounts.google.com/logout'
}
chrome.identity.launchWebAuthFlow(options, function(redirectUri) {});
I am relatively new to sharepoint app development.
Trying to create a on premises, High Trust provider hosted app with App + User Policy. I have followed below document to create a demo.
https://msdn.microsoft.com/library/office/fp179901(v=office.15)
http://blogs.msdn.com/b/russmax/archive/2014/06/23/part-1-intro-to-provider-hosted-apps-setup-the-infrastructure.aspx
I am facing few issue and I have some question to clarify, if anybody can help.
1) When I inspect my request in dev tools, it give me below form data.
SPAppToken:
SPSiteUrl:
SPSiteTitle:Home
SPSiteLogoUrl:
SPSiteLanguage:en-US
SPSiteCulture:en-US
SPRedirectMessage:EndpointAuthorityMatches
SPErrorCorrelationId:f069e89c-a0cd-20ce-a1c0-7db95db0334b
now when i inspect log with above corelation id, i am finding below errors.
-- Error when get token for app i:0i.t|ms.sp.ext|ab8ff461-bc75-4516-b475-b666ac47eec0#802f23e1-6e11-45d1-909c-07a7b0ab0ce2,
exception: Microsoft.SharePoint.SPException: The Azure Access Control
service is unavailable.
-- App token requested from appredirect.aspx for site: 92bfe5c4-7255-4b09-a89a-07e0e2b03622 but there was an error in
generating it. This may be a case when we do not need a token or when
the app principal was not properly set up.
-- Getting Error Message for Exception Microsoft.SharePoint.SPException: The Azure Access Control service is
unavailable.
a) I belive in high-trust app it shouldn't look for Azure ACS.
Is this error because of some incorrect configuration?
b) SPAppToken is null here. Is it null always in case of hig trust app?
2) Say I am logged into sharepoint with User A and trying to launch sharepoint app.
Within app code I want to get identity of logged in user(which is A). From below code i found that Request.LogonUserIdentity gives me identity of user A. But how can we sure that request is came from sharepoint only. I can copy the same app URL and paste in browser window and login with window credential and get the same result. So question is how can I verify if its legitimate request came from sharepoint only and no one is faking request.
ALos, when I inspect request in dev tools, its passing Authorization key in request header. What is use of this?
using (var clientContext = TokenHelper.GetS2SClientContextWithWindowsIdentity(hostWeb, Request.LogonUserIdentity)) { clientContext.Load(clientContext.Web, web => web.Title); clientContext.ExecuteQuery(); Response.Write(clientContext.Web.Title); }
3) Also what happens if my app doesnt support windows authentication and only support FBA, is there any way to get user identity in this case?
Any help would be much appreciated.
Thanks
For issue #1: It looks to me that the step # 9 (Configure authentication settings) in this section (from the first MSDN article you have referred) was missed, i.e., 'ACS Control service' was selected instead of 'Use a Certificate' option.
For issue #2: There are helper methods in TokenHelper.cs to validate the AccessToken from the HttpRequest, which identifies the validity of the request.
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...
I'm trying to authorize with chrome.identity.getAuthToken() to get token for Picasa web service. I couldn't find Picasa API in Google Developer Console and set its scope to "https://picasaweb.google.com/data/" oauth2 part of manifest.json. Picasa docs say that I can skip this step.
chrome.identity.getAuthToken({
interactive: true
}, function (token) {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError);
} else {
console.log(token);
}
});
getAuthToken() always ends with an error "OAuth2 request failed: Service responded with error: 'bad client id: {0}'". If no scopes are set, the error looks like "OAuth2 request failed". Where have I mistaken?
Steps I take to make it work
Go to Google Developers Console and create a new project.
Go to APIs & auth > Credentials in the panel to create new Client ID. The application ID of chrome app can be obtained from Chrome Developer Dashboard if you your app is uploaded.
Go to APIs & auth > Consent screen and fill in Email Address and Product Name and Save.
I didn't know step 3 was necessary.
It seems amazing but after 1 day has passed, everything is working :)
UPD: I've tried gdrive sample from chrome-app-samples repo and added scope for Picasa. After everything worked fine, I copied its key and oauth2 section to my app's manifest. Everything worked fine too. After this I deleted client_id for app in developer console and created it again. And after that everything was ok.
You need to register your application in Google Developer Console and obtain a client_id. See the 'Credentials' pane to configure your application.