CORS on firebase storage - firebase

I'm gettin the normal cors error on my firebase storage when I do a get call on an html file:
Request header field Access-Control-Allow-Origin is not allowed by Access-Control-Allow-Headers in preflight response.
I'm using axios for the call:
axios.get('https://firebasestorage.googleapis.com/v0/b/xxxxx-xxxxx.appspot.com/o/files%2Fsigning%2F148%2F459.html?alt=media&token=f3be2ef2-a598-4c30-a77b-8077e8b1f7bc',
{
headers: {'Access-Control-Allow-Origin': '*',}
)
I have the access set to public:
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write;
}
}
}
This same setup works fine when I load images but it's giving me the error for the stored html file. Any thoughts on how to fix it?

Firebase is using the same storage infrastructure as google cloud and even though there is no firebase method to set the cors rules, you can use gc set up.
First you need to install google cloud sdk:
curl https://sdk.cloud.google.com | bash
Restart your shell:
exec -l $SHELL
Initialize gcloud. This will ask you to select your account and authenticate.
gcloud init
Then create a json file with the following content
[
{
"origin": ["http://example.appspot.com"],
"responseHeader": ["Content-Type"],
"method": ["GET", "HEAD", "DELETE"],
"maxAgeSeconds": 3600
}
]
And run this with your firebase storage gc: endpoint
gsutil cors set yourFile.json gs://yourProject
That should fixe the problem for you as well.

After init the application you need to use setCorsConfiguration method
// Imports the Google Cloud client library
const {Storage} = require('#google-cloud/storage');
// Creates a client
const storage = new Storage();
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
// The ID of your GCS bucket
// const bucketName = 'your-unique-bucket-name';
// The origin for this CORS config to allow requests from
// const origin = 'http://example.appspot.com';
// The response header to share across origins
// const responseHeader = 'Content-Type';
// The maximum amount of time the browser can make requests before it must
// repeat preflighted requests
// const maxAgeSeconds = 3600;
// The name of the method
// See the HttpMethod documentation for other HTTP methods available:
// https://cloud.google.com/appengine/docs/standard/java/javadoc/com/google/appengine/api/urlfetch/HTTPMethod
// const method = 'GET';
async function configureBucketCors() {
await storage.bucket(bucketName).setCorsConfiguration([
{
maxAgeSeconds,
method: [method],
origin: [origin],
responseHeader: [responseHeader],
},
]);
console.log(`Bucket ${bucketName} was updated with a CORS config
to allow ${method} requests from ${origin} sharing
${responseHeader} responses across origins`);
}
configureBucketCors().catch(console.error);
This is my example with NestJs
import { ConfigService } from '#nestjs/config';
import * as admin from 'firebase-admin';
const configureBucketCors = async (app) => {
const configService: ConfigService = app.get(ConfigService);
return admin
.storage()
.bucket(configService.get<string>('BUCKET_NAME'))
.setCorsConfiguration([
{
origin: ['http://localhost:3000'],
responseHeader: ['Content-Type'],
method: ['GET', 'HEAD', 'DELETE'],
maxAgeSeconds: 3600,
},
]);
};
export default async (app) => {
const configService: ConfigService = app.get(ConfigService);
await admin.initializeApp({
databaseURL: configService.get<string>('FIREBASE_DATABASE_URL'),
storageBucket: configService.get<string>('BUCKET_NAME'),
});
await configureBucketCors(app);
};
Check the docs for more details
https://cloud.google.com/storage/docs/cross-origin
https://cloud.google.com/storage/docs/configuring-cors#storage_cors_configuration-nodejs

Related

Firebase functions run in one firebase project but giving internal error in the other

