Skip to content

Instantly share code, notes, and snippets.

Forked from CodingDoug/
Created August 3, 2020 09:41
Show Gist options
  • Save fer-ri/6a77411592ead6b2a66831377a6d30e6 to your computer and use it in GitHub Desktop.
Save fer-ri/6a77411592ead6b2a66831377a6d30e6 to your computer and use it in GitHub Desktop.
Patterns for security with Firebase Authentication: offload work to Cloud Functions

This is the runnable sample code from the blog post Patterns for security with Firebase Authentication: offload work to Cloud Functions. It discusses offloading work from a client app to Cloud Functions using an authentication trigger.

  1. Create a new Firebase project
  2. Enable email/password authentication
  3. Provision Cloud Firestore and apply the rules given in this gist
  4. Use the Firebase CLI to create a workspace for Functions using TypeScript
  5. Deploy the given HTML and JavaScript to Firebase Hosting (the CLI emulator will also work).
  6. Deploy the function code to Cloud Functions using the Firebase CLI
  7. Load up the page and create an account. See how it’s able to immediately respond to the new document being created by the deployed auth trigger.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{uid} {
allow read: if request.auth.uid == uid;
import * as functions from 'firebase-functions'
import * as admin from 'firebase-admin'
const firestore = admin.firestore()
export const authOnCreate =
functions.auth.user().onCreate(async user => {
console.log(`Creating document for user ${user.uid}`)
await firestore.collection('users').doc(user.uid).set({
createdAt: admin.firestore.FieldValue.serverTimestamp(),
credits: 5
export const authOnDelete =
functions.auth.user().onDelete(async user => {
console.log(`Deleting document for user ${user.uid}`)
await firestore.collection('users').doc(user.uid).delete()
<!DOCTYPE html>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Firebase Auth / Security Rules / Functions demo</title>
<script defer src="/__/firebase/6.6.1/firebase-app.js"></script>
<script defer src="/__/firebase/6.6.1/firebase-auth.js"></script>
<script defer src="/__/firebase/6.6.1/firebase-firestore.js"></script>
<script defer src="/__/firebase/init.js"></script>
<script defer src="index.js"></script>
<h1>Create new user</h1>
<form id="form">
<div>Email address:</div>
<div><input id="email" name="email" type="email"/></div>
<div style="margin-top: .5em">Password:</div>
<div><input id="password" name="password" type="password"/></div>
<div style="margin-top: .5em"><input type="submit"/></div>
<div style="margin-top: 1em">Progress:</div>
<pre id="progress"></pre>
document.addEventListener('DOMContentLoaded', () => {
const formEl = document.getElementById("form")
const emailEl = document.getElementById("email")
const passwordEl = document.getElementById("email")
const progressEl = document.getElementById("progress")
formEl.addEventListener("submit", async event => {
const email = emailEl.value
const password = passwordEl.value
try {
const userCredential = await firebase.auth().createUserWithEmailAndPassword(email, password)
const uid = userCredential.user.uid
showProgressMessage(`User account ${uid} created`)
// Wait until document is created by Cloud Functions code
const userDocRef = firebase.firestore().collection('users').doc(uid)
const unsubscribe = userDocRef.onSnapshot({
next: snapshot => {
showProgressMessage('User document created')
error: error => {
catch (error) {
function clearProgress() {
progressEl.innerText = ''
function showProgressMessage(message) {
progressEl.innerText += message + "\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment