OAuth 2.0 Authentication With Gatling Using Bearer Token
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