I have two firebase accounts one used for development(D) and the other for production(P). My development(D) firestore and functions run on us-central1. On production(P) firestore location is asia-south1 and functions run on us-central1
My firebase functions run properly in development (D) but are giving me the following error in production. Further, when I check the logs on the firebase functions console, there does not seem to be any activity. It appears as if the function has not been called.
Error returned by firebase function is :
Function call error Fri Apr 09 2021 09:25:32 GMT+0530 (India Standard Time)with{"code":"internal"}
Further the client is also displaying this message :
Access to fetch at 'https://us-central1-xxx.cloudfunctions.net/gpublish' from origin 'https://setmytest.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. zone-evergreen.js:1052 POST https://us-central1-xxx.cloudfunctions.net/gpublish net::ERR_FAILED
Here is the code from my angular app calling the function -
const process = this.fns.httpsCallable("gpublish");
process(data).subscribe(
(result) => {
console.log("function responded with result: " + JSON.stringify(result));
},
(err) => {
const date1 = new Date();
console.log("Function call error " + date1.toString() + "with" + JSON.stringify(err));
});
Here are the functions -
index.ts
import { gpublish } from "./gpublish/gpublish";
import { sendEmail } from "./sendEmail";
export {gpublish,sendEmail };
gpublish.ts
import * as functions from "firebase-functions";
const fs = require("fs");
const { google } = require("googleapis");
const script = google.script("v1");
const scriptId = "SCRIPT_ID";
const googleAuth = require("google-auth-library");
import { admin } from "../admin";
const db = admin.firestore();
export const gpublish = functions.https.onCall(async (data: any, res: any) => {
try {
const googleTest = data.test;
console.log("Publishing to google test of name " + googleTest.testName);
// read the credentials and construct the oauth client
const content = await fs.readFileSync("gapi_credentials.json");
const credentials = JSON.parse(content); // load the credentials
const { client_secret, client_id, redirect_uris } = credentials.web;
const functionsOauth2Client = new googleAuth.OAuth2Client(client_id,client_secret, redirect_uris); // Constuct an auth client
functionsOauth2Client.setCredentials({refresh_token: credentials.refresh_token}); // Authorize a client with credentials
// run the script
return runScript(functionsOauth2Client,scriptId,JSON.stringify(googleTest)
).then((scriptData: any) => {
console.log("Script data is" + JSON.stringify(scriptData));
sendEmail(googleTest, scriptData);
return JSON.stringify(scriptData);
});
} catch (err) {
return JSON.stringify(err);
}
});
function runScript(auth: any, scriptid: string, test: any) {
return new Promise(function (resolve, reject) {
script.scripts
.run({auth: auth,scriptId: scriptid, resource: {function: "doGet", devMode: true,parameters: test }
})
.then((respons: any) => { resolve(respons.data);})
.catch((error: any) => {reject(error);});
});
}
I have changed the service account key and google credentials correctly when deploying the functions in development and in production.
I have tried many things including the following:
Enabling CORS in Cloud Functions for Firebase
Google Cloud Functions enable CORS?
The function is running perfectly in Development firebase project but not in Production firebase project. Please help!
You need to check that your function has been deployed correctly.
A function that doesn't exist (404 Not Found) or a function that can't be accessed (403 Forbidden) will both give that error as the Firebase Function is never executed, which means the correct CORS headers are never sent back to the client.

How to pull in Heroku postgres credentials for next-auth?

I'm trying to use a postgres instance on Heroku with Next-Auth.js Heroku's documentation notes that the credentials shouldn't be hardcoded into the application; so, I'm trying to use Heroku's api to pull in the needed url. My issue - I think - is when I try to run the axios request asynchronously, the value of the return statement isn't being assigned to the database property of the options object. What am I doing wrong? Many thanks!
import NextAuth from "next-auth";
import Providers from "next-auth/providers";
const axios = require("axios");
// Heroku api key and postgres instance
const herokuApiKey = PROCESS.ENV.API_KEY;
const herokuPostgres = PROCESS.ENV.POSTGRES_INSTANCE;
// Connection to Heroku API
const herokuApi = axios.create({
baseURL: `https://api.heroku.com`,
headers: {
Authorization: `Bearer ${herokuApiKey}`,
Accept: "application/vnd.heroku+json; version=3",
},
});
// Async function to get database string
const getCredentials = async () => {
const response = await herokuApi.get(`addons/${herokuPostgres}/config`);
const pgConnStr = response.data[0].value; // Logging this value displays the needed string
return pgConnStr;
};
export default async (req, res) => NextAuth(req, res, {
providers: [
Providers.Email({
server: process.env.EMAIL_SERVER,
from: process.env.EMAIL_FROM,
}),
],
database: getCredentials(),
});
Your getCredentials is an async function, meaning it returns a promise. As such you'll need to await for it.
database: await getCredentials()

Angular Front - NEST JS on Cloud Functions - has been blocked by CORS policy: No 'Access-Control-Allow-Origin'

