When the user is redirected back to our app, there will be a code
and state
parameter in the query string. The state
parameter will be the same as the one we set in the initial authorization request, and is meant for our app to check that it matches before continuing. This helps protect our app from CSRF attacks.
// When Google redirects the user back here, there will // be a "code" and "state" parameter in the query string if(isset($_GET['code'])) { // Verify the state matches our stored state if(!isset($_GET['state']) || $_SESSION['state'] != $_GET['state']) { header('Location: ' . $baseURL . '?error=invalid_state'); die(); } // Exchange the authorization code for an access token $ch = curl_init($tokenURL); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([ 'grant_type' => 'authorization_code', 'client_id' => $googleClientID, 'client_secret' => $googleClientSecret, 'redirect_uri' => $baseURL, 'code' => $_GET['code'] ])); $response = json_decode(curl_exec($ch), true); // ... fill in from the code in the next section }
This code first checks that the “state” returned from Google matches the state we stored in our session.
We build up a POST request to Google’s token endpoint containing our app’s client ID and secret, as well as the authorization code that Google sent back to us in the query string.
Google will verify our request, and then respond with both an access token as well as an ID token. The response will look like the below.
{ "access_token": "ya29.Glins-oLtuljNVfthQU2bpJVJPTu", "token_type": "Bearer", "expires_in": 3600, "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImFmZmM2MjkwN 2E0NDYxODJhZGMxZmE0ZTgxZmRiYTYzMTBkY2U2M2YifQ.eyJhenAi OiIyNzIxOTYwNjkxNzMtZm81ZWI0MXQzbmR1cTZ1ZXRkc2pkdWdzZX V0ZnBtc3QuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQi OiIyNzIxOTYwNjkxNzMtZm81ZWI0MXQzbmR1cTZ1ZXRkc2pkdWdzZX V0ZnBtc3QuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIi OiIxMTc4NDc5MTI4NzU5MTM5MDU0OTMiLCJlbWFpbCI6ImFhcm9uLn BhcmVja2lAZ21haWwuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUs ImF0X2hhc2giOiJpRVljNDBUR0luUkhoVEJidWRncEpRIiwiZXhwIj oxNTI0NTk5MDU2LCJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2ds ZS5jb20iLCJpYXQiOjE1MjQ1OTU0NTZ9.ho2czp_1JWsglJ9jN8gCg WfxDi2gY4X5-QcT56RUGkgh5BJaaWdlrRhhN_eNuJyN3HRPhvVA_KJ Vy1tMltTVd2OQ6VkxgBNfBsThG_zLPZriw7a1lANblarwxLZID4fXD YG-O8U-gw4xb-NIsOzx6xsxRBdfKKniavuEg56Sd3eKYyqrMA0DWnI agqLiKE6kpZkaGImIpLcIxJPF0-yeJTMt_p1NoJF7uguHHLYr6752h qppnBpMjFL2YMDVeg3jl1y5DeSKNPh6cZ8H2p4Xb2UIrJguGbQHVIJ vtm_AspRjrmaTUQKrzXDRCfDROSUU-h7XKIWRrEd2-W9UkV5oCg" }
The access token should be treated as an opaque string. It has no significant meaning to your app other than being able to use it to make API requests.
The ID token has a specific structure that your app can parse to find out the user data of who signed in. The ID token is a JWT, explained in more detail in OpenID Connect. You can paste the JWT from Google into a site like example-app.com/base64 to quickly show you the contents, or you can base64 decode the middle part between the two .
‘s to see the user data which we’ll do next.