Home > database >  Decoding Firebase ID token failed. Make sure you passed the entire string JWT which represents an ID
Decoding Firebase ID token failed. Make sure you passed the entire string JWT which represents an ID

Time:01-07

I didn't initially get this error, but it mysteriously appeared later on in my code. I tried following allong with the firebase documentation and using the auth.getAuth() method but then got the following error:

** : TypeError: auth.getAuth(...).verifyIdToken is not a function **

This is my auth code:

//const { auth } = require('firebase-admin');
const { admin, db } = require('./admin');
//1. ******************
//const auth = require('firebase/auth');
module.exports = (req, res, next) => {
    let idToken;
    if(req.headers.authorization && req.headers.authorization.startsWith('Bearer ')){
        idToken = req.headers.authorization.split('Bearer')[1]
        //returns an array of 2 strings --> 2nd element is the token
    }
    else{
        console.error("NO TOKEN FOUND");
        return res.status(403).json({error: "Unauthorized"});
    }

admin.auth().verifyIdToken(idToken)
    .then(decodedToken => {
        req.user = decodedToken;
        console.log(decodedToken);
        return db.collection('users')
        .where('userId', '==', req.user.uid)
        .limit(1)
        .get();
    })
    .then(data => {
        req.user.handle = data.docs[0].data().handle;
        return next();
    })
    .catch(err => {
        console.error('Error while verifying token', err);
        return res.status(403).json(err);
    })
}

** where admin is require('firebase-admin');

I tried applying the auth.getAuth() method in the documentation, but my postman response says it is not a function. I'm very lost right now, any help would be very appreciated.

This is the full error:

{ "code": "auth/argument-error",
    "message": "Decoding Firebase ID token failed. Make sure you passed the entire string JWT which represents an ID token. See https://firebase.google.com/docs/auth/admin/verify-id-tokens for details on how to retrieve an ID token."
}

Here is my users.js that the id token gets to:

const { admin, db } = require("../util/admin");
const config = require('../util/config')
const firebase = require('firebase/app')
firebase.initializeApp(config) 
const { validateSignUpData, validateLoginData, reduceUserDetails} = require('../util/validators')
const auth = require('firebase/auth');
// const { user } = require("firebase-functions/v1/auth");

exports.signup = (req,res) => {
    const newUser = {
        email:req.body.email,
        password:req.body.password,
        confirmPassword:req.body.confirmPassword,
        handle:req.body.handle,
    };
    const { valid, errors } = validateSignUpData(newUser);

    if(!valid) return res.status(400).json(errors);

//when a user signs up give them a blank image
const noImg = 'blankpic.png';

//declare an errors object as an empty object 
let token, userId;
db.doc(`/users/${newUser.handle}`).get()
.then((doc) => {
    if(doc.exists){
        return res.status(400).json({ handle: 'this handle is already taken'})
    } else{
        return auth.createUserWithEmailAndPassword(auth.getAuth(), newUser.email,newUser.password)
    }
})
.then((data) => {
    //return access token for user to req more data
    //return data.user.getIdToken();
    userId = data.user.uid;
    return data.user.getIdToken();
})
.then((idToken) => {
    token = idToken;
    //create user document 
    const userCredentials = {
        handle: newUser.handle,
        email: newUser.email,
        createdAt: new Date().toISOString(),
        imageUrl: `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${noImg}?alt=media`,
        userId
    };
    //persist document into users cllection
    return db.doc(`/users/${newUser.handle}`).set(userCredentials);
    //return res.status(201).json( { token } );
})
.then(() => {
    return res.status(201).json({ token })
})
.catch((err) => {
    console.error(err);
    if (err.code == 'auth/email-already-in-use') {
        return res.status(400).json({ email: 'Email is already in use'})
    }
    return res.status(500).json({ general: "Something went wrong with server; please try again"});
});
}

exports.login = (req,res) => {
    const user = {
        email: req.body.email,
        password: req.body.password
    };
    const { valid, errors } = validateLoginData(user);

    if(!valid) return res.status(400).json(errors);

    

    auth.signInWithEmailAndPassword(auth.getAuth(), user.email, user.password)
    .then(data => {
        return data.user.getIdToken();
    })
    .then(token => {
        return res.json({ token });
    })
    .catch((err) => {
        console.error(err);
        return res
        .status(403).json({general: 'Wrong credentials, please try again'});

    });
}

exports.addUserDetails = (req,res) => {
    let userDetails = reduceUserDetails(req.body);
    db.doc(`/users/${req.user.handle}`).update(userDetails)
    .then(() => {
        return res.json({ message: 'Details add successfully'});
    })
    .catch(err => {
        console.error(err);
        return res.status(500).json({error: err.code});
    })
}

