OAuth 2.0 Authentication With Gatling Using Bearer Token

Amir Ghahrai

Amir Ghahrai

Follow on Twitter


This post explains how to do Oauth2 Authentication with Gatling.

In this example, we are sending a request to create a user. However, the user endpoint is protected and requires an access_token.

First, we will get a bearer_token or an access_token and then send it as a header to the next API request to create a user.

To illustrate this, we will be using the same project structure for Gatling that we built previously:

Performance Testing Framework with Gatling and Maven

When we follow the steps in the above post, we would have our project structure as follows:

Defining Parameters in Configuration

First we define our OAuth 2.0 parameters in the Configuration.scala object file under the config folder:

object Configuration {
  val environment: String = System.getProperty("environment")
  val clientId: String = System.getProperty("CLIENT_ID")
  val clientSecret: String = System.getProperty("CLIENT_SECRET")
  val apiURL: String = "https://some-sub-domain." + environment + "some-domain.com/api"
  var tokenPath: String = "https://some-sub-domain" + environment + ".eu.auth0.com/oauth/token"
  val userPath = "/identity/iaa/v1/users"
}

Requests

Now we need to write the code that sends the request to the authorization server to get a bearer token.

OAuth 2.0 Request - access_token

This file AuthRequest.scala is saved under the requests folder in our project structure.

import java.io.{BufferedWriter, FileWriter}

import config.Configuration
import io.gatling.core.Predef._
import io.gatling.http.Predef._

object AuthRequest {

  val getAccessToken = exec(http("Get access token")
    .post(Configuration.tokenPath)
    .body(StringBody(
      s"""{
          "client_id": "${Configuration.clientId}",
          "client_secret": "${Configuration.clientSecret}",
          "audience": "https://some-domain-name.com/user",
          "grant_type": "client_credentials",
          "scope": "user:admin"
        }"""
    ))
    .asJson
    .headers(Map("Content-Type" -> "application/json"))
    .check(status.is(200))
    .check(jsonPath("$.access_token").saveAs("access_token")))
    .exec {
      session =>
        val fw = new BufferedWriter(new FileWriter("access_token.txt", true))
        try {
          fw.write(session("access_token").as[String] + "\r\n")
        }
        finally fw.close()
        session
    }
}

In the above code snippet, we are also saving the access_token to a file.

The above call, just gets the access_token.

We need another request to create a user by sending the access_token as the header.

User Request

Our user request is in a file called UserRequests.scala and is saved under the requests folder.

import config.Configuration.{apiURL, userPath}
import io.gatling.core.Predef._
import io.gatling.http.Predef._

object UserRequests {

  private val auth0Headers = Map(
    "Accept" -> "application/json, text/javascript, */*; q=0.01",
    "Content-Type" -> "application/json",
    "Authorization" -> "Bearer ${access_token}")

  val createUser = exec(http("Create user")
    .post(apiURL + userPath)
    .headers(auth0Headers)
    .body(ElFileBody("createUser.json"))
    .check(status.is(201)))
}

Scenario

Now we write out scenario object. In this example our object is called UserScenarios.scala and is saved under the scenario folder.

import requests.{AuthRequest, UserRequests}
import io.gatling.core.Predef._

object UserScenarios {

  var userIds:Array[Map[String,String]] =
    (100 to 900).toArray map ( x => { Map( "userId" -> x.toString) })

  val getAccessToken = scenario("Get token")
    .exec(AuthRequest.getAccessToken)

  val createUserScenario = scenario("Create user")
    .feed(userIds.circular)
    .exec(UserAuthZRequest.getAccessToken)
    .exec(UserRequests.createUser)
}

The above request, sends a POST request to create a user with the access_token as a bearer in the header.

Simulation

Finally our simulation file called UserSimulation.scala is saved under the simulations folder.

import scenario.UserScenarios
import io.gatling.core.Predef._
import scala.concurrent.duration._

class UserSimulation extends Simulation {
  setUp(
    UserScenarios.createUserScenario.inject(rampUsers(250) during (15 minutes)),
  )
}

To run the tests we use

mvn clean gatling:test
#gatling #performance