Skip to content

Instantly share code, notes, and snippets.

@CodingDoug
Last active July 11, 2023 14:04
Show Gist options
  • Save CodingDoug/c0f782ad2e7e91933f8b5ffc53af55ad to your computer and use it in GitHub Desktop.
Save CodingDoug/c0f782ad2e7e91933f8b5ffc53af55ad to your computer and use it in GitHub Desktop.

Revisions

  1. CodingDoug revised this gist Sep 18, 2019. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -10,4 +10,4 @@ It discusses offloading work from a client app to Cloud Functions using an authe
    1. Deploy the function code to Cloud Functions using the Firebase CLI
    1. 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.

    [1]: TODO
    [1]: https://medium.com/@CodingDoug/patterns-for-security-with-firebase-offload-client-work-to-cloud-functions-7c420710f07?source=friends_link&sk=35865241b7722504ea2802ae0977c062
  2. CodingDoug created this gist Sep 16, 2019.
    13 changes: 13 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,13 @@
    This is the runnable sample code from the blog post
    [Patterns for security with Firebase Authentication: offload work to Cloud Functions][1].
    It discusses offloading work from a client app to Cloud Functions using an authentication trigger.

    1. Create a new Firebase project
    1. Enable email/password authentication
    1. Provision Cloud Firestore and apply the rules given in this gist
    1. Use the Firebase CLI to create a workspace for Functions using TypeScript
    1. Deploy the given HTML and JavaScript to Firebase Hosting (the CLI emulator will also work).
    1. Deploy the function code to Cloud Functions using the Firebase CLI
    1. 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.

    [1]: TODO
    10 changes: 10 additions & 0 deletions firestore.rules
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    rules_version = '2';
    service cloud.firestore {
    match /databases/{database}/documents {

    match /users/{uid} {
    allow read: if request.auth.uid == uid;
    }

    }
    }
    20 changes: 20 additions & 0 deletions functions.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,20 @@
    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()
    })
    29 changes: 29 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,29 @@
    <!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>
    46 changes: 46 additions & 0 deletions index.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,46 @@
    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"
    }

    })