Introduction

In our REST Assured series, we’ve explored topics like Basic Authentication, GPath Expressions, and JSON Path Testing, building a robust foundation for API testing. Now, we’ll dive into Digest Authentication and Form Authentication, two essential mechanisms for securing APIs and web applications. This guide demonstrates how to implement these authentication types in REST Assured, with clear examples and best practices. It’s designed for beginners and experienced developers, ensuring you can confidently test secured endpoints.

Key Point: Digest Authentication provides a more secure alternative to Basic Authentication for APIs, while Form Authentication enables testing of web application login forms using REST Assured’s HTTP capabilities.

What are Digest and Form Authentication?

Let’s briefly define each authentication type:

  • Digest Authentication: An HTTP authentication scheme where credentials are hashed using a nonce (server-provided random value) and other parameters, sent in the Authorization header. It’s more secure than Basic Authentication as it avoids sending plaintext credentials, even over HTTPS.
  • Form Authentication: A web-based authentication method where users submit credentials (username and password) via an HTML form, typically generating a session cookie upon successful login. REST Assured can simulate form submissions to test such endpoints.

REST Assured simplifies Digest Authentication with auth().digest() and supports Form Authentication by sending POST requests with form parameters. We’ll use https://httpbin.org/digest-auth/auth/user/passwd for Digest Authentication examples, which simulates authentication with the credentials user:passwd. For Form Authentication, we’ll simulate a login form submission to a mock endpoint, as public APIs rarely use form-based auth.

Setting Up for Authentication Testing

To test Digest and Form Authentication, 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 Digest Authentication, but Form Authentication may require handling cookies, which REST Assured supports natively.

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>

No additional setup is required for https://httpbin.org for Digest Authentication. For Form Authentication, we’ll simulate a login form submission to a mock endpoint, as real public APIs with form-based auth are uncommon.

Implementing Digest Authentication

Let’s explore how to implement and test Digest Authentication using REST Assured.

Example 1: Digest Authentication with Valid Credentials

Test an API endpoint using valid Digest Authentication credentials.


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("Digest Authentication Testing")
public class DigestAuthValidTest {

    @Test
    @Description("Test Digest Authentication with valid credentials")
    public void testValidDigestAuth() {
        RestAssured.baseURI = "https://httpbin.org";

        given()
            .auth().digest("user", "passwd")
            .log().all()
        .when()
            .get("/digest-auth/auth/user/passwd")
        .then()
            .statusCode(200)
            .body("authenticated", equalTo(true))
            .body("user", equalTo("user"));
    }
}

Explanation:

  • auth().digest("user", "passwd"): Sets Digest Authentication with the username user and password passwd.
  • statusCode(200): Verifies successful authentication.
  • body("authenticated", equalTo(true)): Confirms authentication in the response.
  • log().all(): Logs request and response for debugging.
Important: Digest Authentication requires the server to send a nonce in a 401 challenge response, which REST Assured handles automatically.

Example 2: Digest Authentication with Invalid Credentials

Test an API endpoint with invalid credentials to verify error handling.


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("Digest Authentication Testing")
public class DigestAuthInvalidTest {

    @Test
    @Description("Test Digest Authentication with invalid credentials")
    public void testInvalidDigestAuth() {
        RestAssured.baseURI = "https://httpbin.org";

        given()
            .auth().digest("wronguser", "wrongpass")
            .log().ifValidationFails()
        .when()
            .get("/digest-auth/auth/user/passwd")
        .then()
            .statusCode(401);
    }
}

Explanation:

  • auth().digest("wronguser", "wrongpass"): Uses incorrect credentials.
  • statusCode(401): Expects an Unauthorized response.
  • log().ifValidationFails(): Logs details only if the test fails.

Implementing Form Authentication

Form Authentication involves submitting credentials via a POST request to a login endpoint, typically receiving a session cookie for subsequent requests. We’ll simulate a login form submission to a mock endpoint.

Assume a login form with the following HTML structure:

We’ll simulate submitting this form to a mock endpoint that expects username=user and password=pass as form parameters.

Example 3: Form Authentication with Valid Credentials

Test a form-based login and verify the session cookie for subsequent requests.


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("Form Authentication Testing")
public class FormAuthValidTest {