I have a forehead in ANGULAR - IONIC.
I have an API with NESTJS.
I hosted the API on the cloud functions of firebase with this tutorial: https://www.youtube.com/watch?v=IVy3Tm8iHQ0&ab_channel=Fireship
When I run the API locally (npm a start) it works perfectly!
I have a system for the cors which is the following (stored in main.ts):
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const options = new DocumentBuilder()
.setTitle('MY WEB API')
.setDescription('READ ONLY')
.setVersion('1.0')
.addTag('TAG')
.build();
const document = SwaggerModule.createDocument(app, options);
SwaggerModule.setup('api', app, document);
app.use(helmet());
const whitelist = ['http://localhost:8100/', 'http://localhost:8100', '*'];
app.enableCors({
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
console.log('allowed cors for:', origin);
callback(null, true);
} else {
console.log('blocked cors for:', origin);
callback(new Error('Not allowed by CORS'));
}
},
allowedHeaders:
'X-Requested-With, X-HTTP-Method-Override, Content-Type, Accept, Observe',
methods: 'GET, OPTIONS',
credentials: true,
});
await app.listen(3000);
}
bootstrap();
Unfortunately when I run the api on the firebase environment (firebase serve --only functions) I get the following error:
(I checked, I can use it well with Postman)
I have tried many things to fix that:
Directly from the controller
#Get('ByName')
#Header('Access-Control-Allow-Origin', 'https://localhost:8100')
async findByName(#Query('name') name: string) {
return await this.personnesService.findByName(name);
}
Desactivate the cors
const app = await NestFactory.create(AppModule, {
logger: console,
cors: false,
});
Activate them like that
const app = await NestFactory.create(AppModule);
const corsOptions = {
methods: 'GET',
preflightContinue: true,
optionsSuccessStatus: 204,
credentials: true,
origin: ['http://localhost:8100/', 'http://localhost:8100'],
};
app.enableCors(corsOptions);
I've checked on the cloud functions, the code is up to date (you never know!) and the requests arrive well.
In fact, when I launch the request and I get the error, the API still executes the request (a console.log in the API allows to check it) but doesn't seem to return the result, from what I understand because of the cors.
In reality, it doesn't go through the main.ts either since this console.log doesn't appear. I don't know how to make it go through there.
How can I activate the cors (or deactivate them?) so I don't get the error anymore?
Some information about my versions:
NESTJS API :
"#nestjs/common": "^7.5.1",
"firebase-functions": "^3.13.0",
"#types/express": "^4.17.8",
"typescript": "^4.0.5
"node": "12"
My FRONT:
"#angular/common": "~10.0.0",
"#angular/core": "~10.0.0",
"ts-node": "~8.3.0",
"typescript": "~3.9.5"
I now understand my mistake. My configuration is correct, but it's not in the right place to make it work in production!
In a classic NESTJS application, the main.ts is used to launch the application. In my case, having followed this tutorial https://fireship.io/snippets/setup-nestjs-on-cloud-functions/, the index.ts replaces the main.ts.
So the solution is to move my configuration to the index.ts!
Here is my new function.
const server = express();
export const createNestServer = async (expressInstance) => {
const app = await NestFactory.create(
AppModule,
new ExpressAdapter(expressInstance),
);
const corsOptions = {
methods: 'GET',
preflightContinue: true,
optionsSuccessStatus: 204,
credentials: true,
origin: ['http://localhost:8100/', 'http://localhost:8100'],
};
app.enableCors(corsOptions);
return app.init();
};
createNestServer(server)
.then((v) => console.log('Nest Ready'))
.catch((err) => console.error('Nest broken', err));
export const api = functions.https.onRequest(server);
Don't forget to build before relaunching!
npm run build
firebase serve --only functions
firebase deploy --only functions

Cloud Vision: Credentials issues

