Skip to content

JPostman Tutorial Part 4: Secure API Logs with jpostman secure

David Gofman edited this page Jun 15, 2026 · 5 revisions

JPostman Tutorial Part 4: Secure API Logs with jpostman-secure

Video tutorial: https://www.youtube.com/watch?v=zOci7u021oU

Overview

In this tutorial, we introduce the jpostman-secure module and show how to make API test logs safer.

When API tests fail, request and response logs are useful for troubleshooting, but they can also expose sensitive values such as passwords, access tokens, refresh tokens, cookies, API keys, emails, bank data, browser data, and user profile details.

The secure module helps protect that output while still keeping the logs useful for debugging.

You will learn how to wrap regular JPostman requests and responses with SecureRequest, SecureResponse, and SecureContext, how to mask sensitive values, how to control response headers, and how to move reusable masking rules into an INI policy file.

What You Will Learn

By the end of this tutorial, you will know how to:

  • Add the jpostman-secure dependency to a Maven test project.
  • Wrap a regular Request with SecureRequest.
  • Wrap a regular ApiResponse with SecureResponse.
  • Use SecureContext to share secure configuration across requests.
  • Mask sensitive request and response values.
  • Print unresolved placeholders with log(false).
  • Print resolved secure logs with log().
  • Store environment values as plain or protected values.
  • Use secret(env) to protect environment values.
  • Use unsecret(...) to expose selected values such as base_url.
  • Use headers(...) to protect response or request headers.
  • Use headersFilter(...) to reduce response header output.
  • Use redact(...) rules for body fields, JSON paths, wildcard paths, regex rules, and partial masking.
  • Load reusable secure policy profiles from an INI file.
  • Apply profile-specific rules with loadRules(...).
  • Use filter(...) to reduce response body output.

Prerequisites

Before starting this tutorial, make sure you completed the previous tutorials:

  • Part 1: Create a Java Maven API testing project with JPostman.
  • Part 2: Execute REST API requests using the RestAssured adapter.
  • Part 3: Chain API requests using an access token.

You should already have:

  • A Maven test project.
  • Exported Postman collection JSON file.
  • Exported Postman environment JSON file.
  • jpostman-core configured.
  • jpostman-restassured configured.
  • A working TestNG test that executes a login request and an authenticated user request.

Step 1: Add the Secure Module Dependency

Open your pom.xml file and add the jpostman-secure dependency.

Example:

To manage dependency versions with Maven properties, define the version once:

<properties>
    <java.version>11</java.version>
    <maven.compiler.release>${java.version}</maven.compiler.release>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <jpostman.version>REPLACE_WITH_LATEST_VERSION</jpostman.version>
</properties>

Then reference it from the dependency:

<dependency>
    <groupId>io.github.jpostman</groupId>
    <artifactId>jpostman-secure</artifactId>
    <version>${jpostman.version}</version>
    <scope>test</scope>
</dependency>

After updating the POM, update the Maven project from your IDE.

In Eclipse:

  1. Right-click the project or pom.xml.
  2. Select Maven.
  3. Select Update Project.
  4. Click OK.

Step 2: Create a SecureContext

Import the secure classes:

import io.jpostman.secure.SecureContext;
import io.jpostman.secure.SecureRequest;
import io.jpostman.secure.SecureResponse;

Create a secure context:

SecureContext secure = SecureContext.create();

SecureContext stores secure configuration such as redaction rules, protected values, response filters, and protected headers.

Step 3: Wrap a Request with SecureRequest

Instead of using a regular Request directly, wrap it with the secure context:

SecureRequest reqToken = secure.from(
        col.getRequest("Login user and get tokens")
                .builder()
                .build(env)
);

This creates a SecureRequest that can be printed or logged safely.

Step 4: Wrap a Response with SecureResponse

The executor still returns a regular ApiResponse. Wrap it with the same secure context:

SecureResponse resToken = secure.from(RestAssuredExecutor.execute(reqToken));