exports.getAuthenticatedUser = (req,res) => {
    let userData = {};
    db.doc(`/users/${req.user.handle}`).get() 
    .then(doc => {
        if(doc.exists){
            userData.credentials = doc.data();
            return db.collection('likes').where('userHandle', '==', req.user.handle).get()
        }
    })
    .then(data => {
        userData.likes = [];
        data.forEach(doc => {
            userData.likes.push(doc.data());
        });
        //return res.json(userData);
        return db.collection('notifications').where('recipient', '=='. req.user.handle).get();
        // .orderBy('createdAt').limit(10).get();
    })
    .then(data => {
        userData.notifications = [];
        data.forEach(doc => {
            userData.notifications.push({
                //recipient: doc.data().recipient,
                sender: doc.data().sender,
                createdAt: doc.data().createdAt,
                screamId: doc.data().screamId,
                type: doc.data().type,
                read: doc.data().read,
                notificationId: doc.id
            });
        });
        return res.json(userData);
    })
    .catch(err => {
        console.error(err);
        return res.status(500).json({ error: err.code });
    })
}
exports.getUserDetails = (req, res) => {
    let userData = {};
    db.doc(`/users/${req.params.handle}`)
      .get()
      .then((doc) => {
        if (doc.exists) {
          userData.user = doc.data();
          return db
        .collection("critech")
        .where("userHandle", "==", req.params.handle)
        //.orderBy("createdAt", "desc")
        .get();
        } else {
          return res.status(404).json({ errror: "User not found" });
        }
      })
      .then((data) => {
        userData.posts = [];
        data.forEach((doc) => {
          userData.posts.push({
        body: doc.data().body,
        createdAt: doc.data().createdAt,
        userHandle: doc.data().userHandle,
        userImage: doc.data().userImage,
        likeCount: doc.data().likeCount,
        commentCount: doc.data().commentCount,
        screamId: doc.id,
          });
        });
        return res.json(userData);
      })
      .catch((err) => {
        console.error(err);
        return res.status(500).json({ error: err.code });
      });
      };


exports.uploadImage = (req, res) => {
    const busboyCons = require("busboy");
    const path = require("path");
    const os = require("os");
    const fs = require("fs");
      
    var busboy = busboyCons({ headers: req.headers });
      
    let imageToBeUploaded = {};
    let imageFileName;
    // String for image token
    //let generatedToken = uuid();
      
    busboy.on("file", (fieldname, file, filename, encoding, mimetype) => {
      console.log(fieldname, filename, mimetype);
    //   if (mimetype !== "image/jpeg" && mimetype !== "image/png") {
    //     return res.status(400).json({ error: "Wrong file type submitted" });
    //   }
      // my.image.png => ['my', 'image', 'png']
      filename = filename.toString();
      const imageExtension = filename.split(".")[filename.split(".").length - 1];
    //   32756238461724837.png
      imageFileName = `${Math.round(
        Math.random() * 1000000000000
      ).toString()}.${imageExtension}`;
      //tmdir() --> temporarydirectory
      const filepath = path.join(os.tmpdir(), imageFileName);
      imageToBeUploaded = { filepath, mimetype };
      //use file system lib to create the file object using the node js function file.pipe
      file.pipe(fs.createWriteStream(filepath));
    });
    busboy.on("finish", () => {
      admin
        .storage()
        .bucket()
        .upload(imageToBeUploaded.filepath, {
          resumable: false,
          metadata: {
        metadata: {
          contentType: imageToBeUploaded.mimetype,
          //Generate token to be appended to imageUrl
        //   firebaseStorageDownloadTokens: generatedToken,
        },
          },
        })
        .then(() => {
            //construct image url to add to our user
          // Append token to url
          const imageUrl = `https://firebasestorage.googleapis.com/v0/b/${config.storageBucket}/o/${imageFileName}`;
          return db.doc(`/users/${req.user.handle}`).update({ imageUrl });
        })
        .then(() => {
          return res.json({ message: "image uploaded successfully" });
        })
        .catch((err) => {
          console.error(err);
          return res.status(500).json({ error: "something went wrong" });
        });
    });
    busboy.end(req.rawBody);
      };

 exports.markNotificationsRead = (req, res) => {
    let batch = db.batch();
    req.body.forEach((notificationId) => {
      const notification = db.doc(`/notifications/${notificationId}`);
      batch.update(notification, { read: true });
    });
    batch
      .commit()
      .then(() => {
        return res.json({ message: "Notifications marked read" });
      })
      .catch((err) => {
        console.error(err);
        return res.status(500).json({ error: err.code });
      });
      };

This is the token I get back when I log in 2 The response I get back when I use the token in my authorization header in Postman 1

CodePudding user response:

The authorization header is of format Bearer <Token> with a space in between. However you are passing 'Bearer' in split() which would result in ['', ' <token>'] (notice the additional whitespace before actual token). You must use .split(" ") and this should resolve it. Try refactoring the code as shown below:

if( req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
  idToken = req.headers.authorization.split(' ')[1]
}

const r1 = "Bearer token".split("Bearer")
const r2 = "Bearer token".split(" ")

console.log(`Token 1: '${r1[1]}'`)
console.log(`Token 2: '${r2[1]}'`)

  •  Tags:  
  • Related