How to perform domain verification for Firebase functions - firebase

I'd like to use Google's Webmaster Tools to add domain verification for my "site", which is entirely made up of Cloud Functions for Firebase:
https://us-central1-<project-id>.cloudfunctions.net/
However I cannot figure out how to do this in a way that would work successfully.
The recommended way is to download and serve an HTML file with a verification key. However, I cannot seem to create a function with a dot.
exports['googleKEY.html'] = functions...
This fails when trying to deploy.
An alternative is to put a meta tag in my "homepage", but that also does not work as I cannot seem to create an index page.
exports[''] = functions...
and
exports['index.html'] = functions...
Also fail.
Is there a way to do this domain verification just through functions? I'd appreciate guidance.

I had the same problem: I wanted to validate my Domain Ownership in the Google Search Console. But the domain is actually a Firebase Cloud Functions domain (https://*.cloudfunctions.net). I found a super easy solution today:
1) When adding a property in Google Search Console, select the method "URL prefix" and enter the url of the function you will create in step 3 (i.e. https://foobar.cloudfunctions.net/googleDomainVerification).
2) Select the method "HTML tag" and copy the meta-tag.
3) Create a https function that you push on Firebase Cloud Function. Don't forget to copy your meta-tag from step 2:
exports.googleDomainVerification = functions.https.onRequest((req, res) => {
res.status(200).send('<!DOCTYPE html> <html> <head> YOUR_META_TAG_HERE </head> <body> </body> </html>')
})
4) Wait a minute then press "Verify" on the Google Search Console
That's it. Everything should work now :)

