--- outline: deep --- # Firebase [Firebase](https://firebase.google.com/docs/auth) requires a custom [OAuth Authentication Strategy](../../api/authentication/oauth.html#oauthstrategy). This is because one is not provided to us, by the default [Grant](https://github.com/simov/grant) configuration Feathers uses for [OAuth](https://docs.feathersjs.com/api/authentication/oauth.html#oauth). Since Firebase does not provide a UI for us to redirect to, we use flow #2 outlined in [OAuth Flow](../../api/authentication/oauth.html#flow). ## Authentation Setup Update `config/default.json`: ```json { "authentication": { "oauth": {} }, "firebase": { "type": "THIS SHOULD BE YOUR SERVICE ACCOUNT", "project_id": "GENERATED UNDER FIREBASE CONSOLE", "...": "..." } } ``` > Note: Since Firebase can be used for more than just authentication, we'll store our service account in the root of our config. Otherwise, if preferred, you can store under `authentication.oauth`. ## Authentication Strategy Create a file under `src/firebase.js`: ```js const firebase = require('firebase-admin'); const { OAuthStrategy } = require('@feathersjs/authentication-oauth'); const { NotAuthenticated } = require('@feathersjs/errors'); const logger = require('./logger'); function initialize(app){ const firebaseConfig = app.get('firebase'); // Initialize app try { firebase.initializeApp({ credential: firebase.credential.cert(firebaseConfig) }); } catch (e) { console.log('erorr initializing firebase', e); } } class FirebaseStrategy extends OAuthStrategy { async authenticate(authentication, params){ logger.debug('firebase:strategy:authenticate'); return super.authenticate(authentication, params); } async getProfile(data, _params){ const firebase = require('firebase-admin'); let user; try { user = await firebase.auth().verifyIdToken(data.access_token); } catch(e){ logger.error(e); throw new NotAuthenticated(); } logger.debug(`firebase:strategy:getProfile:successful ${user.user_id}`); return { email: user.email, id: user.user_id }; } async getEntityData(profile) { const baseData = await super.getEntityData(profile); return { ...baseData, email: profile.email }; } } module.exports = { initialize, FirebaseStrategy }; ``` Now we can edit `src/authentication.js` ```js const { AuthenticationService, JWTStrategy } = require('@feathersjs/authentication'); const { expressOauth } = require('@feathersjs/authentication-oauth'); const { FirebaseStrategy } = require('./firebase'); module.exports = app => { const authentication = new AuthenticationService(app); authentication.register('firebase', new FirebaseStrategy()); app.use('/authentication', authentication); app.configure(expressOauth()); }; ``` ## Building frontend To save time, you can leverage the pre-built UI provided by [Firebase UI](https://firebase.google.com/docs/auth/web/firebaseui). ### Create auth page First, create a `public/firebase_auth.html` file that initializes everything we'll need for our different auth components. ```html Firebase Authentication Example

Welcome to My Awesome App

``` ### Initialize client w/Firebase auth Now, let's make a `public/client.js` file where all of our JavaScript will live. > Be sure to update `firebaseConfig` with the one provided from your [Firebase Console](https://console.firebase.google.com/). Additionally, checkout [Firebase UI](https://firebase.google.com/docs/auth/web/firebaseui) docs for more information on customizing `ui.start`. This includes theming options, all providers supported by Firebase & more. ```js let client, ui; init(); function init(){ initializeFeathers(); initializeAuth(); initializeFirebase(); } function initializeFeathers(){ // Establish a Socket.io connection const socket = io(); // Initialize our Feathers client application through Socket.io // with hooks and authentication. client = feathers(); client.configure(feathers.socketio(socket)); // Use localStorage to store our login token client.configure(feathers.authentication()); } // Either re-authenticate existing session, or start Firebase UI async function initializeAuth(){ try { await client.reAuthenticate(); showMemberApp(); } catch(e){ // Error re-authenticating, so let's start Firebase UI showGuestApp(); } // No longer need to prepare anything document.getElementById('app-preparing').style.display = 'none'; } function initializeFirebase(){ // Your web app's Firebase configuration // For Firebase JS SDK v7.20.0 and later, measurementId is optional var firebaseConfig = { // Copy this from your Firebase Console // Under Project Settings -> Web App }; // Initialize Firebase firebase.initializeApp(firebaseConfig); // Initialize the FirebaseUI Widget using Firebase. ui = new firebaseui.auth.AuthUI(firebase.auth()); } async function showMemberApp(){ // Get user information const { user } = await client.get('authentication'); // Hide Guest App document.getElementById('app-guest').style.display = 'none'; // Show member app document.getElementById('app-member').style.display = 'block'; document.getElementById('app-member').innerHTML = `Logged in as, ${user.email}. Logout`; } function showGuestApp(){ // Hide & clear member app document.getElementById('app-member').style.display = 'none'; document.getElementById('app-member').innerHTML = ''; // Show Guest app document.getElementById('app-guest').style.display = 'block'; startFirebaseUI(); } function startFirebaseUI(){ ui.start('#firebaseui-auth-container', { callbacks: { signInSuccessWithAuthResult: function(authResult, redirectUrl) { // User successfully signed in. // Return type determines whether we continue the redirect automatically // or whether we leave that to developer to handle. firebase.auth().currentUser.getIdToken(/* forceRefresh */ true).then(async function(idToken) { await client.authenticate({ strategy: 'firebase', access_token: idToken, }); showMemberApp(); }); return false; }, uiShown: function() { // The widget is rendered. // Hide the loader. document.getElementById('loader').style.display = 'none'; } }, // Will use popup for IDP Providers sign-in flow instead of the default, redirect. signInFlow: 'popup', credentialHelper: firebaseui.auth.CredentialHelper.NONE, // disable accountchooter.com helper signInOptions: [ firebase.auth.EmailAuthProvider.PROVIDER_ID, firebase.auth.FacebookAuthProvider.PROVIDER_ID, firebase.auth.TwitterAuthProvider.PROVIDER_ID, ], // Other config options... }); } const addEventListener = (selector, event, handler) => { document.addEventListener(event, async ev => { if (ev.target.closest(selector)) { handler(ev); } }); }; // "Logout" button click handler addEventListener('#logout', 'click', async () => { await client.logout(); showGuestApp(); }); ``` Now you should be able to visit your Firebase auth at the ``` http://localhost:3030/firebase_auth.html ``` page locally and authenticate w/any Firebase Providers you've set up in your Firebase Project 🔥