Dealing with Google OAuth 2.0 for Server to Server Applications

From i2Rest
Jump to: navigation, search

When you need your application to call Google APIs on behalf of its own (no user data is accessing and user is not involved directly), you should refer to Google OAuth 2.0 for Server to Server Applications. It is not exactly OAuth2 Client Credential flow, so i2Rest Client can't deal with it for you using existing built-in authentication flows. But we still can reproduce this authorization scenario composing requests and handling responses manually. Lets take a look on steps we should perform.

Google-serv-to-serv.png
A) Create a JSON Web Token (JWT, pronounced, "jot") which includes a header, a claim set, and a signature.
B) Request an access token from the Google OAuth 2.0 Authorization Server.
C) Handle Authorization Server JSON response.
D) Use token to perform API call

Initial step

To perform server-to-(Google)server interactions you need a service account, which is an account that belongs to your application instead of to an individual end user. Your application will call Google APIs on behalf of the service account using service account credentials - a generated email address that is unique and at least one public/private key pair. We should go to Google API console and find this account details, because they are necessary at the next step.

JSON Web Token

Now we have to deal with JSON Web Token (JWT). JWT consists of two JSON objects - a header and a claim set, and a signature. All parts must be encoded using the Base64url encoding. Using JWT encoders like this one can save much time. So lets compose our JWT using credentials prepared on the initial step and Google's instructions.
Noauth3-JWTIO.png

Token request

