DEV Community

Pacharapol Withayasakpunt
Pacharapol Withayasakpunt

Posted on • Edited on

8 3

Firebase auth with both frontend (SPA) and backend

auth0-spa-js with express-jwt is not the only way.

Also, firebase offers not only database and authentication, but also analytics and blob storage.

Frontend

npm i firebase
Enter fullscreen mode Exit fullscreen mode
import firebase from 'firebase/app'

import 'firebase/analytics'
import 'firebase/auth'

firebase.initializeApp(require('../firebase.config.js'))

let isAuthReady = false

firebase.auth().onAuthStateChanged((user) => {
  store.commit('setUser', user)

  if (!isAuthReady) {
    isAuthReady = true
    new Vue({
      router,
      store,
      render: (h) => h(App),
    }).$mount('#app')
  }
})
Enter fullscreen mode Exit fullscreen mode
import Vue from 'vue'
import Vuex from 'vuex'
import axios from 'axios'
import { User } from 'firebase/app'
import { SnackbarProgrammatic as Snackbar, LoadingProgrammatic as Loading } from 'buefy'

Vue.use(Vuex)

let loading: {
  close(): any
  requestEnded?: boolean
} | null = null

const store = new Vuex.Store({
  state: {
    user: null as User | null,
  },
  mutations: {
    setUser (state, user) {
      state.user = user
    },
    removeUser (state) {
      state.user = null
    },
  },
  actions: {
    async getApi ({ state }, silent) {
      const api = axios.create()

      if (state.user) {
        api.defaults.headers.Authorization = `Bearer ${await state.user.getIdToken()}`
      }

      if (!silent) {
        api.interceptors.request.use((config) => {
          if (!loading) {
            loading = Loading.open({
              isFullPage: true,
              canCancel: true,
              onCancel: () => {
                if (loading && !loading.requestEnded) {
                  Snackbar.open('API request is loading in background.')
                }
              },
            })
          }

          return config
        })

        api.interceptors.response.use((config) => {
          if (loading) {
            loading.requestEnded = true
            loading.close()
            loading = null
          }

          return config
        }, (err) => {
          if (loading) {
            loading.close()
            loading = null
          }

          Snackbar.open(err.message)
          return err
        })
      }

      return api
    },
  },
})

export default store
Enter fullscreen mode Exit fullscreen mode

Backend

npm i firebase-admin
Enter fullscreen mode Exit fullscreen mode

I use Fastify, but it can easily be framework-agnostic, or even language-agnostic.

import { FastifyInstance } from 'fastify'
import fSession from 'fastify-session'
import fCoookie from 'fastify-cookie'
import admin from 'firebase-admin'

admin.initializeApp({
  credential: admin.credential.cert(require('../../firebase-key.json')),
  databaseURL: 'https://<YOUR_PROJECT_NAME>.firebaseio.com',
})

const router = (f: FastifyInstance, opts: any, next: () => void) => {
  f.register(fCoookie)
  f.register(fSession, { secret: process.env.SECRET! })

  f.addHook('preHandler', async (req, reply, done) => {
    try {
      if (req.req.url && req.req.url.startsWith('/api/doc')) {
        return done()
      }

      const m = /^Bearer (.+)$/.exec(req.headers.authorization || '')

      if (!m) {
        reply.status(401).send()
        return
      }

      const ticket = await admin.auth().verifyIdToken(m[1], true)

      req.session.user = ticket
      if (!db.user) {
        await db.signIn(ticket.email)
      }

      done()
    } catch (e) {
      done(e)
    }
  })

  f.register(apiRouter)
  next()
}

export default router
Enter fullscreen mode Exit fullscreen mode

Conclusion

Firebase, along with a NoSQL (maybe firestore) or SQL, could be a fine choice for web apps with

  • Authentication
  • Upload
  • Database

However, in my eyes, I am not really sure about offline capabilities, even with PWA; unless I resort to Electron.

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay