I\'m trying to set up a Sign in with Google button that will allow people to purchase things on my website.
Client-side authentication looks pretty straightforward,
What you might want to do before performing a purchase is to verify the user is who you expect them to be by securely passing the user id from the client to your server and verifying it against the user id for the stored credentials. This offers additional protection against replay attacks where an attacker is pretending to be your site's user by hijacking their session and is the most relevant check to make before accepting payment from the user.
I would not rely on user validation alone as a mechanism for protection against fraud. You should use a secure payment system such as the Google Commerce platform and follow the best practices for commerce.
As a reminder, the OAuth2 v2 endpoint should be used to check your token every time the cached credentials are initialized. Checking on every request seems a bit excessive because you should be using cached credentials that have already been validated and stored server-side. At most, you could perform the checks when you update an access token but if you trust your refresh token, you should be sufficiently safe if you perform the checks when you create the account and set that refresh token.
The following steps are taken in addition to the user id validation upon account creation:
As mentioned in your linked post, the sample code in the Google+ quickstarts should sufficiently demonstrate how to perform these checks in a variety of programming languages for account authorization.
Within the HTML/JS client, the following code shows where the userId (value, as opposed to the special string "me") is retrieved for passing to the connect method to verify the Google+ userId:
var request = gapi.client.plus.people.get( {'userId' : 'me'} );
request.execute( function(profile) {
$('#profile').empty();
if (profile.error) {
$('#profile').append(profile.error);
return;
}
helper.connectServer(profile.id);
$('#profile').append(
$('
'));
$('#profile').append(
$('Hello ' + profile.displayName + '!
Tagline: ' +
profile.tagline + '
About: ' + profile.aboutMe + '
'));
if (profile.cover && profile.coverPhoto) {
$('#profile').append(
$('
'));
}
});
... and the following code shows the Google+ id being passed.
connectServer: function(gplusId) {
console.log(this.authResult.code);
$.ajax({
type: 'POST',
url: window.location.href + '/connect?state={{ STATE }}&gplus_id=' +
gplusId,
contentType: 'application/octet-stream; charset=utf-8',
success: function(result) {
console.log(result);
helper.people();
},
processData: false,
data: this.authResult.code
});
}
The relevant code performing these checks in the Java sample is as follows:
// Check that the token is valid.
Oauth2 oauth2 = new Oauth2.Builder(
TRANSPORT, JSON_FACTORY, credential).build();
Tokeninfo tokenInfo = oauth2.tokeninfo()
.setAccessToken(credential.getAccessToken()).execute();
// If there was an error in the token info, abort.
if (tokenInfo.containsKey("error")) {
response.status(401);
return GSON.toJson(tokenInfo.get("error").toString());
}
// Make sure the token we got is for the intended user.
if (!tokenInfo.getUserId().equals(gPlusId)) {
response.status(401);
return GSON.toJson("Token's user ID doesn't match given user ID.");
}
// Make sure the token we got is for our app.
if (!tokenInfo.getIssuedTo().equals(CLIENT_ID)) {
response.status(401);
return GSON.toJson("Token's client ID does not match app's.");
}
// Store the token in the session for later use.
request.session().attribute("token", tokenResponse.toString());
return GSON.toJson("Successfully connected user.");
} catch (TokenResponseException e) {
response.status(500);
return GSON.toJson("Failed to upgrade the authorization code.");
} catch (IOException e) {
response.status(500);
return GSON.toJson("Failed to read token data from Google. " +
e.getMessage());
}
In the samples, the ClientID came from the Google API console and will be distinct for your application.