How to verify google auth token at server side in node js?

Zammy Page picture Zammy Page · Feb 23, 2017 · Viewed 9.2k times · Source

My front end application is authenticated using gmail account.

I retrieve id_token after the authentication is successful and send it as Authorization Header as bearer token.

E.g. http://localhost:4000/api

Authorization Bearer token_id

At nodejs server side, I call the following method to verify the token.

exports.verifyUser = function(req, res, next) {
    var GoogleAuth = require('google-auth-library');
    var auth = new GoogleAuth();
    var client = new auth.OAuth2(config.passport.google.clientID, config.passport.google.clientSecret, config.passport.google.callbackURL);
    // check header or url parameters or post parameters for token
    var token = "";
    var tokenHeader = req.headers["authorization"];
    var items = tokenHeader.split(/[ ]+/);
    if (items.length > 1 && items[0].trim().toLowerCase() == "bearer") {
        token = items[1];
    }
    if (token) {
        var verifyToken = new Promise(function(resolve, reject) {
            client.verifyIdToken(
                token,
                config.passport.google.clientID,
                function(e, login) {
                    console.log(e);
                    if (login) {
                        var payload = login.getPayload();
                        var googleId = payload['sub'];
                        resolve(googleId);
                        next();
                    } else {
                        reject("invalid token");
                    }
                }
            )
        }).then(function(googleId) {
            res.send(googleId);
        }).catch(function(err) {
            res.send(err);
        })
    } else {
        res.send("Please pass token");
    }
}

When I call the above method, I always get Invalid token response with following error.

Error: No pem found for envelope:     {"alg":"RS256","kid":"c1ab5857066442ea01a01601
850770676460a712"}
    at OAuth2Client.verifySignedJwtWithCerts (\node_modules\google-auth-libr
ary\lib\auth\oauth2client.js:518:13)
  • Is this the right approach to verify token?
  • Do I send the id_token as Authorization bearer? Or is it for authorization only?
  • How do I send the id_token to the sever side? Thru url, header?
  • What am I doing wrong?

Any help is highly appreciated.

Answer

Bertrand Martel picture Bertrand Martel · Feb 23, 2017

OAuth2Client.verifyIdToken take an idToken in arguments, from the library source :

/**
 * Verify id token is token by checking the certs and audience
 * @param {string} idToken ID Token.
 * @param {(string|Array.<string>)} audience The audience to verify against the ID Token
 * @param {function=} callback Callback supplying GoogleLogin if successful
 */
OAuth2Client.prototype.verifyIdToken = function(idToken, audience, callback)

You have passed the whole header value bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxYWI1OD U3MDY2NDQyZWEwMWEwMTYwMTg1MDc3MDY3NjQ2MGE3MTIifQ so you will have to split the headers value as :

var authorization = req.headers["authorization"];
var items = authorization.split(/[ ]+/);

if (items.length > 1 && items[0].trim() == "Bearer") {
    var token = items[1];
    console.log(token);
    // verify token
}

Is this the right approach to verify token ?

Yes, this is the right way to verify token. For debugging, you can also verify token with the tokeninfo endpoint if you have any doubt or for quick testing :

https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123
  • Do I send the id_token as Authorization bearer? Or is it for authorization only?
  • How do I send the id_token to the sever side? Thru url, header?

You can send JWT token in Authorization header but it could lead to usecase where you have multiple Authorization headers. It's best to URL encode or embed the token in the body. You can check Google example here

Moreover, the following are required by Google :

  • the token must be sent via HTTPS POST
  • the token integrity must be verified

To optimize your code, you could also move your Google auth object to your app.js at the root of your app instead of redefining it each time the token should be verified. In app.js :

var app = express();

var GoogleAuth = require('google-auth-library');
var auth = new GoogleAuth();
app.authClient = new auth.OAuth2(config.passport.google.clientID, config.passport.google.clientSecret, config.passport.google.callbackURL);

and in verifyUser call it from req.app.authClient :

req.app.authClient.verifyIdToken(...)