4

I'm working in an Angular App with firebase and I'm stuck validating the idToken with the firebase SDK in a cloud function.

It starts when I tried to make a call to an protected endpoint, the user must be authenticated to access it but when I make a call with an authenticated user it doesn't make it.

First I check the functions:log to see the error message I log when the authentication fails.

2018-07-18T13:10:11.575Z E api: Error while verifying Firebase ID token:  { Error: 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.
    at FirebaseAuthError.Error (native)
    at FirebaseAuthError.FirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:39:28)
    at FirebaseAuthError.PrefixedFirebaseError [as constructor] (/user_code/node_modules/firebase-admin/lib/utils/error.js:85:28)
    at new FirebaseAuthError (/user_code/node_modules/firebase-admin/lib/utils/error.js:143:16)
    at FirebaseTokenVerifier.verifyJWT (/user_code/node_modules/firebase-admin/lib/auth/token-verifier.js:136:35)
    at FirebaseTokenGenerator.verifyIdToken (/user_code/node_modules/firebase-admin/lib/auth/token-generator.js:129:37)
    at Auth.verifyIdToken (/user_code/node_modules/firebase-admin/lib/auth/auth.js:124:37)
    at validateFirebaseIdToken (/user_code/lib/routes/employee/employeeRoute.js:29:18)
    at Layer.handle [as handle_request] (/user_code/node_modules/express/lib/router/layer.js:95:5)
    at next (/user_code/node_modules/express/lib/router/route.js:137:13)  errorInfo: 
   { 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.' },
  codePrefix: 'auth' }

So I check how I get the token and it seems to be fine:

  public async getIdToken() {
    return this.angularFireAuth.auth.currentUser.getIdToken(true)
      .then(idToken => {
        return idToken
      })
      .catch(err => {
        throw new Error(err)
      })
  }

And how I validate it, seems fine too (for my eyes)

const validateFirebaseIdToken = (req, res, next) => {
  console.log('Check if request is authorized with Firebase ID token')

  if ((!req.headers.authorization || !req.headers.authorization.startsWith('Bearer ')) && !(req.cookies && req.cookies.__session)) {
    console.error('No Firebase ID token was passed as a Bearer token in the Authorization header.',
      'Make sure you authorize your request by providing the following HTTP header:',
      'Authorization: Bearer <Firebase ID Token>',
      'or by passing a "__session" cookie.')
    res.status(403).send('Unauthorized')
    return
  }

  let idToken
  if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
    console.log('Found "Authorization" header')
    idToken = req.headers.authorization.split('Bearer')[1]
  } else if(req.cookies) {
    console.log('Found "__session" cookie')
    idToken = req.cookies.__session
  } else {
    console.log('No cookie')
    res.status(403).send('Unauthorized')
    return
  }

  admin.auth().verifyIdToken(idToken)
    .then(decodedIdToken => {
      console.log('ID token correctly decoded', decodedIdToken)
      return next()
    })
    .catch(error => {
      console.error('Error while verifying Firebase ID token: ', error)
      res.status(403).send('Unauthorized')
    })

}

So I log the idToken returned in the getIdToken function and the idToken just before admin.auth().verifyIdToken(idToken) is called and they match perfectly.

So I don't understand why it fails.

I already checked the documentation and it seems to match what I did https://firebase.google.com/docs/auth/admin/verify-id-tokens

Any ideas would be much appreciated.

1 Answer 1

6

Carlos here.

I think the procedure is fine, but maybe there is an extra space in the token when you split the header:

if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
    console.log('Found "Authorization" header')
    idToken = req.headers.authorization.split('Bearer')[1] // <- this part has a space at the beginning
}

Trimming the string helps you resolve the issue?

Sign up to request clarification or add additional context in comments.

1 Comment

That was the problem. Thank you very much Carlos. Sometimes when you are stuck on the same problem for hours, you overlook this kind of details.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.