Google supports OAuth 2.0 authorization for access to their APIs and gain access to private user data. In this tutorial I am going to show you how to request an Access token and a refresh token from Google’s Oauth2 server using CURL.
The steps for Google authorization
OAuth2 is performed in three steps, well maybe a fourth depending upon how you look at it.
- Request consent of the user
- receive the authorization code.
- Exchange the authorization code
- Exchange the refresh token
Why Curl?
In this tutorial we are going to walk through the OAuth 2.0 authorization flow. As an example we will use Google’s authorization server with CURL. Most OAuth servers are similar so you may be able to convert this for use with other Authorization servers. This code should also work with all of the Google APIs. If you want to use this with another Google API you may need to change the scope in the request. I have chosen to use CURL so that I can show you each of the steps one at a time in their pure form as HTTP. I did something similar to this in my video using How to set up Oauth2 in PostMan.
Request consent
In order to access private user data we must have consent of the user to access their data. We get that consent by first requesting access and displaying a consent screen to them. This consent screen is displayed on the authorization server.
Consent screen code
To display a consent screen on the authorization server we make a HTTP GET. A HTTP GET is basically just a link so it can be placed in any browser window.
https://accounts.google.com/o/oauth2/v2/auth?client_id=XXXX.apps.googleusercontent.com&redirect_uri=urn:ietf:wg:oauth:2.0:oob&scope=https://www.googleapis.com/auth/userinfo.profile&response_type=code
Consent screen call explained
The first thing we need to know is the endpoint on the aurhozation server to call in order to cause it to display a consent screen. Most if not all authorization servers have something called a disco doc or a discovery document. The discovery document is an endpoint with a list of all the endpoints that the authorization server has. You can find Google’s disco doc here. The endpoint we need is the one called authorization endpoint.
"authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
I recommend checking the discovery document from time to time. The endpoint has changed a few times over the years that I have been using it. It’s a good idea to ensure that you are always using the most recent endpoints.
There are four url parameters that need to be sent with this request.
client_id | client id from the credentials created on google cloud console |
redirect_uri | urn:ietf:wg:oauth:2.0:oob for installed applications |
scope | the scope of authorization we need in order to make the requests to the api. |
response_type | code |
In order to use Google’s authorization server we need to register our application on Google cloud platform. We will be using CURL and CURL will be running on my machine so we will need to create Desktop app credentials. I have a video which will walk you through creating a project on Google cloud console. How to create Google Oauth2 installed application
In this example I will also be making a call to the Google People API. To make a call to private Google profile data I will need the permission of the user to access it. I get that by using the Google profile scopes in my call so I have enabled the Google people api under librarie for my project. This code will work for any of Google APIs just remember to enable the proper library and request the scope you will need for the method you will be calling.
Client id is the first parameter I will be sending the client id can be found in the credentials.json file which I download for my project on Google cloud console.
The second parameter I will be sending is the redirect uri. The redirect uri tells the authorization server where we would like the tokens to be returned to. In our case we are using curl as an installed application so we would just like it to return the token in the web browser. In order to tell the authorization server that we want the token returned in the web browser we just send it urn:ietf:wg:oauth:2.0:oob as our redirect uri.
The next parameter we will be sending is one called scope. Scopes are used to define the level of scope which our application needs. In order to access private user data you need permission of the owner of that data. In our case we will be calling the Google People api so I will be requesting the following scope.
https://www.googleapis.com/auth/userinfo.profile
This scope will give my application read only access to the users google profile data. Googles authorization server supports a lot of different scopes you should check out the list here. I also recommend that you check the documentation for the method you are trying to use. The documentation will always state which scope is needed in order to access that method.
The final method parameter we will be sending is response type. The response type parameter tells the server which type of response we are expecting back. In our case we are expecting a authorization code to be returned to us.
When run this in a web browser the consent screen will be displayed to us and we will be given the option to authorize the application or not. If we grant the application authorize then the authorization server will return to use an authorization code.
This code will appear both in the title bar of the web browser
https://accounts.google.com/o/oauth2/approval/v2/approvalnativeapp?auto=false&response=code%3D4%2F1AY0e-g5x1K4pIjDxKhSV9qivBSItA--I_LkgtiSope%3Dhttps%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile&hl=en&approvalCode=4%2F1AY0e-g5x1K4pIjDxKhSV9qivBSItA-
As well as in the web browser window itself
Authorization codes have a very short lifetime, they need to be used right away. Authorization codes can only be used once so there is no reason to store them anywhere.
Exchanging the authorization response code
The next step in this process is to exchange the authorization code for an access token and refresh token.
Access tokens are short lived tokens bearer tokens. They are short lived because they expire after an hour. They are bearer tokens meaning that they bearer access to the data. As long as you have the access token and it has not expired you can access the data there is no other security concerns involved. So if you leak this access token you are granting other people access to your data. Keep your access token secure for the time they are valid.
Refresh tokens are long lived tokens. For the most part a refresh token should not expire, there are some cases where they do but this article will not be going into that. A refresh token can be used in combination with your client id and client secret to request a new access token whenever you need one. If you will be requesting access of the users account in the future you should store the refresh token this will give you access later.
Exchange authorization code.
This call is a HTTP POST so we will need to use curl.
curl -s \
--request POST \
--data "code=4/1AY0e-g7BhBt0QU9f5HTgNDGNR1GYtH12q4xvgL_D2Q34A&client_id=XXXX.apps.googleusercontent.com&client_secret=zYAoXDam3mqsdwabh3dQ3NTh&redirect_uri=urn:ietf:wg:oauth:2.0:oob&grant_type=authorization_code" \
https://accounts.google.com/o/oauth2/token
Exchanging the authorization code explained.
If you check the last line you will notice that we are sending this to the token endpoint this endpoint can also be found in Google’s disco doc.
"token_endpoint": "https://oauth2.googleapis.com/token",
The post data for this request is in the format of HTTP request query string so each parameter should be separated by a &.
code | The authorization code from the previous call |
client_id | client id from the credentials created on google cloud console |
client_secret | client secret from the credentials created on google cloud console |
redirect_uri | urn:ietf:wg:oauth:2.0:oob for installed applications |
grant_type | authorization_code |
The code is the code which we recieved from the first request, this is very short lived rememr you should use it as soon as you get it.
The client id and client secrete can be found in the credetinals.json file which you downloaded from google cloud console when you created your project. Think of them as a login and a password for your project. They should always be kept safe and secure you should not share them with anyone or post them online. Together the client id and client secret identify your application.
The redirect uri again tells the authorization server where we would like the tokens to be returned to, curl directly. In order to tell the authorization server that we want the token returned back as part of the same request send it urn:ietf:wg:oauth:2.0:oob as our redirect uri.
Finally we send it a grant type, in this type we are sending it an authorization code so we tell it that by sending a grant type of authorization code.
Exchanging the authorization code response.
Assuming all went well curl should now return to use an access token and a refresh token.
{
"access_token": "ya29.a0AfH6SMDypscIeiyNnPRvoizz3NvvA6SZdk9U4K8h4MyQRRm29kEc2shdrskPZp71Q1roy8RqIm_7spufW84ozUoSTk0QKkQ",
"expires_in": 3599,
"refresh_token": "1//09Y5LQ0XRxjt-CgYIARAAGAkSNwF-L9IrYzyMnbGtJHgh-FTf6z79cBhQ1hsPUAk71HFgFwqyXoiwpIa-4eA",
"scope": "https://www.googleapis.com/auth/userinfo.profile",
"token_type": "Bearer"
}
Using the refresh token with curl
Once the access token has expired you will need to retrieve a new one. The code to request a new access token is again a HTTP POST which means we will need to use CURL again.
curl -s \
--request POST \
--data 'client_id=XXXXX.apps.googleusercontent.com&client_secret=AoXDam3mqsdwabh3dQ3NTh&refresh_token=1//09PsxSjPF2dMnCgYIARAAGAkSNwF-L9IrnCeO3BOLt0d8MGTpDX-bIAP3zb-Jp9sZtACxtJuIromiYeCH_twCyJoiqRsE8R_zOdg&grant_type=refresh_token' \
https://accounts.google.com/o/oauth2/token
Refreshing the access token explained
If you check the last line you will notice that we are again sending this to the token endpoint this endpoint can also be found in Google’s disco doc.
"token_endpoint": "https://oauth2.googleapis.com/token",
The post data for this request is also in the format of HTTP request query string so each parameter should be separated by a &.
refresh_token | The refresh_token from the previous call |
client_id | client id from the credentials created on google cloud console |
client_secret | client secret from the credentials created on google cloud console |
redirect_uri | urn:ietf:wg:oauth:2.0:oob for installed applications |
grant_type | refresh_token |
The first parameter we will be sending is the refresh_token this is the token that was returns as part of the authorization code exchange request. Refresh tokens are long lived tokens and can be used in this matter to request a new access token.
The client id, client secrete and redirect uri you have seen in the previous requests.
In this case the grant type we will be sending will be refresh token because we are telling the authorization server that we are sending it a refresh token.
Refreshing the access token response.
{
"access_token": "ya29.a0AfH6SMA_vRaZekKJnvylcviCdEF1mzkPUd2i5k5qhFpclvi7deVMAL1nE4Ci6S3e3z5L0hnhhgYW6KknQEXu3StsdzykuNG6Zd5J80wORd4",
"expires_in": 3599,
"scope": "https://www.googleapis.com/auth/userinfo.profile",
"token_type": "Bearer"
}
This time the server simply returned to use an access token. Our new access token can be used for an hour.
Request user Profile data
In order to make a request to the API we then pass the access token as an Amortization header as type bearer token.
curl -H 'Accept: application/json' -H "Authorization: Bearer ya29.a0AfH6SMDe0-ToZWsfUpgPYw2BxHMIU8yRgW3-RiV0yBTjOZJZzOQVp3os3Kh2weJ50AHS_3oPvullLs_wfonlBMo37KabiO7-VJ6G3XbJQ37_ABpikL-tpMrlou3koA67lAiMY3exFY70zT5v7idlT8FDift1kg" \
https://people.googleapis.com/v1/people/me?personFields=names
The response from the server will then contain the users profile data.
{
"resourceName": "people/117200475532",
"etag": "%EgUBAj03LhoEAQIFByIMR3BzQkR2c9",
"names": [
{
"metadata": {
"primary": true,
"source": {
"type": "PROFILE",
"id": "11720047"
}
},
"displayName": "Linda Lawton",
"familyName": "Lawton",
"givenName": "Linda",
"displayNameLastFirst": "Lawton, Linda",
"unstructuredName": "Linda Lawton"
},
{
"metadata": {
"source": {
"type": "CONTACT",
"id": "3faa96eb0"
}
},
"displayName": "Linda Lawton",
"familyName": "Lawton",
"givenName": "Linda",
"displayNameLastFirst": "Lawton, Linda",
"unstructuredName": "Linda Lawton"
}
]
}
I recommend having a look at the People.get method to see how best to use it to retrieve the user profile information that you need.
YouTube video
Conclusion
In order to access private user data you need permission of that user. Permission is granted using an authorization server. The authorization server has several steps that must be completed in the correct order in order to be granted an access token to access the users data.
Is there a way to use curl to get the authorization token in a JSON container similar to the access token? How do I find out what should be added to the scope? I am trying to access the google cloud speech API.
Im not sure what you mean by a container. If you are refereeing to docker it depends on what you are doing normally with docker i would use a service account and that would be preauthorized. Oauth2 with a docker container would require some addental code to ensure that it has an exit point to request access of a user it would need to be a web app.
As for your scope that is normally found in the documentation for the method you are using. Scopes – speech
Do you know of a way to send emails with attachments via the Gmail API using CURL?
It should be doable though the api. Just get the authorization to work once you have an access token it should be simple enough. I dont have any tutorials on it though
This walkthrough is legit. Thank you. It help me connect to a client’s data.
As a side note, the walkthrough worked right away on my personal account, using a project app in testing mode.
However using the client’s account I got a permission error on the Consent Screen Code section and could not get the code. I confirmed it was a Desktop app credentials but it had to do with the app being in production vs test and having no users in the OAuth consent screen section. The solution – I used redirect_uri=http://localhost instead, which gave a redirect error but it showed the code in the error page.
Thank you so much, this is the best online walk-though…. Perfect!!
Hello,
Great video. This is the most concise explanation I have seen yet! Can this also be done with a google service account credential? If so, what is the client id and client secret? Client email and private key? I would love it if you could respond.
Thanks,
Braham
probably but service accounts require a lot of encryption I have not had time to look into it.
Hi, the OOB method is deprecated: https://developers.google.com/identity/protocols/oauth2/resources/oob-migration
Change:
redirect_uri=urn:ietf:wg:oauth:2.0:oob
to:
redirect_uri=http://127.0.0.1