    @Test
    @Description("Test Form Authentication with valid credentials")
    public void testValidFormAuth() {
        RestAssured.baseURI = "https://httpbin.org";

        // Simulate form submission
        Response loginResponse = given()
            .formParam("username", "user")
            .formParam("password", "pass")
            .contentType("application/x-www-form-urlencoded")
            .log().all()
        .when()
            .post("/post") // Using /post to echo form data
        .then()
            .statusCode(200)
            .body("form.username", equalTo("user"))
            .body("form.password", equalTo("pass"))
            .extract().response();

        // Simulate using session cookie (mock example)
        String sessionCookie = loginResponse.cookie("session"); // Mock cookie
        given()
            .cookie("session", sessionCookie != null ? sessionCookie : "mock-session")
            .log().all()
        .when()
            .get("/get")
        .then()
            .statusCode(200);
    }
}

Explanation:

  • formParam("username", "user"): Sets form parameters for the login request.
  • contentType("application/x-www-form-urlencoded"): Specifies the form submission content type.
  • cookie("session", ...): Simulates using a session cookie for subsequent requests (mocked here).
  • In a real scenario, extract the actual session cookie from the login response.
Pro Tip: For Form Authentication, extract and reuse session cookies to maintain authenticated sessions across multiple requests.

Example 4: Form Authentication with Response Specification

Combine Form 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("Form Authentication Testing")
public class FormAuthWithSpecTest {

    private ResponseSpecification formSuccessSpec;

    @BeforeEach
    public void setup() {
        formSuccessSpec = new ResponseSpecBuilder()
            .expectStatusCode(200)
            .expectContentType("application/json")
            .expectBody("form.username", equalTo("user"))
            .build();
    }

    @Test
    @Description("Test Form Authentication with Response Specification")
    public void testFormAuthWithSpec() {
        RestAssured.baseURI = "https://httpbin.org";

        given()
            .formParam("username", "user")
            .formParam("password", "pass")
            .contentType("application/x-www-form-urlencoded")
            .log().all()
        .when()
            .post("/post")
        .then()
            .spec(formSuccessSpec)
            .body("form.password", equalTo("pass"));
    }
}

Explanation:

  • formSuccessSpec: Defines a specification for successful form submissions.
  • spec(formSuccessSpec): Applies the specification to validate the response.

Integrating with Allure Reporting

Document Digest and Form 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("Digest and Form Authentication Testing")
public class AllureAuthTest {

    @Test
    @Description("Test Digest Authentication with Allure reporting")
    public void testDigestAuthWithAllure() {
        RestAssured.baseURI = "https://httpbin.org";

        Response response = given()
            .auth().digest("user", "passwd")
            .log().all()
        .when()
            .get("/digest-auth/auth/user/passwd")
        .then()
            .statusCode(200)
            .body("authenticated", equalTo(true))
            .extract().response();

        Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
    }

    @Test
    @Description("Test Form Authentication with Allure reporting")
    public void testFormAuthWithAllure() {
        RestAssured.baseURI = "https://httpbin.org";

        Response response = given()
            .formParam("username", "user")
            .formParam("password", "pass")
            .contentType("application/x-www-form-urlencoded")
            .log().all()
        .when()
            .post("/post")
        .then()
            .statusCode(200)
            .body("form.username", equalTo("user"))
            .extract().response();

        Allure.addAttachment("Response Body", "application/json", response.asString(), ".json");
    }
}

Explanation:

  • Allure.addAttachment: Attaches the response body to the Allure report for both tests.
  • Run mvn clean test and mvn allure:serve to view the report.

Integrating with CI/CD

Add Digest and Form 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 credentials in environment variables or configuration files, not hardcoded in tests.
  • Understand Digest Flow: Digest Authentication involves a server challenge (401) with a nonce, which REST Assured handles transparently.
  • Handle Cookies for Form Auth: Extract and reuse session cookies to maintain authenticated sessions.
  • Log Selectively: Use log().ifValidationFails() to debug authentication failures efficiently.
Troubleshooting Tip: If authentication fails, enable log().all() to inspect headers (e.g., Authorization for Digest, cookies for Form) and verify credentials against the API or form requirements.

What’s Next?

This post enhances our REST Assured series by covering Digest and Form Authentication, key skills for testing secured APIs and web applications. To continue your learning, consider exploring:

  • OAuth 2.0 Authentication: Testing APIs with token-based authentication.
  • API Key Authentication: Handling APIs that use keys in headers or query parameters.
  • End-to-End Testing: Combining REST Assured with Selenium for UI and API testing.
Stay tuned for more testing tutorials!