Google SignIn - “access_token” vs “id_token” vs “c

2020-07-27 04:35发布

In our website we used to use access_token when logging people with Google Sign In. First, we redirect the user to google, user brings the access_token to us, and we validate that token to make sure the user is the actual Google user.

Then, we needed a Google sign-in feature for our Android app, so I wanted the Android developer to bring access_token to us. He replied he couldn't. I searched about that finding almost no documentation about access_token. In documentation, Google says me to use the "id_token".

OK, I wanted the developer to bring me the id_token, and I have successfully verified the token's integrity. Then I wanted to implement the same for websites.

My c# code is:

string googleId = GoogleJsonWebSignature.ValidateAsync(idToken).Result.Subject;

It worked when I ran it locally, but when I tried in production, it gave an error: JWT is not yet valid

Is id_token the correct way to send to the backend and verify? I found another option too: code.

Code is something like A/12112312......

Access_token is something like ya29.somemorestring

My question is, Which one is correct to send to the backend? By the way, I think access_token is sort of deprecated or something like that.

1条回答
可以哭但决不认输i
2楼-- · 2020-07-27 05:21

Yes, you should be using the id_token. You get the id_token on the client side using this:

var id_token = googleUser.getAuthResponse().id_token;

and validating it on the server side using (do in a try/catch block to catch any errors):

token = await GoogleJsonWebSignature.ValidateAsync(idToken);

The JWT is not yet valid error is due to the time on your server being slow. Even a few seconds slow will cause this problem. To be sure of this working all the time, you'll need to implement a custom clock which gets an accurate time from somewhere. Here's an example using NNTP:

public class AccurateClock : Google.Apis.Util.IClock
{
    const int UpdateIntervalMinutes = 60;
    const string NntpServer = "time.nist.gov";

    private TimeSpan _timeOffset;
    private DateTime _lastChecked;

    public AccurateClock()
    {
        _timeOffset = TimeSpan.FromSeconds(0);
        _lastChecked = DateTime.MinValue;
    }

    private DateTime GetTime()
    {
        try
        {
            if (DateTime.Now.Subtract(_lastChecked).TotalMinutes >= UpdateIntervalMinutes)
            {
                // Update offset 
                var client = new TcpClient(NntpServer, 13);
                DateTime serverTime;
                using (var streamReader = new StreamReader(client.GetStream()))
                {
                    var response = streamReader.ReadToEnd();
                    var utcDateTimeString = response.Substring(7, 17);
                    serverTime = DateTime.ParseExact(utcDateTimeString, "yy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
                }
                _timeOffset = DateTime.UtcNow.Subtract(serverTime);
                _lastChecked = DateTime.Now;
            }
            var accurateTime = DateTime.UtcNow.Subtract(_timeOffset);
            return accurateTime;
        }
        catch (Exception ex)
        {
            return DateTime.UtcNow;
        }

    }

    public DateTime Now
    {
        get
        {
            return GetTime().ToLocalTime();
        }
    }

    public DateTime UtcNow
    {
        get
        {

            return GetTime();
        }
    }
}

You then pass the custom clock to the validation method.

token = await GoogleJsonWebSignature.ValidateAsync(idToken, new AccurateClock());

Please note: This will update the difference between the correct time and the local machine time every time the class is created, so you really want to register this as a Singleton in whatever IOC container you are using and pass the reference to the validator instead. It will then recheck the time using NNTP every hour. If you are not using an IOC Container you could make the class static.

查看更多
登录 后发表回答