Firebase part III: add authentication

30th Sep 19
elephants

I will be adding the ability for users to register to the website.

Firstly I need to add authentication to my project.  So within firebase I go to authentication and set up sign-in method and enable email/password.  Then go to project settings and register your app by clicking on the <>.  Copy your firebaseConfig object.  I will be using firebase libraries to sign in and sign up users, so I will need to install firebase package.

npm install --save firebase

Import and then initialise the firebase library passing the firebaseConfig object

const firebaseLib = require('firebase');
firebaseLib.initializeApp(firebaseConfig)

Now we can use the firebase library in our new route to sign up users. We use the createUserWithEmailAndPassword method passing the email and password to set up the user.

app.post('/signup', (req, res) => {
    const newUser = {
        email: req.body.email,
        password: req.body.password,
        confirmPassword: req.body.confirmPassword,
        handle: req.body.handle,
        admin: false
    }
    firebaseLib.auth()
        .createUserWithEmailAndPassword(newUser.email, newUser.password)
        .then(data => {
            return res.status(201)
                        .json({message: `user ${data.user.uid} signed up successfully`})
        })
        .catch(err => {
            console.error(err);
            return res.status(500).json({error: err.code});
        })
});

 

The handle is the username, so I will check whether that handle has already been used when a user registers. For that I need to add a collection of 'users' to my database so I can cross check.  I manually add the collection and a document for the user I signed via Postman, getting the userId from firebase authentication.

 

database users

I then go back to my function and refactor.  I firstly check whether the username has already been taken if not I create the user.  In the next then statement I retrieve the token from the user and in the final then statement I return the response returning the tokenId. 

 

app.post('/signup', (req, res) => {
    const newUser = {
        email: req.body.email,
        password: req.body.password,
        confirmPassword: req.body.confirmPassword,
        handle: req.body.handle,
        admin: false
    }
    let token;
    db.doc(`/users/${newUser.handle}`)
        .get()
        .then(doc => {
             if(doc.exists){
                 return res.status(400).json({handle: 'this username is already taken'});
             }else{
                return firebaseLib.auth()
                .createUserWithEmailAndPassword(newUser.email, newUser.password)
             }
        })
        .then(data => {
            // we have our user created, we can get the token
           return data.user.getIdToken()

        })
        .then(tokenId => {
            token = tokenId;
            return res.status(201).json({token});
        })
        .catch(err => {
            console.error(err);
            return res.status(500).json({error: err.code})
        });

 

In Postman I send the signup POST request for a new user, it registers the user and returns the user token.  This token will be needed in authentication later on.  If I were to send the same user again I receive a client error of "error": "auth/email-already-in-use".  We can handle this in the catch block.

   .catch(err => {
            console.error(err);
            if(err.code === 'auth/email-already-in-use'){
                return res.status(400).json({email: 'Email already in use'})    
            }else{
                return res.status(500).json({error: err.code})
            }
              
        });

 

Currently I am not persisting the user details to the database.  So within the block where we return the token we can add the code to create the user document.  

app.post('/signup', (req, res) => {
 ....

    let token, userId; 
    db.doc(`/users/${newUser.handle}`).get()
        .then(doc => {
          ...
        })
        .then(data => {
           userId = data.user.uid;
           ...

        })
        .then(tokenId => {
            token = tokenId;
            const userCredentials = {
                handle: newUser.handle,
                email: newUser.email,
                createdAt: new Date().toISOString(),
                admin: newUser.admin,
                userId
            };
           return db.doc(`/users/${newUser.handle}`).set(userCredentials)
              
        })
        .then(() => {
            return res.status(201).json({token}); 
        })
        .catch(err => {
                ......
              
        });

});

 

I have recently completed my apprenticeship.  I am currently building the API to a React JS site using Firebase.