Firebase Authentication in a Chrome Extension Background Page - google-chrome-extension

How would I authenticate with Firebase in a chrome extension? I need to specify the allowed domain list in the Forge. Chrome domain for the extension is just a big hash-like string.
I did read this: authClient.login problems
But the hashed based domain of a chrome extension is not being accepted in the Firebase forge. Is there another way to go about it? Currently am just reading the cookie firebaseSessionKey to just assume that I am logged in. But surely that can't be as secure as letting Firebase validate this session key.

As Rob points out, authentication cannot work in an environment that does not enforce origin restrictions. The fundamental problem here is that any authentication provider (Facebook, Twitter, Persona, or your own service) cannot issue an identity to a browser - i.e. it is meaningless to use Facebook to login to your browser (or extension).
The F1 add-on for Firefox ran into a similar problem (http://f1.mozillamessaging.com/) - where you would authorize F1 to post on twitter/facebook on your behalf. The extension had a website to along with it, from where you would serve the login page and proceed as you would normally in a web page. You'll need some code to communicate between the web page and your extension, chrome provides the tools necessary.
I would recommend the same approach - create a web page on a real domain (Github pages is awesome for this) to go along with your extension. This means your extension can't work offline, but neither can your login or writing to Firebase!

This will work using Google Plus Login Flow which I believe is the only one that allows cross authentication so the scopes are Google Plus Login.
"www[dot]googleapis[dot]com/auth/plus.login"
So what is happening here is you will get the access_token from the extension which you will be sending to firebase with the request using authwihtoauthtoken specifying google as a provider along with the access_token acquired from chrome.identity.getAuthToken()!
https://www.firebase.com/docs/web/api/firebase/authwithoauthtoken.html
Now the fact is that this access token could be issued by any other app, so we need to make sure that it is valid and has been issued for our app, basically we need to know there isn't man in the middle trying to access our database.
This verification is being made by the firebase.
They will check if this token belongs to the same application as the token has been issued to.
So you will need to create another set of credentials under the same application in the google developers console as for your extension. We will be basically doing the same thing as if we were to do it for our webpage but we will be inserting this new set of credentials to firebase's google oAuth in their security section.
They will do this check for us there. They will verify with google if the token is issued to the same app.
That's it.
Background Information.
https://developers.google.com/identity/protocols/OAuth2UserAgent#validatetoken
Use case
Sending ID tokens with requests that need to be authenticated. For example, if you need to pass data to your server and you want to ensure that particular data came from a specific user.
When to verify the access
All tokens need to be verified on your server unless you know that they came directly from Google. Any token that you receive from your client apps must be verified.
Google has a tutorial how to do this for python found at:
"github[dot]com/googleplus/gplus-verifytoken-python"
So basically what is happening here is; instead you doing to verification from on your server, firebase does this verification for you when you enter the CLIENT_ID and APP_SECRET into the firebase and enable the Google Authentication.
The way to do this correctly is a combination or same style of verifying to whom the client_secret was issued. Chrome will give you a access_token and then this access_token will be checked on the firebase's backend.

Related

Implement SSO in Chrome extensions

To simplify the scenario let's say I have a website which stores user data such as a to-do list.
I also want to have a Chrome extension which shows this list but without asking user to authenticate again if he is already authenticated with the website.
To do this I implemented an authorization server with Oauth 2.0 but the problem is that I don't know which flow should I follow for my extension. I followed authorization code flow for web apps but it seems wrong as I don't want my extension to be treated as a 3rd party app and ask user for permission.
For authorization server I used this library.
For my extension I also created another independent back-end to store access tokens as I read it is unsafe to store the access and refresh token in client-side and browser storage.
The example that comes to my mind is Google Hangout extension.

Server-side authentication using Google accounts in a Chrome extension

I have a Web application that currently uses OAuth2 to authenticate users using their Google accounts. The flow is quite standard: the user logs in to Google, the web app gets a callback, retrieves the user identity and stores it in the session.
Now I need to create an accompanying Chrome extension. This extension needs to access the web app underneath, so it needs to authenticate against this app. I configured my extension using the official documentation, but during experiments, I realized this is not what I need. Since it uses the OAuth2 implicit flow, it doesn't return a token that could be validated on the server side. This flow is suitable only for using Google APIs on the client side, which is not my use case. This documentation (and pretty much everything else I found on the Web) focuses on two possible cases:
We want to access Google APIs on the extension side (chrome.identity.getAuthToken()).
We want to authenticate using an alternative OAuth2 service (chrome.identity.launchWebAuthFlow()).
However, in my case, I'd like to authenticate users using Google accounts, but process the token on the server side of my Web app. I could use option 2 here, but it just doesn't "feel right" to me to create my own "non-Google authentication service" that is just a wrapper over Google authentication service, only to be able to authenticate on the server side.
Is option 2 really the only way to go, or is there any simpler way?
I also saw someone recommending using the tokeninfo endpoint to validate the token, but I find it hard to make sure that this is indeed an "official" and secure way of doing this.
To retrieve an access token that you can use on both parts of your app, the extension and the server, you should request a Google Cross-Client Access Token. This allows you to register your two apps (two client IDs) in a single project and share an access token.
This is described and discussed by Google here:
Docs: Google Identity Platform: Cross-client Identity
Video: Google Drive SDK: Cross-client authorization
The rough steps are:
You will need two clientIds, one for your extension and another for your server app
Add both clientIds to a single project
Retrieve the cross-client access token from your extension
Send it to your server via HTTPS
To do this in Chrome, it looks like you would call chrome.identity.getAuthToken() with a callback function that sends the token to your web app.
The reference says the following on chrome.identity.getAuthToken():
chrome.identity.getAuthToken(object details, function callback)
Gets an OAuth2 access token using the client ID and scopes specified in the oauth2 section of manifest.json.
and that it can take a callback function as specified as:
Called with an OAuth2 access token as specified by the manifest, or undefined if there was an error.
If you specify the callback parameter, it should be a function that looks like this:
function(string token) {...};
Ref: method-getAuthToken

Authentication strategy between my chome extension and server

I'm in the process of building a Google Chrome extension, and have some questions about how to implement security into the application.
I need to access a couple of Google API's so am going to be using OAuth 2.0 for that. So basically from the extension I know which user is logged into the browser.
My extension then needs to get and post data to my (nodejs) API service. I want to ensure that the user requesting data is the same user that is logged into the browser. Is there any way of using the previous Google authentication process to also authenticate communications between the extension and my API? I dont really want the user to have to log in again, to access my API.
I'm sure I'm missing something simple, and I've not been able to find anything that fits this scenario
Follow the OpenID Connect auth flow and you will get an access_token and an id_token. The acess_token you will use to use to make authenticated requests to Google APIs as usual. The id_token will be used as authentication with requests to your server.
When the requests hit your server you will need to validate the token and you can then use the contents of the id_token to identify the user.
User wouldn't have to login on auth process provided if user is already logged in and you are using a web application flow (not chrome.identity APIs) but user would see the consent screen atleast the first time. However you can skip the account selector screen if you already know the email address by providing &login_hint= parameter.

Does OAuth 2.0 always require a browser in the flow

Can I use OAuth 2.0 without a browser (or an embedded browser in my app) to perform nightly uploads?
Setup I have a refresh token and access token from provider console-- Google Drive API
I wish to use Java SDK to use/reuse these to upload data without the requirement for any browser authorization once i have initially received my refresh/access tokens.
OAuth 2.0 requires a browser for user consent once
A browser is required, so that the user can agree to the request of the app to access the users data.
After the user agreed on sharing the data with the app, the app can use the refresh token without a browser based flow.
Documented here: https://developers.google.com/accounts/docs/OAuth2WebServer
Alternative for non-browser apps
You may use the OAuth 2.0 for Devices flow:
You app can act as a device which queries a code from google, displays it to the user, and asks the user to browse to a verification URL (e.g. with (system.out.println...).
So a browser is still needed, but your application itself doesn't need to provide a webpage to the user.
Yes. That is precisely what unattended access with the refresh token is about. When the user granted permission to the app, he was specifically prompted "... even when you're not logged in" (or similar, I can't remember the exact wording). You will store the refresh token on the server somewhere, and then use it to request an access token whenever your app needs to do its thang.
Just to clarify some of the wording in your question, the refreash and access tokens do NOT form a pair, so saying "reuse these", should actually be "reuse this", where 'this' is the refresh token.

client secret in OAuth 2.0

To use google drive api, I have to play with the authentication using OAuth2.0. And I got a few question about this.
Client id and client secret are used to identify what my app is. But they must be hardcoded if it is a client application. So, everyone can decompile my app and extract them from source code. Does it mean that a bad app can pretend to be a good app by using the good app's client id and secret? So user would be showing a screen that asking for granting permission to a good app even though it is actually asked by a bad app? If yes, what should I do? Or actually I should not worry about this?
In mobile application, we can embedded a webview to our app. And it is easy to extract the password field in the webview because the app that asking for permission is actually a "browser". So, OAuth in mobile application does not have the benefit that client application has not access to the user credential of service provider?
I had the same question as the question 1 here, and did some research myself recently, and my conclusion is that it is ok to not keep "client secret" a secret.
The type of clients that do not keep confidentiality of client secret is called "public client" in the OAuth2 spec.
The possibility of someone malicious being able to get authorization code, and then access token, is prevented by the following facts.
1. Client need to get authorization code directly from the user, not from the service
Even if user indicates the service that he/she trusts the client, the client cannot get authorization code from the service just by showing client id and client secret.
Instead, the client has to get the authorization code directly from the user. (This is usually done by URL redirection, which I will talk about later.)
So, for the malicious client, it is not enough to know client id/secret trusted by the user. It has to somehow involve or spoof user to give it the authorization code,
which should be harder than just knowing client id/secret.
2. Redirect URL is registered with client id/secret
Let’s assume that the malicious client somehow managed to involve the user and make her/him click "Authorize this app" button on the service page.
This will trigger the URL redirect response from the service to user’s browser with the authorization code with it.
Then the authorization code will be sent from user’s browser to the redirect URL, and the client is supposed to be listening at the redirect URL to receive the authorization code.
(The redirect URL can be localhost too, and I figured that this is a typical way that a “public client” receives authorization code.)
Since this redirect URL is registered at the service with the client id/secret, the malicious client does not have a way to control where the authorization code is given to.
This means the malicious client with your client id/secret has another obstacle to obtain the user’s authorization code.
I started writing a comment to your question but then found out there is too much to say so here are my views on the subject in the answer.
Yes there is a real possibility for this and there were some exploits based on this. Suggestion is not to keep the app secret in your app, there is even part in the spec that distributed apps should not use this token. Now you might ask, but XYZ requires it in order to work. In that case they are not implementing the spec properly and you should A not use that service (not likely) or B try to secure token using some obfuscating methods to make it harder to find or use your server as a proxy.
For example there were some bugs in Facebook library for Android where it was leaking tokens to Logs, you can find out more about it here
http://attack-secure.com/all-your-facebook-access-tokens-are-belong-to-us
and here https://www.youtube.com/watch?v=twyL7Uxe6sk.
All in all be extra cautious of your usage of third party libraries (common sense actually but if token hijacking is your big concern add another extra to cautious).
I have been ranting about the point 2 for quite some time. I have even done some workarounds in my apps in order to modify the consent pages (for example changing zoom and design to fit the app) but there was nothing stopping me from reading values from fields inside the web view with username and password. Therefore I totally agree with your second point and find it a big "bug" in OAuth spec. Point being "App doesn't get access to users credentials" in the spec is just a dream and gives users false sense of security… Also I guess people are usually suspicions when app asks them for their Facebook, Twitter, Dropbox or other credentials. I doubt many ordinary people read OAuth spec and say "Now I am safe" but instead use common sense and generally not use apps they don't trust.
Answering to 2nd question: Google APIs for security reason mandate that authentication/sign-in cannot be done within App itself (like webviews are not allowed) and needs to be done outside app using Browser for better security which is further explained below:
https://developers.googleblog.com/2016/08/modernizing-oauth-interactions-in-native-apps.html

Resources