Now the response output can be protected before it is printed or added to an assertion message.

Step 5: Add Safe Assertion Output

Request and response logs are especially useful when a test fails.

Instead of printing the raw response body, use secure logging:

assertEquals(resToken.statusCode(), 200, "Body Result: " + secure.log() + "\n");

This keeps the failure message useful while masking protected values.

Step 6: Redact Additional Fields

The secure module includes default rules for common sensitive values, but you can add your own rules.

Example:

SecureContext secure = SecureContext.create()
        .redact("email");

This masks fields named email in request or response logs.

Example output:

{
  "email": "********"
}

Step 7: Compare log(false) and log()

Use log(false) when you want to inspect unresolved placeholders:

secure.log(false);

Example unresolved output:

Authorization = Bearer {{accessToken}}

Use log() when you want resolved values with masking applied:

secure.log();

Example resolved secure output:

Authorization = Bearer ********

This is helpful when debugging missing environment variables or unresolved placeholders.

Step 8: Use Plain and Secret Values

SecureContext can store values used for request resolution.

Use plain(env) when the values are safe to display:

SecureContext secure = SecureContext.create()
        .plain(env);

Use secret(env) when the values should be protected:

SecureContext secure = SecureContext.create()
        .secret(env);

With secret(env), resolved values are available for request execution, but they are masked in logs.

Step 9: Show Selected Secret Values with unsecret(...)

Sometimes one value should remain visible for debugging. For example, you may want to show base_url while still hiding tokens and passwords.

Use unsecret(...):

SecureContext secure = SecureContext.create()
        .secret(env)
        .unsecret("base_url");

This keeps base_url available and visible while the other environment values remain protected.

Step 10: Protect Headers

Use headers(...) to mask specific request or response headers.

Example:

SecureContext secure = SecureContext.create()
        .headers("Etag");

If the response contains an Etag header, its value is masked:

Etag = ********

You can also use regex header rules:

SecureContext secure = SecureContext.create()
        .headers("regex:.*cookie.*");

Step 11: Filter Response Headers

Responses may include many headers that are not needed in test failure logs.

Use headersFilter(...) to show only selected headers:

SecureContext secure = SecureContext.create()
        .headersFilter("Date");

Only matching response headers are included in the secure response log.

You can also use regex:

SecureContext secure = SecureContext.create()
        .headersFilter("regex:^x-.*");

Step 12: Move Rules into a Policy File

As rules grow, it is better to move them out of Java code and into a policy file.

Create a file under:

src/test/resources

Example file name:

demo_test_rule.ini

Example policy file:

# Default secure rules
[default]
unsecret=base_url
redact=email
headersFilter=Date

# User response rules
[user]
extends=default

# show only country code from phone values
redact=phone[regex:^\+\d{1,2}]

# hide user address only
redact=/address/address

# hide additional user details
redact=ip,bloodGroup,height,weight,eyeColor,/hair

# hide location coordinates and MAC address
redact=/**/coordinates,macAddress

# hide bank details and keep only last 4 characters
redact=cardNumber[-4:],iban[-4:]

# hide identity, browser, and crypto data
redact=ssn[-3:],userAgent,/crypto

The [default] section is applied when the policy file is loaded.

The [user] section extends [default] and adds response-specific rules for the authenticated user response.

Step 13: Load the Policy File

Load the policy file from test resources:

SecureContext secure = SecureContext.create()
        .secret(env)
        .load(getClass().getResourceAsStream("demo_test_rule.ini"));

The default rules are applied immediately.

Step 14: Apply a Named Policy Profile

Before executing or logging the authenticated user request, apply the [user] profile:

secure = secure.loadRules("user");

loadRules(...) returns a copied context with the selected rules applied. The original context is not changed.

This makes it easier to reuse a base secure context and apply different rules for different API flows.

Example:

SecureContext loginSecure = secure.loadRules("login");
SecureContext userSecure = secure.loadRules("user");

Step 15: Supported Rule Formats

Rule policy template