I am attempting to setup Cloud Vision on my local machine in a Firebase project but I am encountering problems with the default credentials.
First, I encountered Could not load the default credentials. This post suggested that I do gcloud auth application-default login. Upon attempting that, I encountered this:
Error: 7 PERMISSION_DENIED: Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the vision.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.
I also attempted exports GOOGLE_APPLICATION_CREDENTIALS = "pathToServiceAccount" but it didn't work in my case.
Note that I have no issue reading/writing data to Firestore and Firebase Storage. The moment my code hits the Cloud Vision part, it throws the error. I have activated the API on cloud console and enabled billing. Security rules in firestore and storage are in testing mode at this moment.
const vision = require('#google-cloud/vision');
var admin = require('firebase-admin');
let serviceAccount = require('../path-to-service-account.json');
admin.initializeApp({
credential: admin.credential.cert(serviceAccount),
storageBucket: "mybucket.appspot.com"
});
let db = admin.firestore()
let bucket = admin.storage().bucket();
//Some networking code, return a promise
.then(response => {
//setup storagePath
return pipeToStorage(item, response, storagePath) //Save to firebase storage ok
})
.then((item) => {
return performTextDetection(item.id) //Throws error here
})
function pipeToStorage(item, response, storagePath) {
return new Promise((resolve, reject) => {
gcFile = bucket.file(storagePath)
response.data
.pipe(gcFile.createWriteStream({
metadata : {
contentType: "application/pdf"
}
}))
.on('error', (error) => {
reject(error)
})
.on('finish', () => {
resolve(item)
})
})
}
function performTextDetection(id) {
const client = new vision.ImageAnnotatorClient();
const bucketName = bucket.name;
const fileName = `items/${id}.pdf`
const outputPrefix = 'ocr_results'
const gcsSourceUri = `gs://${bucketName}/${fileName}`;
const gcsDestinationUri = `gs://${bucketName}/${outputPrefix}/${id}/`;
const inputConfig = {
mimeType: 'application/pdf',
gcsSource: {
uri: gcsSourceUri,
},
};
const outputConfig = {
gcsDestination: {
uri: gcsDestinationUri,
},
};
const features = [{type: 'DOCUMENT_TEXT_DETECTION'}];
const request = {
requests: [
{
inputConfig: inputConfig,
features: features,
outputConfig: outputConfig,
},
],
};
return client.asyncBatchAnnotateFiles(request)
.then(([operation]) => {
return operation.promise()
})
.then(([filesResponse]) => {
const resultsUri = filesResponse.responses[0].outputConfig.gcsDestination.uri
return resultsUri
})
}
This happens because you have exports rather than export:
exports GOOGLE_APPLICATION_CREDENTIALS = "pathToServiceAccount"
please try:
export GOOGLE_APPLICATION_CREDENTIALS="/home/user/credentials.json"
note that there are not spaces, see details here. By the way, I have also found the same PERMISSION_DENIED error when export is omitted.
The validation step is executing a REST request with curl:
curl -X POST \
-H "Authorization: Bearer "$(gcloud auth application-default print-access-token) \
-H "Content-Type: application/json; charset=utf-8" \
-d #request.json \
https://vision.googleapis.com/v1/images:annotate
See the complete example here.

How to protect firebase Cloud Function HTTP endpoint to allow only Firebase authenticated users?

