Skip to content

Instantly share code, notes, and snippets.

@CodingDoug
Last active July 11, 2023 14:04
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save CodingDoug/c0f782ad2e7e91933f8b5ffc53af55ad to your computer and use it in GitHub Desktop.
Save CodingDoug/c0f782ad2e7e91933f8b5ffc53af55ad 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'
admin.initializeApp()
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>
<html>
<head>
<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>
</head>
<body>
<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>
</form>
<div style="margin-top: 1em">Progress:</div>
<pre id="progress"></pre>
</body>
</html>
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 => {
event.preventDefault()
clearProgress()
const email = emailEl.value
const password = passwordEl.value
try {
const userCredential = await firebase.auth().createUserWithEmailAndPassword(email, password)
console.log(userCredential)
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')
unsubscribe()
},
error: error => {
console.log(error)
showProgressMessage(error.message)
unsubscribe()
}
})
}
catch (error) {
console.log(error)
showProgressMessage(error.message)
}
})
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