Policy rules support exact keys, slices, paths, wildcards, recursive wildcards, and regex matching.

# Exact key rule
redact=email

# Keep the last 4 characters
redact=cardNumber[-4:]

# Keep only the value part matching a regex
redact=phone[regex:^\+\d{1,2}]

# JSON path rule
redact=/address/address

# Wildcard path rule
redact=/products/*/reviews

# Recursive wildcard path rule
redact=/**/coordinates

# Regex key or path rule
redact=regex:.*token.*

Step 16: Reduce Response Body Output with filter(...)

After protecting sensitive data, you can reduce the response body to only the fields needed for debugging.

Example:

secure.filter("id", "firstName", "lastName", "gender");

This keeps the log shorter and easier to read.

Complete Example Flow

import static org.testng.Assert.assertEquals;

import org.testng.annotations.Test;

import io.jpostman.ApiResponse;
import io.jpostman.Collection;
import io.jpostman.Environment;
import io.jpostman.JPostman;
import io.jpostman.JPostman.Context;
import io.jpostman.secure.SecureContext;
import io.jpostman.secure.SecureRequest;
import io.jpostman.secure.SecureResponse;
import io.jpostman.restassured.RestAssuredExecutor;

public class DemoTest {

    @Test
    public void test1() throws Exception {

        Context cxt = JPostman
                .fromResources()
                .collection("DummyJSON.postman_collection.json")
                .environment("DummyJSON.postman_environment.json")
                .build();

        Environment env = cxt.getEnvironment();
        Collection col = cxt.getCollection();

        SecureContext secure = SecureContext.create()
                .secret(env)
                .load(getClass().getResourceAsStream("demo_test_rule.ini"));

        SecureRequest reqToken = secure.from(
                col.getRequest("Login user and get tokens")
                        .builder()
                        .build()
        );

        SecureResponse resToken = secure.from(RestAssuredExecutor.execute(reqToken));

        assertEquals(resToken.statusCode(), 200, "Body Result: " + secure.log() + "\n");

        secure = secure.loadRules("user");

        SecureRequest reqUser = secure.from(
                col.getRequest("Get current auth user")
                        .builder()
                        .build()
        );

        ApiResponse rawUser = RestAssuredExecutor
                .apply(reqUser)
                .auth()
                .oauth2(resToken.path("accessToken"))
                .response();

        SecureResponse resUser = secure.from(rawUser);

        assertEquals(resUser.statusCode(), 200, "Body Result: " + secure.log() + "\n");
    }
}

Update the collection, environment, and policy file names if your files use different names.

What the Test Does

This test performs a secure chained API flow:

  1. Loads the Postman collection.
  2. Loads the Postman environment.
  3. Stores environment values as protected values with secret(env).
  4. Loads reusable secure rules from demo_test_rule.ini.
  5. Executes the login request through SecureRequest.
  6. Wraps the login response as SecureResponse.
  7. Validates the login status code.
  8. Applies the [user] secure policy profile.
  9. Executes the authenticated user request.
  10. Wraps the user response as SecureResponse.
  11. Validates the user request status code.
  12. Uses secure logging for safer assertion output.

Why Secure Logs Are Useful

Secure logs help API test automation teams troubleshoot failures without exposing sensitive data.

This is useful when logs are stored in:

  • Local console output.
  • CI/CD build logs.
  • Cloud log platforms.
  • Test reports.
  • Shared issue attachments.

With jpostman-secure, you can keep enough data for debugging while masking values that should not be exposed.

Summary

In this tutorial, we added the jpostman-secure module, wrapped requests and responses with secure classes, protected environment values, masked sensitive response fields, filtered headers, and moved reusable masking rules into an INI policy file.

We also used loadRules(...) to apply a named policy profile for the authenticated user response and used filter(...) to reduce response output.

In the next tutorial, we will review additional JPostman integrations such as Vault, Kubernetes ConfigMap and Secret, and GitHub environment support.

Related Links

Clone this wiki locally