Can I get a consistent 'iss' value for a Google OpenIDConnect id_token?
Asked Answered
D

2

4

I'm using Google's OpenIDConnect authentication, and I want to validate the JWT id_token returned from Google. However, the documentation seems inconsistent about what value Google returns for the iss (issuer) claim in the ID token.

One page says, "iss: always accounts.google.com", but another page says "The value of iss in the ID token is equal to accounts.google.com or https://accounts.google.com" and a comment in the example code further explains:

// If you retrieved the token on Android using the Play Services 8.3 API or newer, set
// the issuer to "https://accounts.google.com". Otherwise, set the issuer to
// "accounts.google.com". If you need to verify tokens from multiple sources, build
// a GoogleIdTokenVerifier for each issuer and try them both.

I have a server-side application, not an Android app, so I'm not using Play Services.

To further muddy the waters, the OpenIDConnect specification itself contains a note that:

Implementers may want to be aware that, as of the time of this writing, Google's deployed OpenID Connect implementation issues ID Tokens that omit the required https:// scheme prefix from the iss (issuer) Claim Value. Relying Party implementations wishing to work with Google will therefore need to have code to work around this, until such time as their implementation is updated. Any such workaround code should be written in a manner that will not break at such point Google adds the missing prefix to their issuer values.

That document is dated November 8, 2014. In the time since then, has Google standardized on an iss value, or do I really need to check for both of them? The comment above seems to indicate that only Play Services >=8.3 gets iss with https://, and everywhere else the value will be just accounts.google.com. Is that true?

Dairymaid answered 27/7, 2016 at 16:43 Comment(1)
Just ran in to this with Spring Security 5's Resource Server and issuer-uri. It's sad that, 4 years after that document date, this is still a problem.Missus
I
1

You have to check both possibilities. This is what worked for me...

Decode the token to get the issuer. If the issuer is not equal to either one of https://accounts.google.com or accounts.google.com you can stop there. It's an invalid token.

If the issuer is equal to either of the above Google strings, then pass that same decoded issuer value forward to the verification step.

Following is the an implementation I wrote in JavaScript for some Node.js Express middleware:

function authorize(req, res, next) {
    try {
        var token       = req.headers.authorization;
        var decoded     = jwt.decode(token, { complete: true });
        var keyID       = decoded.header.kid;
        var algorithm   = decoded.header.alg;
        var pem         = getPem(keyID);
        var iss         = decoded.payload.iss;

        if (iss === 'accounts.google.com' || iss === 'https://accounts.google.com') {
            var options = {
                audience: CLIENT_ID,
                issuer: iss,
                algorithms: [algorithm]
            }

            jwt.verify(token, pem, options, function(err) {
                if (err) {
                    res.writeHead(401);
                    res.end();
                } else {
                    next();
                }
            });            

        } else {
            res.writeHead(401);
            res.end();
        }
    } catch (err) {
        res.writeHead(401);
        res.end();
    }
}

Note this function uses jsonwebtoken and jwk-to-pem node modules. I ommitted details of the getPem function which ultimately converts a json web key to pem format.

Isonomy answered 25/1, 2017 at 7:4 Comment(0)
C
0

To start with, I definitely agree that Google's documentation is a murky business.

There are a couple of different ways in which you can validate the integrity of the ID token on the server side (btw this is the page you're looking for):

  1. "Manually" - constantly download Google's public keys, verify signature and then each and every field, including the iss one; the main advantage (albeit a small one in my opinion) I see here is that you can minimize the number of requests sent to Google).
  2. "Automatically" - do a GET on Google's endpoint to verify this token - by far the simplest: https://www.googleapis.com/oauth2/v3/tokeninfo?id_token={0}
  3. Using a Google API Client Library - the overhead might not be worth it, C# doesn't have an official one etc.

I suggest you go with the 2nd option and let Google worry about the validation algorithm.

Cero answered 28/7, 2016 at 6:50 Comment(3)
And on that page it says at the moment, still: "The value of iss in the ID token is equal to accounts.google.com or https://accounts.google.com."Hamrah
agreed; if you go down that path you'd probably have to check against both possibilitiesCero
Thanks, this doesn't quite answer my question, because you're talking about generally how to verify a Google 'id_token'. I'm specifically asking about the 'iss' field. It sounds like you're saying "No, there's no way to get a consistent value, you have to just check for both possibilities."Dairymaid

© 2022 - 2024 — McMap. All rights reserved.