The next step is POST request on https://oauth2.googleapis.com/token with JWT as an URL encoded request body.
Note: you have to add Google.com SSL certificate CA to your DCM to perform https requests

   I2REST COMMAND(*POST)                                       
       URL('https://oauth2.googleapis.com/token')           
       BODY(*N 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agra
            nt-type%3Ajwt-bearer&assertion=eyJhbGciOiJSUzI1N
            iIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJpMnJlc3RzZXJ2QGNs
            aWVudC1mbG93LWV4YW1wbGUuaWFtLmdzZXJ2aWNlYWNjb3Vu
            dC5jb20iLCJzY29wZSI6Imh0dHBzOi8vd3d3Lmdvb2dsZWFw
            aXMuY29tL2F1dGgvY2xvdWQtcGxhdGZvcm0iLCJhdWQiOiJo
            dHRwczovL29hdXRoMi5nb29nbGVhcGlzLmNvbS90b2tlbiIs
            ImV4cCI6MTU4NzEzMzAwMCwiaWF0IjoxNTg3MTI5NDU3fQ.h
            _n7RXC13ACXFJQ5J2_5AlMcRxhaEK0Yi7SW6s_GRkED9qV8X
            rDFa47e-5uI3ZuMSw3aak9-RUJk7v2uw7kJUhT11At5JLPtb
            wpwJxqj0dbvaqUKuwk4OKXYBWrHsRfWq8-GZZ-GryAwXzq38
            p6j-3-jSJUm4EYKiXukzRWiGlUpP9xDZsOU_8gemJM3yR911
            95Bsc0yY-sHoG1FjaGy9EMRq4nHzD-An-8OGezYot2tWbunk
            MU8LmurcM0IEafwytB_iM7QOO8LNV2eKbjj-Ilxqm5XLbzIm
            WAvqIK9gNQ7avrmpnttJMX78VKuCFK9UB3OdcTtCs3Wb7r4P
            jQ5qg' 'application/x-www-form-urlencoded')     
       OUTPUT(*BOTH)                  
       DCMCLIENT(MYCLIENT)            
       RECVLOG('/home/btpl/rejwt.log')
       SENTLOG('/home/btpl/sejwt.log')
       AUTHMETHOD(*NONE)    

Handling Authorization Server response

If we composed JWT and access token request correctly, Authorization Server will respond with an access token.

    Server response (status 200, shown 261 bytes of 261):
    {"access_token":"ya29.c.Ko8BxwcD_TDznwIQVB7Y_vs1S8a86_DhMfVwz1rcMfLkaMkMtx
    BBIxqoYbfJdQvp5O3EONN-lz7VviAVNWx3pQInTxPdf_2pmL9JW3l8Qt                
    DfSrfVL0CSk1j_BgEdR0jkPCCsRQPtWkSdSm-cH2vFZZiVcOOEOq4Yt8C3jzBl3kzNt2N882ic
    P0G6vmwdFljOdhY","expires_in":3599,"token_type":"Bearer"}

Authorized API call

Now it's time to call an API. As an example we will create Google service account with IAM API and appropriate method. Access token will be attached using the access_token query string parameter.

   I2REST COMMAND(*POST)                                       
       URL('https://iam.googleapis.com/v1/projects/client-fl
           ow-example/serviceAccounts?access_token=ya29.c.Ko
           8BxwcD_TDznwIQVB7Y_vs1S8a86_DhMfVwz1rcMfLkaMkMtxB
           BIxqoYbfJdQvp5O3EONN-lz7VviAVNWx3pQInTxPdf_2pmL9J
           W3l8QtDfSrfVL0CSk1j_BgEdR0jkPCCsRQPtWkSdSm-cH2vFZ
           ZiVcOOEOq4Yt8C3jzBl3kzNt2N882icP0G6vmwdFljOdhY') 
       BODY(*N '{  "accountId": "i2restcreated",             
                   "serviceAccount": {                               
                          "description": "created via i2rest client",                   
                          "displayName": "example one" }
                }' 'application/json' *YES 1208)                
       OUTPUT(*BOTH) 
       DCMCLIENT(MYCLIENT)                 
       RECVLOG('/home/btpl/recreatsr1.log')
       SENTLOG('/home/btpl/sncreatsr1.log')
       AUTHMETHOD(*NONE)

Let's check if account was created with another request to list method of the same API. At this time we will attach access token as an additional header, which is a preferred option.

  I2REST COMMAND(*GET)                                        
       URL('https://iam.googleapis.com/v1/projects/client-fl
           ow-example/serviceAccounts')                     
       HEADERS((AUTHORIZATION 'Bearer ya29.c.Ko8BxwcD_TDznwI
               QVB7Y_vs1S8a86_DhMfVwz1rcMfLkaMkMtxBBIxqoYbfJ
               dQvp5O3EONN-lz7VviAVNWx3pQInTxPdf_2pmL9JW3l8Q
               tDfSrfVL0CSk1j_BgEdR0jkPCCsRQPtWkSdSm-cH2vFZZ
               iVcOOEOq4Yt8C3jzBl3kzNt2N882icP0G6vmwdFljOdhY
               '))                                          
       OUTPUT(*BOTH)                                        
       DCMCLIENT(MYCLIENT)                                  
       RECVLOG('/home/btpl/CAdriverecv.log')                
       SENTLOG('/home/btpl/CAdrivesent.log')                
       AUTHMETHOD(*NONE)   

And here is server respond showing us that both requests were successfull:

  "accounts": [
    {
      "name": "projects/client-flow-example/serviceAccounts/i2restserv@client-flow-example.iam.gserviceaccount.com",
      "projectId": "client-flow-example",
      "uniqueId": "117967955212758073044",
      "email": "i2restserv@client-flow-example.iam.gserviceaccount.com",
      "displayName": "i2restserv",
      "etag": "MDEwMjE5MjA=",
      "description": "Example to i2rest client flow",
      "oauth2ClientId": "117967955212758073044"
    },
    {
      "name": "projects/client-flow-example/serviceAccounts/i2restcreated@client-flow-example.iam.gserviceaccount.com",
      "projectId": "client-flow-example",
      "uniqueId": "104934312932229503067",
      "email": "i2restcreated@client-flow-example.iam.gserviceaccount.com",
      "displayName": "example one",
      "etag": "MDEwMjE5MjA=",
      "description": "created via i2rest client",
      "oauth2ClientId": "104934312932229503067"
    }
    ]