With the new firebase cloud function I've decided to move some of my HTTP endpoint to firebase.
Everything works great... But i have the following issue. I have two endpoints build by HTTP Triggers (Cloud Functions)
An API endpoint to create users and returns the custom Token
generated by Firebase Admin SDK.
An API endpoint to fetch certain user details.
While the first endpoint is fine, but for my second end point i would want to protect it for authenticated users only. meaning someone who has the token i generated earlier.
How do i go about solving this?
I know we can get the Header parameters in the cloud function using
request.get('x-myheader')
but is there a way to protect the endpoint just like protecting the real time data base?
There is an official code sample for what you're trying to do. What it illustrates is how to set up your HTTPS function to require an Authorization header with the token that the client received during authentication. The function uses the firebase-admin library to verify the token.
Also, you can use "callable functions" to make a lot of this boilerplate easier, if your app is able to use Firebase client libraries.
As mentioned by #Doug, you can use firebase-admin to verify a token. I've set up a quick example:
exports.auth = functions.https.onRequest((req, res) => {
cors(req, res, () => {
const tokenId = req.get('Authorization').split('Bearer ')[1];
return admin.auth().verifyIdToken(tokenId)
.then((decoded) => res.status(200).send(decoded))
.catch((err) => res.status(401).send(err));
});
});
In the example above, I've also enabled CORS, but that's optional. First, you get the Authorization header and find out the token.
Then, you can use firebase-admin to verify that token. You'll get the decoded information for that user in the response. Otherwise, if the token isn't valid, it'll throw an error.
As also mentioned by #Doug,
you can use Callable Functions in order to exclude some boilerplate code from your client and your server.
Example callable function:
export const getData = functions.https.onCall((data, context) => {
// verify Firebase Auth ID token
if (!context.auth) {
return { message: 'Authentication Required!', code: 401 };
}
/** This scope is reachable for authenticated users only */
return { message: 'Some Data', code: 200 };
});
It can be invoked directly from you client like so:
firebase.functions().httpsCallable('getData')({query}).then(result => console.log(result));
The above methods authenticate the user using logic inside the function, so the function must be still be invoked to do the checking.
That's a totally fine method, but for the sake of comprehensivity, there is an alternative:
You can set a function to be "private" so that it can't be invoked except by registered users (you decide on permissions). In this case, unauthenticated requests are denied outside the context of the function, and the function is not invoked at all.
Here are references to (a) Configuring functions as public/private, and then (b) authenticating end-users to your functions.
Note that the docs above are for Google Cloud Platform, and indeed, this works because every Firebase project is also a GCP project. A related caveat with this method is that, as of writing, it only works with Google-account based authentication.
In Firebase, in order to simplify your code and your work, it's just a matter of architectural design:
For public accessible sites/contents, use HTTPS triggers with Express. To restrict only samesite or specific site only, use CORS to control this aspect of security. This make sense because Express is useful for SEO due to its server-side rendering content.
For apps that require user authentication, use HTTPS Callable Firebase Functions, then use the context parameter to save all the hassles. This also makes sense, because such as a Single Page App built with AngularJS -- AngularJS is bad for SEO, but since it's a password protected app, you don't need much of the SEO either. As for templating, AngularJS has built-in templating, so no need for sever-side template with Express. Then Firebase Callable Functions should be good enough.
With the above in mind, no more hassle and make life easier.
There is a lot of great information here that really helped me, but I thought it might be good to break down a simple working example for anyone using Angular attempting this for the first time. The Google Firebase documentation can be found at https://firebase.google.com/docs/auth/admin/verify-id-tokens#web.
//#### YOUR TS COMPONENT FILE #####
import { Component, OnInit} from '#angular/core';
import * as firebase from 'firebase/app';
import { YourService } from '../services/yourservice.service';
#Component({
selector: 'app-example',
templateUrl: './app-example.html',
styleUrls: ['./app-example.scss']
})
export class AuthTokenExample implements OnInit {
//property
idToken: string;
//Add your service
constructor(private service: YourService) {}
ngOnInit() {
//get the user token from firebase auth
firebase.auth().currentUser.getIdToken(true).then((idTokenData) => {
//assign the token to the property
this.idToken = idTokenData;
//call your http service upon ASYNC return of the token
this.service.myHttpPost(data, this.idToken).subscribe(returningdata => {
console.log(returningdata)
});
}).catch((error) => {
// Handle error
console.log(error);
});
}
}
//#### YOUR SERVICE #####
//import of http service
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { Observable } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class MyServiceClass {
constructor(private http: HttpClient) { }
//your myHttpPost method your calling from your ts file
myHttpPost(data: object, token: string): Observable<any> {
//defining your header - token is added to Authorization Bearer key with space between Bearer, so it can be split in your Google Cloud Function
let httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
})
}
//define your Google Cloud Function end point your get from creating your GCF
const endPoint = ' https://us-central1-your-app.cloudfunctions.net/doSomethingCool';
return this.http.post<string>(endPoint, data, httpOptions);
}
}
//#### YOUR GOOGLE CLOUD FUNCTION 'GCF' #####
//your imports
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({origin: true});
exports.doSomethingCool = functions.https.onRequest((req, res) => {
//cross origin middleware
cors(req, res, () => {
//get the token from the service header by splitting the Bearer in the Authorization header
const tokenId = req.get('Authorization').split('Bearer ')[1];
//verify the authenticity of token of the user
admin.auth().verifyIdToken(tokenId)
.then((decodedToken) => {
//get the user uid if you need it.
const uid = decodedToken.uid;
//do your cool stuff that requires authentication of the user here.
//end of authorization
})
.catch((error) => {
console.log(error);
});
//end of cors
})
//end of function
})
There is a nice official example on it using Express - may be handy in future: https://github.com/firebase/functions-samples/blob/master/authorized-https-endpoint/functions/index.js (pasted below just for sure)
Keep in mind that exports.app makes your functions available under /app slug (in this case there is only one function and is available under <you-firebase-app>/app/hello. To get rid of it you actually need to rewrite Express part a bit (middleware part for validation stays the same - it works very good and is quite understandable thanks to comments).
/**
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const express = require('express');
const cookieParser = require('cookie-parser')();
const cors = require('cors')({origin: true});
const app = express();
// Express middleware that validates Firebase ID Tokens passed in the Authorization HTTP header.
// The Firebase ID token needs to be passed as a Bearer token in the Authorization HTTP header like this:
// `Authorization: Bearer <Firebase ID Token>`.
// when decoded successfully, the ID Token content will be added as `req.user`.
const validateFirebaseIdToken = async (req, res, next) => {
console.log('Check if request is authorized with Firebase ID token');
if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) &&
!(req.cookies && req.cookies.__session)) {
console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
'Make sure you authorize your request by providing the following HTTP header:',
'Authorization: Bearer <Firebase ID Token>',
'or by passing a "__session" cookie.');
res.status(403).send('Unauthorized');
return;
}
let idToken;
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
console.log('Found "Authorization" header');
// Read the ID Token from the Authorization header.
idToken = req.headers.authorization.split('Bearer ')[1];
} else if(req.cookies) {
console.log('Found "__session" cookie');
// Read the ID Token from cookie.
idToken = req.cookies.__session;
} else {
// No cookie
res.status(403).send('Unauthorized');
return;
}
try {
const decodedIdToken = await admin.auth().verifyIdToken(idToken);
console.log('ID Token correctly decoded', decodedIdToken);
req.user = decodedIdToken;
next();
return;
} catch (error) {
console.error('Error while verifying Firebase ID token:', error);
res.status(403).send('Unauthorized');
return;
}
};
app.use(cors);
app.use(cookieParser);
app.use(validateFirebaseIdToken);
app.get('/hello', (req, res) => {
res.send(`Hello ${req.user.name}`);
});
// This HTTPS endpoint can only be accessed by your Firebase Users.
// Requests need to be authorized by providing an `Authorization` HTTP header
// with value `Bearer <Firebase ID Token>`.
exports.app = functions.https.onRequest(app);
My rewrite to get rid of /app:
const hello = functions.https.onRequest((request, response) => {
res.send(`Hello ${req.user.name}`);
})
module.exports = {
hello
}
I have been struggling to get proper firebase authentication in golang GCP function. There is actually no example for that, so I decided to build this tiny library: https://github.com/Jblew/go-firebase-auth-in-gcp-functions
Now you can easily authenticate users using firebase-auth (which is distinct from gcp-authenticated-functions and is not directly supported by the identity-aware-proxy).
Here is an example of using the utility:
import (
firebaseGcpAuth "github.com/Jblew/go-firebase-auth-in-gcp-functions"
auth "firebase.google.com/go/auth"
)
func SomeGCPHttpCloudFunction(w http.ResponseWriter, req *http.Request) error {
// You need to provide 1. Context, 2. request, 3. firebase auth client
var client *auth.Client
firebaseUser, err := firebaseGcpAuth.AuthenticateFirebaseUser(context.Background(), req, authClient)
if err != nil {
return err // Error if not authenticated or bearer token invalid
}
// Returned value: *auth.UserRecord
}
Just keep in mind to deploy you function with --allow-unauthenticated flag (because firebase authentication occurs inside function execution).
Hope this will help you as it helped me. I was determined to use golang for cloud functions for performance reasons — Jędrzej
You can take this as a functions returns boolean. If the user verified or not then you will continue or stop your API. In Addition you can return claims or user result from the variable decode
const authenticateIdToken = async (
req: functions.https.Request,
res: functions.Response<any>
) => {
try {
const authorization = req.get('Authorization');
if (!authorization) {
res.status(400).send('Not Authorized User');
return false;
}
const tokenId = authorization.split('Bearer ')[1];
return await auth().verifyIdToken(tokenId)
.then((decoded) => {
return true;
})
.catch((err) => {
res.status(401).send('Not Authorized User')
return false;
});
} catch (e) {
res.status(400).send('Not Authorized User')
return false;
}
}

Resources