Ian Jones Logo

Firebase

Installation

Documentation Link

You first have to create a firebase "app" for your project. Go to the root of your project, and click the </> icon (indicating a web application), add your app name and continue.

This is where you will get something like this as the output:

<!-- Production app creds -->
<!-- The core Firebase JS SDK is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/8.3.1/firebase-app.js"></script>

<!-- TODO: Add SDKs for Firebase products that you want to use
     https://firebase.google.com/docs/web/setup#available-libraries -->

<script>
  // Your web app's Firebase configuration
  var firebaseConfig = {
    apiKey: "random-api-key",
    authDomain: "project-name.firebaseapp.com",
    databaseURL: "https://project-name.firebaseio.com",
    projectId: "project-name",
    storageBucket: "project-name.appspot.com",
    messagingSenderId: "0000000000000",
    appId: "0:0000000000000:web:e000ab00c00c0e000a0aba"
  };
  // Initialize Firebase
  firebase.initializeApp(firebaseConfig);
</script>

You will need to copy the firebaseConfig object for later user

Meanwhile, inside of your project...

yarn add firebase

In your firebase.js file, firebase/app must be the first thing you import.

import firebase from 'firebase/app'

Document Referecnce

Documentation Link

DocumentReference is the main object you are working with.

Collection Reference

Documentation Link

A container for multiple documents. You can use a CollectionReference to add documents, query documents etc.

Firebase Authentication

You can integrate Firebase Authentication with a custom authentication system by modifying your authentication server to produce custom signed tokens when a user successfully signs in. Your app receives this token and uses it to authenticate with Firebase.

  • first you need to set up a Project service key

  • Then you have your server return a custom token when the user is valid

  • this token is then used to sign in to a firebase session

  • a user in firebase is then attatched to that authentication

api keys are not used to control access to the backend resources

Security Rules

Youtube video on security rules

Rules you write for a specific route will only apply to that route. They wont cascade down to sub routes.

You have to use a wild card {wildcard=**} to write a single rule for multiple routes. This will catch all the sub routes for that route.

There are 5 different actions you can guard against in security rules.

  • read

    • get

    • list

  • write

    • create

    • delete

    • update

You can specify them individually or you can specify all read actions (get and list) with read. You can specify all write actions (create, delete, and update) as write.

You can speficy a single resource in a security rule like this:

/users/{userId} {
  allow read, write: if userId == request.auth.uid
}

userId will reference the specific ID that is being requested.

The request object has a number of properties on it: the resource and the auth object.

Firebase Admin

The firebase-admin npm package lets you create custom auth tokens that you can use to sign into firebase auth.

First initialize the admin

if (!firebaseAdmin.apps.length) {
    firebaseAdmin.initializeApp({
      credential: firebaseAdmin.credential.cert({
        // https://stackoverflow.com/questions/50299329/node-js-firebase-service-account-private-key-wont-parse
        privateKey: FIREBASE_ADMIN_PRIVATE_KEY.replace(/\\n/g, '\n'),
        clientEmail: FIREBASE_ADMIN_CLIENT_EMAIL,
        projectId: FIREBASE_ADMIN_PROJECT_ID,
      }),
      databaseURL: `https://${FIREBASE_ADMIN_PROJECT_ID}.firebaseio.com`,
    })
  }

You can see that Im checking if an admin app already exists. You want to do this so that you dont initialize the same app again.

Next you can create the token:

const token = await firebaseAdmin
    .auth()
    .createCustomToken(eggheadUser.contact_id)
    .catch((error) => {
      console.log('Error creating custom token:', error)
    })

Here, we are creating a custom token. createCustomToken expects you to pass some guid as the first argument. This will be used as the auth.uid for that user. So its how you will identify these users in the firebase database. At egghead, we want to use a contact_id

I wrap all of this in a function because I want to be able to call it from a Next.js api function:

const generateAuthToken = async (eggheadUser) => {
   if (!firebaseAdmin.apps.length) {
    firebaseAdmin.initializeApp({
      credential: firebaseAdmin.credential.cert({
        // https://stackoverflow.com/questions/50299329/node-js-firebase-service-account-private-key-wont-parse
        privateKey: FIREBASE_ADMIN_PRIVATE_KEY.replace(/\\n/g, '\n'),
        clientEmail: FIREBASE_ADMIN_CLIENT_EMAIL,
        projectId: FIREBASE_ADMIN_PROJECT_ID,
      }),
      databaseURL: `https://${FIREBASE_ADMIN_PROJECT_ID}.firebaseio.com`,
    })
  }

  const token = await firebaseAdmin
    .auth()
    .createCustomToken(eggheadUser.contact_id)
    .catch((error) => {
      console.log('Error creating custom token:', error)
    })

  return token
}

Signing a FirebaseUser in

In the previous section, we generated a custom firebase admin token to use to sign in our user. Now we have to actually use it.

Make sure that you are importing 'firebase/auth' in the file you want to use your token in.

Heres how I initialize a firebase app with a token:

const initializeApp = async (firebaseAuthToken) => {
  if (!firebase.apps.length) {
    firebase.initializeApp(config)
  }
  const firebaseUserCredential = await firebase
    .auth()
    .signInWithCustomToken(firebaseAuthToken)
  const db = firebase.firestore()
  const usersCollectionRef = db.collection('users')
  return {db, usersCollectionRef, firebaseUserCredential}
}

You always want to check if there is an app initialized already.

Next you can use firebase.auth().signInWithCustomToken(theTokenYouGenerated) to create the session associated with that user.

Then you can do whatever firebase stuff you need to to get different collections or credentials.

Integrations

Next.js

You can use next-firebase-auth to integrate firebase auth with next serverside hooks.