Search code examples
restrest-assuredgoogle-apis-explorerweb-api-testing

How to get the access token for validating Google API /Gmail API using Rest Assured


I am trying to validate the gmail API using restAssured. As per the docs, it requires authentication with Key and OAuth2.0. I used POSTMAN initially and was able to generate the access token and subsequently hit the request to get a success response. Now I want to achieve the same with Rest Assured framework.

I want to add the logic of token generation somewhere in beforeMethod/beforeTest in testNG framework.

I have basically two questions:

  1. How should I be setting up the API credentials for OAuth in Google Cloud Platform for hitting the request through Rest Assured(like We do for Postman)
  2. What should be the Request Endpoint and method.

So far I have tried below approaches referring to various solutions posted on Stack Overflow and other blogs:

  1. Approach 1

    public void oAuthToken() {
    
        Response res = given().
            auth().
            preemptive().basic("username", "password").
            header("Content-Type","application/json").
            queryParam("key","KeyGeneratedFromAPICedentials").
            formParam("client_id","created an OAuth Client ID").
            formParam("client_secret","created an OAuth Client Secret_ID").
            formParam("grant_type","client_credentials").
    
            when().
            get("https://accounts.google.com/o/oauth2/auth").
    
            //Getting this endpoint from JSON in OAuth Client ID created in google Cloud Platform
    
            then().assertThat().statusCode(200).extract().response();
    
            System.out.println("This is the response : " +res.asString());
    }
    

Result: Expected status code <200> but was <400>.

Approach 2:

public void oAuthToken() {

            Response res = given().
                auth().
                preemptive().basic("username", "password").
                header("Content-Type","application/json").
                queryParam("key","KeyGeneratedFromAPICedentials").
                formParam("client_id","created an OAuth Client ID").
                formParam("client_secret","created an OAuth Client Secret_ID").
                formParam("grant_type","client_credentials").

                when().
                get("https://oauth2.googleapis.com/token").

                //Getting this endpoint from JSON in OAuth Client ID as Token_URI created in google Cloud Platform

                then().assertThat().statusCode(200).extract().response();

                System.out.println("This is the response : " +res.asString());
        }

Result: Expected status code <200> but was <404>

Approach 3:

public void oAuthToken() {

        RestAssured.baseURI="https://oauth2.googleapis.com";
        Response res = given().
            auth().preemptive().basic("Client_ID", "Client_Secret").
            contentType("application/x-www-form-urlencoded").
            formParam("grant_type","client_credentials").
            formParam("scope","openid").

            when().
            get("/token").

            then().assertThat().statusCode(200).extract().response();

            System.out.println("This is the response : " +res.asString());
}

Result : Got 404 as response again.

Approach 4: Passed the access token directly after fetching it through "Generate Access Token" in postman.

Result: Got 403 as the response.

Needless to say to the experts here that I am quite new to Rest Assured and just trying to shoot arrows in the dark to get things working.

I want a robust approach of generating the OAuth token before running the Test each time. Feel free to guide me to any existing documentation as well.

This is the link to the API docs I am trying to access: https://developers.google.com/gmail/api/v1/reference/users/getProfile#auth


Solution

  • After going through N number of blogs and trying to capture as much information as I can, I was finally able to come up with a Solution which in the process helped to understand the actual issue as well.

    The main issue here was to handle the OAuth2.0 authentication to access the Gmail API which I was doing in a wrong way. Google OAuth basically asks us to get a Code using which we can request it to send us a Token. The token then needs to be sent as authentication to the API Endpoint we are testing to get the desired response.

    You can first setup the App Credentials in Google Cloud Platform. Please refer this answer for the detailed steps : Using Postman to access OAuth 2.0 Google APIs

    The above step will give you important parameters like : Client_ID, Client_Secret, auth_url, redirect_uri.

    Below will be the steps that we need to follow from here on :

    1. Construct the AuthURL from these Parameters : BaseURI,Resource,scope,auth_url, client_id,responseType,redirect_uri,state

      public static void constructAuthenticationURL(String BaseURI, String Resource,String scope,
      String auth_url,String client_id,String responseType,String redirect_uri,String state) { 
      
      URL = BaseURI+Resource+"?scope="+scope+"&auth_url="+auth_url+"&client_id="+client_id+
          "&response_type="+responseType+"&redirect_uri="+redirect_uri+"&state="+state;
      
          }
      

    BaseURI - https://accounts.google.com

    Resource - /o/oauth2/v2/auth

    Scope - From API Docs

    responseType - Code

    state - empty

    1. Now we need to hit this URL in browser using Selenium and Enter Our Username and Password. We will see a blank screen with URL having code in front of "&code=".

       public static void getCodeThroughBrowserAuthentication(String Username,String Password) throws Exception {
          driver.get(URL);
          wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector
          ("input[type='email']"))).sendKeys(Username);
          driver.findElement(By.xpath("//span[text()='Next']")).click();
          wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector
          ("input[type='password']"))).sendKeys(Password);
          driver.findElement(By.xpath("//span[text()='Next']")).click();
          Thread.sleep(10000);
          String[] arr =  driver.getCurrentUrl().split("&code=");
          String code[] = arr[1].split("&scope=");
          //Store the Browser Code in a Variable to use it in Step 3
      }
      

    I have used split() to get the code out of the complete URL.

    1. Now we need to use this code to get the AccessToken(Bearer) to use it for Authenticating out request to actual Endpoint.

      public static void getBearerAccessToken() {
      RestAssured.baseURI="https://www.googleapis.com";
      Response res = given().urlEncodingEnabled(false)
      .queryParam("code", "Enter Browser code from previous step.")
      .queryParam("client_id", "Client ID from Google Cloud Platform")
      .queryParam("client_secret", "Client Secret ID from Google Cloud Platform")
      .queryParam("redirect_uri", "The one you have entered while setting up the App credentials")
      .queryParam("grant_type","authorization_code").
      when()
      .post("/oauth2/v4/token").
      then()
      .assertThat().statusCode(200).extract().response();
      
      System.out.println("The response with Access Token is : " +res.asString());
      
      JsonPath json = res.jsonPath();
      //Storing AccessToken in a Variable
      AccessToken = json.get("access_token");
      }
      
    2. Last step is to hit the Endpoint under Test using the Token we have got.

      public void getUserProfile(String email,String AccessToken) {
      RestAssured.baseURI="https://www.googleapis.com";
      Response res = given().
      auth().preemptive().oauth2(Access Token //Pass the Value of Access Token from Previous Step).
      header("Content-Type","application/json").
      queryParam("key","Setup an API Credentials Key on Google Cloud Platform.").
      
      when().
      get("/gmail/v1/users/"+email+"/profile").
      
      then().assertThat().statusCode(200).extract().response();
      
      System.out.println("User profile response : " +res.asString());
      }
      

    I will soon add the link to gitHub repo link as well If someone needs more clearer picture.