Introduction
In our REST Assured series, we’ve covered authentication methods like Digest and Form Authentication, Basic Authentication, and GPath Expressions, equipping you with tools to test secured APIs. Now, we’ll explore three advanced authentication mechanisms: OAuth 2.0 Authentication, API Key Authentication, and Bearer Token Authentication. This guide demonstrates how to implement these in REST Assured, with practical examples and best practices. It’s designed for beginners and experienced developers, ensuring you can confidently test modern, secured APIs.
Key Point: OAuth 2.0, API Key, and Bearer Token Authentication are widely used in modern APIs, enabling secure access to protected resources. REST Assured simplifies their implementation for robust API testing.
Understanding the Authentication Mechanisms
Let’s define each authentication type:
- OAuth 2.0 Authentication: A token-based authorization framework where clients obtain an access token via a grant type (e.g., Client Credentials, Authorization Code) to access protected resources. The token is sent in the
Authorization
header. - API Key Authentication: A simple method where a unique key is included in the request (e.g., header, query parameter) to identify the client. It’s lightweight but less secure than token-based methods.
- Bearer Token Authentication: A method where a token (e.g., JWT) is sent in the
Authorization
header with the prefixBearer
. It’s commonly used with OAuth 2.0 or standalone tokens.
REST Assured supports these methods via flexible header and parameter configurations. For OAuth 2.0, we’ll use a simplified Client Credentials flow with a mock token endpoint. For API Key and Bearer Token, we’ll use https://httpbin.org
endpoints to simulate authentication.
Setting Up for Authentication Testing
We’ll set up a Maven project with REST Assured, JUnit, and Allure for reporting, consistent with previous posts. No additional dependencies are needed for these authentication types.
Here’s the pom.xml
, styled with your preferred Blogger format for XML syntax highlighting:
<project xmlns="http://maven.apache.org/POM/4.0.0">
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>rest-assured-tests</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<java.version>11</java.version>
<allure.version>2.27.0</allure.version>
<aspectj.version>1.9.22</aspectj.version>
</properties>
<dependencies>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.10.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>2.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-junit5</artifactId>
<version>${allure.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<argLine>
-javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar"</argLine>
</configuration>
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectj.version}</version>
</dependency>
</dependencies>
</plugin>
<plugin>
<groupId>io.qameta.allure</groupId>
<artifactId>allure-maven</artifactId>
<version>2.12.0</version>
<configuration>
<reportVersion>${allure.version}</reportVersion>
</configuration>
</plugin>
</plugins>
</build>
</project>
For OAuth 2.0, we’ll simulate a token endpoint. For API Key and Bearer Token, we’ll use https://httpbin.org
endpoints like /headers
to verify headers. No additional setup is required.
Implementing OAuth 2.0 Authentication
OAuth 2.0 involves obtaining an access token and using it in subsequent requests. We’ll use the **Client Credentials** flow, which is simpler for API testing, with a mock token endpoint.
Example 1: OAuth 2.0 Client Credentials Flow
Obtain an access token and use it to access a protected endpoint.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("OAuth 2.0 Authentication Testing")
public class OAuth2ClientCredentialsTest {
@Test
@Description("Test OAuth 2.0 Client Credentials flow")
public void testOAuth2ClientCredentials() {
RestAssured.baseURI = "https://httpbin.org";
// Simulate obtaining access token
Response tokenResponse = given()
.auth().preemptive().basic("client_id", "client_secret")
.formParam("grant_type", "client_credentials")
.contentType("application/x-www-form-urlencoded")
.log().all()
.when()
.post("/post") // Mock token endpoint
.then()
.statusCode(200)
.extract().response();
// Mock token (in real scenario, extract from response)
String accessToken = "mock_access_token";
// Use token in protected request
given()
.header("Authorization", "Bearer " + accessToken)
.log().all()
.when()
.get("/headers")
.then()
.statusCode(200)
.body("headers.Authorization", equalTo("Bearer " + accessToken));
}
}
Explanation:
auth().preemptive().basic("client_id", "client_secret")
: Authenticates to the token endpoint (mocked here).formParam("grant_type", "client_credentials")
: Specifies the OAuth 2.0 grant type.header("Authorization", "Bearer " + accessToken)
: Uses the token in a protected request.- In production, extract the token from the
access_token
field in the token response.
Important: For real OAuth 2.0 testing, configure client credentials and token endpoints per your API’s OAuth provider (e.g., Auth0, Okta).
Implementing API Key Authentication
API Key Authentication involves including a key in the request header or query parameter.
Example 2: API Key in Header
Test an endpoint using an API key in the request header.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("API Key Authentication Testing")
public class ApiKeyHeaderTest {
@Test
@Description("Test API Key Authentication in header")
public void testApiKeyInHeader() {
RestAssured.baseURI = "https://httpbin.org";
given()
.header("X-Api-Key", "my-api-key")
.log().all()
.when()
.get("/headers")
.then()
.statusCode(200)
.body("headers.X-Api-Key", equalTo("my-api-key"));
}
}
Explanation:
header("X-Api-Key", "my-api-key")
: Includes the API key in the request header.body("headers.X-Api-Key", ...)
: Verifies the header was sent correctly.
Example 3: API Key in Query Parameter
Test an endpoint using an API key in the query parameter.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("API Key Authentication Testing")
public class ApiKeyQueryTest {
@Test
@Description("Test API Key Authentication in query parameter")
public void testApiKeyInQuery() {
RestAssured.baseURI = "https://httpbin.org";
given()
.queryParam("api_key", "my-api-key")
.log().all()
.when()
.get("/get")
.then()
.statusCode(200)
.body("args.api_key", equalTo("my-api-key"));
}
}
Explanation:
queryParam("api_key", "my-api-key")
: Includes the API key in the query string.body("args.api_key", ...)
: Verifies the query parameter was sent.
Pro Tip: Prefer header-based API keys over query parameters for security, as query parameters may be logged in server logs.
Implementing Bearer Token Authentication
Bearer Token Authentication involves sending a token in the Authorization
header with the Bearer
prefix.
Example 4: Bearer Token Authentication
Test an endpoint using a Bearer token.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("Bearer Token Authentication Testing")
public class BearerTokenTest {
@Test
@Description("Test Bearer Token Authentication")
public void testBearerToken() {
RestAssured.baseURI = "https://httpbin.org";
String bearerToken = "my-bearer-token";
given()
.header("Authorization", "Bearer " + bearerToken)
.log().all()
.when()
.get("/headers")
.then()
.statusCode(200)
.body("headers.Authorization", equalTo("Bearer " + bearerToken));
}
}
Explanation:
header("Authorization", "Bearer " + bearerToken)
: Sends the token in theAuthorization
header.body("headers.Authorization", ...)
: Verifies the header was sent correctly.- In production, obtain the token from an OAuth 2.0 flow or another authentication mechanism.
Example 5: Bearer Token with Response Specification
Combine Bearer Token Authentication with a ResponseSpecification for reusable validation.
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.specification.ResponseSpecification;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("Bearer Token Authentication Testing")
public class BearerTokenWithSpecTest {
private ResponseSpecification authSuccessSpec;
@BeforeEach
public void setup() {
authSuccessSpec = new ResponseSpecBuilder()
.expectStatusCode(200)
.expectContentType("application/json")
.expectBody("headers.Authorization", containsString("Bearer"))
.build();
}
@Test
@Description("Test Bearer Token with Response Specification")
public void testBearerTokenWithSpec() {
RestAssured.baseURI = "https://httpbin.org";
String bearerToken = "my-bearer-token";
given()
.header("Authorization", "Bearer " + bearerToken)
.log().all()
.when()
.get("/headers")
.then()
.spec(authSuccessSpec)
.body("headers.Authorization", equalTo("Bearer " + bearerToken));
}
}
Explanation:
authSuccessSpec
: Defines a specification for successful Bearer Token responses.spec(authSuccessSpec)
: Applies the specification to validate the response.
Integrating with Allure Reporting
Document authentication tests with Allure, attaching request and response details.
import io.qameta.allure.Allure;
import io.qameta.allure.Description;
import io.qameta.allure.Feature;
import io.restassured.RestAssured;
import io.restassured.response.Response;
import org.junit.jupiter.api.Test;
import static io.restassured.RestAssured.*;
import static org.hamcrest.Matchers.*;
@Feature("OAuth 2.0, API Key, and Bearer Token Authentication Testing")
public class AllureAuthTest {
@Test
@Description("Test OAuth 2.0 with Allure reporting")
public void testOAuth2WithAllure() {
RestAssured.baseURI = "https://httpbin.org";
Response tokenResponse = given()
.auth().preemptive().basic("client_id", "client_secret")
.formParam("grant_type", "client_credentials")
.contentType("application/x-www-form-urlencoded")
.log().all()
.when()
.post("/post")
.then()
.statusCode(200)
.extract().response();
String accessToken = "mock_access_token";
Response protectedResponse = given()
.header("Authorization", "Bearer " + accessToken)
.log().all()
.when()
.get("/headers")
.then()
.statusCode(200)
.extract().response();
Allure.addAttachment("Token Response", "application/json", tokenResponse.asString(), ".json");
Allure.addAttachment("Protected Response", "application/json", protectedResponse.asString(), ".json");
}
@Test
@Description("Test API Key with Allure reporting")
public void testApiKeyWithAllure() {
RestAssured.baseURI = "https://httpbin.org";
Response response = given()
.header("X-Api-Key", "my-api-key")
.log().all()
.when()
.get("/headers")
.then()
.statusCode(200)
.extract().response();
Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
}
@Test
@Description("Test Bearer Token with Allure reporting")
public void testBearerTokenWithAllure() {
RestAssured.baseURI = "https://httpbin.org";
String bearerToken = "my-bearer-token";
Response response = given()
.header("Authorization", "Bearer " + bearerToken)
.log().all()
.when()
.get("/headers")
.then()
.statusCode(200)
.extract().response();
Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
}
}
Explanation:
Allure.addAttachment
: Attaches response bodies to the Allure report for each test.- Run
mvn clean test
andmvn allure:serve
to view the report.
Integrating with CI/CD
Add authentication tests to a GitHub Actions pipeline for automation.
Create or update .github/workflows/ci.yml
:
name: REST Assured CI Pipeline
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
build-and-test:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
- name: Cache Maven dependencies
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
restore-keys: ${{ runner.os }}-maven-
- name: Run tests
run: mvn clean test
- name: Generate Allure report
run: mvn allure:report
- name: Upload Allure results
if: always()
uses: actions/upload-artifact@v4
with:
name: allure-results
path: target/allure-results
- name: Publish Allure report
if: always()
uses: simple-elf/allure-report-action@v1.7
with:
allure_results: target/allure-results
gh_pages: gh-pages
allure_report: allure-report
- name: Deploy report to GitHub Pages
if: always()
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: allure-report
Explanation:
- Runs authentication tests with
mvn clean test
. - Publishes Allure reports to GitHub Pages for visibility.
Tips for Beginners
- Secure Credentials: Store OAuth client IDs, API keys, and tokens in environment variables or secure vaults, not hardcoded in tests.
- Understand OAuth Flows: Start with Client Credentials for machine-to-machine APIs; explore Authorization Code for user-based flows.
- Validate Tokens: Check token expiration and refresh tokens as needed in production tests.
- Log Selectively: Use
log().ifValidationFails()
to debug authentication failures efficiently.
Troubleshooting Tip: If authentication fails, enablelog().all()
to inspect headers (e.g.,Authorization
,X-Api-Key
) and verify credentials against API documentation.
What’s Next?
This post enhances our REST Assured series by covering OAuth 2.0, API Key, and Bearer Token Authentication, essential for modern API testing. To continue your learning, consider exploring:
- GraphQL Testing: Testing GraphQL APIs with REST Assured.
- Advanced Allure Reporting: Customizing reports with environments and categories.
- End-to-End Testing: Combining REST Assured with Selenium for UI and API testing.