So... I think I finally may have a solution.
There is no direct way to verify a Firebase Functions domain (https://*.cloudfunctions.net) BUT verifying Firebase Hosting domain (https://*.firebaseapp.com) is easy (using verification file). So let's start with that.
There is a config option in Hosting to setup url rewrite to serve a Function. (Documented here)
This is a modified example config from the link above, opening url https://<your-project-id>.firebaseapp.com/covertFnBigben to invoke Function bigben.
{
"hosting": {
"public": "public",
// Add the following rewrites section *within* "hosting"
"rewrites": [
{
"source": "/covertFnBigben", "function": "bigben"
}
]
}
}
So after successfull verification of your Firebase Hosting domain you can use that domain to call Firebase Functions.

Related

Firebase 3rd-party AuthProvider (Google/Facebook/etc) login with chrome extension manifest v3

Manifest version 3 for Chrome extensions have been killing me lately. Been able to navigate around it so far, but this one has really stumped me. I'm trying to use Firebase authentication for a Chrome extension, specifically with 3rd party auth providers such as Google and Facebook. I've setup the Firebase configuration for Login with Google and created a login section in the options page of the Chrome extension and setup the Firebase SDK.
Now, there are two login options when using an auth provider, signInWithRedirect and signInWithPopup. I've tried both of these and both have failed for different reasons. signInWithRedirect seems like a complete dead end as it redirects to the auth provider, and when it attempts to redirect back to the chrome-extension://.../options.html page, it just redirects to "about:blank#blocked" instead.
When attempting to use signInWithPopup, I instead get
Refused to load the script 'https://apis.google.com/js/api.js?onload=__iframefcb776751' because it violates the following Content Security Policy directive: "script-src 'self'". Note that 'script-src-elem' was not explicitly set, so 'script-src' is used as a fallback.
In v2, you could simply add https://apis.google.com to the content_security_policy in the manifest. But in v3, the docs say
"In addition, MV3 disallows certain CSP modifications for extension_pages that were permitted in MV2. The script-src, object-src, and worker-src directives may only have the following values:"
self
none
Any localhost source, (http://localhost, http://127.0.0.1, or any port on those domains)
So is there seriously no way for a Google Chrome extension to authenticate with a Google auth provider through Google's Firebase? The only workaround I can think of is to create some hosted site that does the authentication, have the Chrome extension inject a content script, and have the hosted site pass the auth details back to the Chrome extension through an event or something. Seems like a huge hack though and possibly subject to security flaws. Anyone else have ideas??
Although it was mentioned in the comments that this works with the Google auth provider using chrome.identity sadly there was no code example so I had to figure out myself how to do it.
Here is how I did it 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...

How to check for authenticated users on Google Cloud Function

I am building a web site and decided to go pure HTML+JS with full Firebase so I don't have to implement a backend system to test new ideas. The use case for this question is that all users should be authenticated in order to get access to the pages (pretty standard security feature, right?).
To accomplish that, I am taking advantage of Google Cloud Functions to check whether a user is signed in or not before allowing access to the pages.
Here is the code implemented on firebase.json:
"hosting": {
"rewrites": [ {
"source": "/home.html",
"function": "home"
} ]
}
Inside the home function, I run the following code to check whether the Id Token is a valid one:
admin.auth().verifyIdToken(idToken).then((decodedToken) => {
const userId = decodedToken.uid;
})
The problem I am facing is that the value for idToken is invalid:
Firebase ID token has incorrect algorithm. Expected "none" but got
"RS256"
I tried to copy & past the value from result.credential.accessToken, but I still get the same error message.
firebase.auth().getRedirectResult().then(function(result) {
if (result.credential) {
var token = result.credential.accessToken;
}
});
Any help will be very appreciated.
Thanks!
I understand that you direct the HTTPS requests to your home HTTPS Cloud Function.
You should pass the Firebase ID token as a Bearer token in the Authorization header of the HTTP request, as explained and demonstrated in the following official Cloud Function sample.

How do I serve firebase functions from a custom domain?

I have a website that I'm already running on firebase hosting using a google domain. I would like to now show all calls to my firebase function being made through a url such as api.mydomain.com, instead of the default firebase domain. How is it that I may be able to do this?
I read the firebase tutorial on hosting cloud functions, and I also came across this article on creating multiple sites. So could someone please tell how is it that I can set up the workflow such that my site is still running at mydomain.com, but my APIs are now being called through api.mydomain.com? What would be the target name for
If possible, I Would like all requests to be shown as requests to api.mydomain.com, and not to api.mydomain.com/endpoint - so that what endpoint is being hit is also hidden from public
Sorry, I am new to this.
Let's say your main project has an ID of example-app. To serve requests as api.mydomain.com, you would have to use a Cloud Function that makes use of express (or some other similar route handler).
Create the secondary site for your project using the Firebase CLI, (with an id of example-app-api, example-api, etc.)
firebase hosting:sites:create example-app-api
Connect your hosting targets to your resources
firebase target:apply hosting app example-app
firebase target:apply hosting api example-app-api
Modify your firebase.json file to suit the targets above.
{
"hosting": [
{
// app is linked to example-app, served as mydomain.com
"target": "app",
// contents of this folder are deployed to the site "example-app"
"public": "public",
// ... other settings ...
},
{
// api is linked to example-app-api, served as api.mydomain.com
"target": "api",
// Contents of this folder are deployed to the site "example-app-api"
// Any file here will be returned instead of calling your Cloud Function.
// Recommended contents:
// - favicon.ico (website icon for bookmarks, links, etc)
// - robots.txt (instructions for bots and scrapers)
// Optional contents:
// - service-worker.js (empty file, used to prevent triggering cloud function)
// - humans.txt (details about who you/your company are & how to report bugs)
"public": "api-static-resources",
// ... other settings ...
"rewrites": [
{
// redirect all calls to the function called "api"
"source": "**",
"function": "api"
}
]
}
]
}
Deploy the api hosting config using the Firebase CLI
firebase deploy --only hosting:api
Open Hosting Settings for your project, click "View" for example-app-api then click "Custom Domain" following these instructions.
You should now be able to trigger your Cloud Function by calling it at api.mydomain.com.
api.mydomain.com/getPost?id=someId
api.mydomain.com/favicon.ico
api.mydomain.com/robots.txt

Is it possible to cache Cloud Function invocation result in Firebase Hosting rewrite indepedently of the requested URL?

I'm rewriting multiple paths in Firebase Hosting to a Cloud Function that always returns the same result. I need to invoke the function once, cache its result, and return it for any subsequent requests to any of these paths. However, as the documentation states, the cached content is served based on:
The hostname
The path
The query string
The content of the request headers specified in the Vary header
So, if a different URL is requested, the function will be invoked again. But is there a way to avoid that? Setting the Cache-Control header does prevent the function from invoking again when the same URL is requested, but not when a different one is.
Here is my Hosting and Functions configuration:
firebase.json:
{
"hosting": {
"rewrites": [
{
"source": "**",
"function": "myFunction"
}
]
}
}
functions/index.ts:
import * as functions from "firebase-functions"
export const myFunction = functions.https.onRequest((req, res) => {
res.set("Cache-Control", "public, max-age=31536000")
res.send("This is a Cloud Function.")
})
The caching behavior of Firebase Hosting (and web browsers) is always dependent on the URL path.
There are a couple ways you could try to work around this, depending on your goals:
Use a redirect (for instance, to /) instead of the rewrite. The the cloud function can then serve content only on a known (and cacheable) path.
Serve a static page instead of a cloud function on every path, then have that static page use javascript to call your cloud function on a known, cached path. The initial static page wouldn't be cached, but it should be faster than a function.
The integration between Firebase Hosting and Cloud Functions/Cloud Run allows your (Cloud Functions/Cloud Run) code to control the content of the URL that was requested from Firebase Hosting.
You can modify other hosted files, but will have to call the Firebase Hosting API for this. For an example of this, see How to update a file that I deployed to Firebase Hosting?

Firebase uses cloudfunctions.net instead of hosting rewrites rules

I have set up rewrites for named functions in firebase.json but still firebase.functions().httpsCallable() envokes [my-server].cloudfunctions.net/[function-name] instead of [my-server].com/
I am upgrading a current project that has been working fine with cloudfunctions.net, but I would like to limit the domain names being called because of some firewalls blocking that domain.
Reading the guide if thought this addition in firebase.json would be sufficient:
"rewrites": [
{
"source": "/getResponse",
"function": "getResponse"
}]
and then calling the function from my app with:
firebase.functions().httpsCallable('getResponse')
...But that envokes [my-server].cloudfunctions.net/getResponse instead of [my-server].com/getResponse
Opening [my-server].com/getResponse in my browser works, so I figure, there is some sort of explicit setting on firebase.functions() where I can force it to use custom domain?
Thanks you for any help
There is no way to configure the Firebase client SDK for callable functions to invoke anything other than the default URL for the function. If this is somehow important to you, you are free to file a feature request.

Resources