Multiple techniques can be used to lock down MockServer deployments, as follows:

  • limit network access to MockServer, i.e. only available on localhost
  • launch MockServer on-demand, i.e. just before tests, and shutdown immediately after
  • disable or restrict cross-site requests using CORS
  • restrict content or functionality of javascript, velocity or mustache templates
  • authenticate all TCP connections using mTLS
  • authenticate all REST API i.e. control plane requests using mTLS
  • authenticate all REST API i.e. control plane requests using JWT
  • authenticate all REST API i.e. control plane requests using a username and password (HTTP Basic over HTTPS)
  • set security-focused configuration property values — see Configuration Hardening below

Proxy Authentication: When MockServer is used as an HTTP proxy, it supports HTTP Basic proxy authentication (RFC 7235) on the data plane via three configuration properties: proxyAuthenticationUsername, proxyAuthenticationPassword, and proxyAuthenticationRealm. When these are configured, MockServer responds with 407 Proxy Authentication Required and a Proxy-Authenticate: Basic realm="…" header to any CONNECT or forwarded request that does not include valid Proxy-Authorization credentials. The authentication mechanisms described below secure the control plane (expectation management, verification, retrieval, etc.), which is separate from this data-plane proxy authentication.

Data-Plane Authentication: to require credentials (HTTP Basic, a bearer token or an API key) on the mocked endpoints themselves, set dataPlaneAuthenticationRequired and the related properties described in Data Plane Authentication Configuration. It applies to the standalone MockServer server (JAR, Docker image, Helm chart, and the JUnit, Spring and Testcontainers integrations), the WAR deployments and the in-process server, but not to DNS mocking.

Common confusion: The MockServerClient.withProxyConfiguration() method configures how the client connects to MockServer through an upstream proxy—it does not add authentication to MockServer itself. See the client documentation for details.

 

Control Plane Authentication

Authentication can be enabled for all control plane requests (i.e. create expectations, clear, reset, verify, retrieve, stop, etc) using mTLS, JWT, OIDC, HTTP Basic, or a combination.

If both mTLS and JWT are enabled mTLS will be validated first.

Control plane authentication settings cannot be changed with PUT /mockserver/configuration. Every setting that decides who may use the control plane, or what each user may do — the mTLS, JWT, OIDC and Basic settings, controlPlaneAuthorizationEnabled and controlPlaneScopeMapping — is fixed at startup as far as the control plane is concerned. A PUT that supplies a different value is still answered, but the value is ignored and a warning is logged, so nobody who can change MockServer's configuration over the network can switch authentication off, trust their own keys or give themselves a role. In-process code can still change them: the settings are re-read from the current configuration on every request, so a system property or a Configuration setter on a running MockServer takes effect immediately.

So, if you run MockServer embedded, set the CA chain on the Configuration instance you start the server with rather than through the global static properties, so unrelated code in the same JVM (including other tests) cannot move it.

 

Control Plane mTLS Authentication

When mTLS authentication is enabled all control plane requests need to be received over a mTLS connection where the client's X509 certificate can be validated using the controlPlaneTLSMutualAuthenticationCAChain.

MockServer checks only the client's own certificate, the one whose private key the client used for the connection. It must be signed by a CA in the chain, either directly or through intermediate CA certificates that the client sends after it; any other certificate the client sends is used only to find that path and is never trusted on its own. The client certificate must be in date (and so must any intermediate), must not itself be a CA certificate or self-signed, must not be one of the certificates in the chain, must allow digital signatures if it lists key usages, and must allow client authentication if it lists extended key usages. A self-signed client certificate is never accepted, even if you put it in the chain: sign client certificates with a CA instead.

Security fix: MockServer 5.13.0 to 9.2.0 accepted a connection if any certificate the client sent could be validated. Because a CA certificate is public, anyone who could reach the control plane could send their own certificate followed by your CA certificate and be authenticated. Also requiring client certificates for every connection (tlsMutualAuthenticationRequired) did not stop this unless MockServer had its own CA: that check also trusts MockServer's CA, which by default is the CA bundled with MockServer, and its private key is published, so anyone can sign a certificate it accepts. Upgrade, and if a MockServer that others could reach had control plane mTLS on, treat its expectations, recorded traffic and settings as possibly read or changed by someone else.

The bundled CA is never trusted for control plane mTLS. If controlPlaneTLSMutualAuthenticationCAChain contains the CA bundled with MockServer, MockServer refuses to start; earlier versions only logged a warning.

MockServer accepts only client certificates signed by a CA in that chain. If the chain is not set, it accepts client certificates signed by its own CA certificate (mockserver.certificateAuthorityCertificate, or the CA it creates when mockserver.dynamicallyCreateCertificateAuthorityCertificate is enabled), unless that is the CA bundled with MockServer, which must not be trusted for control plane client certificates. MockServer therefore refuses to start with control plane mTLS enabled, no chain and the bundled CA, and answers 400 to a PUT /mockserver/configuration that would lead to that set-up by changing MockServer's CA; the message says how to fix it: set controlPlaneTLSMutualAuthenticationCAChain, or give MockServer its own CA with mockserver.certificateAuthorityCertificate and mockserver.certificateAuthorityPrivateKey.

Changed: earlier versions also accepted client certificates signed by MockServer's own CA certificate when controlPlaneTLSMutualAuthenticationCAChain was set. If your control plane client certificates are signed by MockServer's CA, add that CA to the chain. If MockServer's CA is the bundled default, sign your client certificates with your own CA instead; MockServer logs a warning if the chain includes the bundled CA. Earlier versions also started with control plane mTLS enabled, no chain and the bundled CA; that set-up is now refused, as described above.

Enable mTLS authentication for control plane interactions (i.e. create expectations, clear, reset, verify, retrieve, stop, etc)

If enabled then all control plane requests need to be received over a mTLS connection where the client's X509 certificate will be validated using the controlPlaneTLSMutualAuthenticationCAChain

It is possible to enable both controlPlaneJWTAuthenticationRequired and controlPlaneTLSMutualAuthenticationRequired but the mTLS will be checked first.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: boolean Default: false

Java Code:

ConfigurationProperties.controlPlaneTLSMutualAuthenticationRequired(boolean controlPlaneTLSMutualAuthenticationRequired)

System Property:

-Dmockserver.controlPlaneTLSMutualAuthenticationRequired=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_TLS_MUTUAL_AUTHENTICATION_REQUIRED=...

Property File:

mockserver.controlPlaneTLSMutualAuthenticationRequired=...

Example:

-Dmockserver.controlPlaneTLSMutualAuthenticationRequired="true"

File system path or classpath location of the CA (i.e. trust) chain to use to validate client X509 certificates if controlPlaneTLSMutualAuthenticationRequired is enabled

MockServer accepts only client certificates signed by a CA in this chain; earlier versions also accepted those signed by MockServer's own CA certificate. If it is not set, MockServer accepts client certificates signed by its own CA certificate, unless that is the bundled default CA: then MockServer refuses to start (and refuses a configuration update that would lead there) until you set this chain or give MockServer its own CA with certificateAuthorityCertificate and certificateAuthorityPrivateKey.

In the JVM running MockServerClient the same property holds the only CAs the client trusts for MockServer's own certificate, so the client's value must include the CA that signed MockServer's certificate (MockServer's CA certificate unless MockServer is given its own certificate). Earlier versions also trusted MockServer's CA certificate automatically.

MockServer refuses to start if this chain contains the CA bundled with MockServer, whose private key is published, because anyone could then create an accepted client certificate. If MockServerClient and MockServer share this property in one JVM, give MockServer its own CA with mockserver.certificateAuthorityCertificate and mockserver.certificateAuthorityPrivateKey and put that CA in the chain.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneTLSMutualAuthenticationCAChain(String controlPlaneTLSMutualAuthenticationCAChain)

System Property:

-Dmockserver.controlPlaneTLSMutualAuthenticationCAChain=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_TLS_MUTUAL_AUTHENTICATION_CERTIFICATE_CHAIN=...

Property File:

mockserver.controlPlaneTLSMutualAuthenticationCAChain=...

Example:

-Dmockserver.controlPlaneTLSMutualAuthenticationCAChain="/some/existing/path"

File system path or classpath location of the private key used by MockServerClient when controlPlaneTLSMutualAuthenticationRequired is enabled to ensure control plane request are correctly authorised

For control plane requests to be authorised the private key controlPlanePrivateKeyPath and certificate controlPlaneX509CertificatePath must:

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlanePrivateKeyPath(String controlPlanePrivateKeyPath)

System Property:

-Dmockserver.controlPlanePrivateKeyPath=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_TLS_PRIVATE_KEY_PATH=...

Property File:

mockserver.controlPlanePrivateKeyPath=...

Example:

-Dmockserver.controlPlanePrivateKeyPath="/some/existing/path"

File system path or classpath location of the certificate used by MockServerClient when controlPlaneTLSMutualAuthenticationRequired is enabled to ensure control plane request are correctly authorised

For control plane requests to be authorised the private key controlPlanePrivateKeyPath and certificate controlPlaneX509CertificatePath must:

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneX509CertificatePath(String controlPlaneX509CertificatePath)

System Property:

-Dmockserver.controlPlaneX509CertificatePath=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_TLS_X509_CERTIFICATE_PATH=...

Property File:

mockserver.controlPlaneX509CertificatePath=...

Example:

-Dmockserver.controlPlaneX509CertificatePath="/some/existing/path"
 

Control Plane JWT Authentication

When JWT authentication is enabled all control plane requests need and JWT via a authorization header which is validated using the controlPlaneJWTAuthenticationJWKSource

Enable JWT authentication for control plane interactions (i.e. create expectations, clear, reset, verify, retrieve, stop, etc)

If enabled then all control plane requests need and JWT via a authorization header which is validated using the controlPlaneJWTAuthenticationJWKSource

It is possible to enable both controlPlaneJWTAuthenticationRequired and controlPlaneTLSMutualAuthenticationRequired but the mTLS will be checked first.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: boolean Default: false

Java Code:

ConfigurationProperties.controlPlaneJWTAuthenticationRequired(boolean controlPlaneJWTAuthenticationRequired)

System Property:

-Dmockserver.controlPlaneJWTAuthenticationRequired=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_JWT_AUTHENTICATION_REQUIRED=...

Property File:

mockserver.controlPlaneJWTAuthenticationRequired=...

Example:

-Dmockserver.controlPlaneJWTAuthenticationRequired="true"

URL, file system path or classpath location of the JWK source when controlPlaneJWTAuthenticationRequired is enabled to validate JWT signatures

For control plane requests to be authorised:

  • they must include an authorization header, with a Bearer auth scheme, containing a JWT
  • the JWT should be validated by a key in the JWK source

For details of JWK see the JWK specification

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneJWTAuthenticationJWKSource(String controlPlaneJWTAuthenticationJWKSource)

System Property:

-Dmockserver.controlPlaneJWTAuthenticationJWKSource=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_JWT_AUTHENTICATION_JWK_SOURCE=...

Property File:

mockserver.controlPlaneJWTAuthenticationJWKSource=...

Example:

-Dmockserver.controlPlaneJWTAuthenticationJWKSource="/some/existing/path"

Audience claim (i.e. aud) a control-plane JWT must carry when JWT authentication is enabled. When empty (the default), the audience claim is not checked — any validly-signed token is accepted regardless of its audience. Set it to the audience your issuer puts in tokens meant for this MockServer instance to reject tokens issued for other services.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: ""

Java Code:

ConfigurationProperties.controlPlaneJWTAuthenticationExpectedAudience(String controlPlaneJWTAuthenticationExpectedAudience)

System Property:

-Dmockserver.controlPlaneJWTAuthenticationExpectedAudience=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_JWT_AUTHENTICATION_EXPECTED_AUDIENCE=...

Property File:

mockserver.controlPlaneJWTAuthenticationExpectedAudience=...

Example:

-Dmockserver.controlPlaneJWTAuthenticationExpectedAudience="mockserver-control-plane"

Matching claims expected when JWT authentication is enabled for control plane requests

Value should be string with comma separated key=value items, for example: scope=internal public,sub=some_subject

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneJWTAuthenticationMatchingClaims(Map<String, String> controlPlaneJWTAuthenticationMatchingClaims)

System Property:

-Dmockserver.controlPlaneJWTAuthenticationMatchingClaims=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_JWT_AUTHENTICATION_MATCHING_CLAIMS=...

Property File:

mockserver.controlPlaneJWTAuthenticationMatchingClaims=...

Example:

-Dmockserver.controlPlaneJWTAuthenticationMatchingClaims="scope=internal,sub=user-123"

Required claims that should exist (i.e. with any value) when JWT authentication is enabled for control plane requests

Value should be string with comma separated values, for example: scope,sub

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneJWTAuthenticationRequiredClaims(Set<String> controlPlaneJWTAuthenticationRequiredClaims)

System Property:

-Dmockserver.controlPlaneJWTAuthenticationRequiredClaims=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_JWT_AUTHENTICATION_REQUIRED_CLAIMS=...

Property File:

mockserver.controlPlaneJWTAuthenticationRequiredClaims=...

Example:

-Dmockserver.controlPlaneJWTAuthenticationRequiredClaims="scope,sub"
 

Control Plane OIDC Authentication

When OIDC authentication is enabled all control plane requests need a Bearer access token via an authorization header issued by an external OpenID Connect identity provider. The token signature is verified against the provider's JWK set (configured directly via controlPlaneOidcJwksUri or discovered from controlPlaneOidcIssuer), and its issuer, audience, expiry and required scopes are checked. The verified subject is recorded as the principal in the control plane audit log.

Enable verified OIDC authentication for control plane interactions (i.e. create expectations, clear, reset, verify, retrieve, stop, etc) using access tokens issued by an external OpenID Connect identity provider

If enabled then all control plane requests must include a Bearer access token via an authorization header. The token signature is verified against the provider's JWK set, and its issuer, audience, expiry and required scopes are checked. The verified subject (sub) is recorded as the principal in the control plane audit log.

For security, the OIDC handler enforces the following secure-by-default requirements (MockServer will refuse to start the OIDC handler, and fail every control plane request closed with a 401, if any are not met):

  • At least one of controlPlaneOidcIssuer or controlPlaneOidcAudience must be set — without either, any validly-signed token from the JWK set would be accepted regardless of who it was issued for.
  • A remote controlPlaneOidcJwksUri (or issuer used for discovery) must use https://. Plaintext http:// is allowed only for localhost/loopback (local testing).
  • Tokens must carry an exp (expiry) claim, and are verified only against asymmetric signing algorithms (RS*, PS*, ES*, EdDSA) — HMAC and unsigned (alg=none) tokens are always rejected.

When a control plane request fails OIDC authentication the client receives a generic Unauthorized for control plane response; the detailed reason (e.g. expected issuer/audience/scopes) is written only to the MockServer server log.

It is possible to enable controlPlaneOidcAuthenticationRequired alongside controlPlaneTLSMutualAuthenticationRequired and/or controlPlaneJWTAuthenticationRequired, in which case every enabled handler must pass.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: boolean Default: false

Java Code:

ConfigurationProperties.controlPlaneOidcAuthenticationRequired(boolean controlPlaneOidcAuthenticationRequired)

System Property:

-Dmockserver.controlPlaneOidcAuthenticationRequired=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_OIDC_AUTHENTICATION_REQUIRED=...

Property File:

mockserver.controlPlaneOidcAuthenticationRequired=...

Example:

-Dmockserver.controlPlaneOidcAuthenticationRequired="true"

Issuer (i.e. iss) required on control plane OIDC tokens. When controlPlaneOidcJwksUri is not set, the JWKS URI is discovered from this issuer's OIDC discovery document at {issuer}/.well-known/openid-configuration.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneOidcIssuer(String controlPlaneOidcIssuer)

System Property:

-Dmockserver.controlPlaneOidcIssuer=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_OIDC_ISSUER=...

Property File:

mockserver.controlPlaneOidcIssuer=...

Example:

-Dmockserver.controlPlaneOidcIssuer="https://idp.example.com"

JWKS URI used to verify control plane OIDC token signatures. If not set, it is discovered from the issuer's OIDC discovery document. A remote URI must use https:// (plaintext http:// is permitted only to localhost/loopback); a file or classpath path may also be used.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneOidcJwksUri(String controlPlaneOidcJwksUri)

System Property:

-Dmockserver.controlPlaneOidcJwksUri=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_OIDC_JWKS_URI=...

Property File:

mockserver.controlPlaneOidcJwksUri=...

Example:

-Dmockserver.controlPlaneOidcJwksUri="https://idp.example.com/.well-known/jwks.json"

Audience claim (i.e. aud) required on control plane OIDC tokens.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneOidcAudience(String controlPlaneOidcAudience)

System Property:

-Dmockserver.controlPlaneOidcAudience=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_OIDC_AUDIENCE=...

Property File:

mockserver.controlPlaneOidcAudience=...

Example:

-Dmockserver.controlPlaneOidcAudience="mockserver-control-plane"

Scopes that must all be present in a control plane OIDC token before it is accepted.

Value should be a string with comma separated values, for example: mockserver.read,mockserver.write

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: null

Java Code:

ConfigurationProperties.controlPlaneOidcRequiredScopes(Set<String> controlPlaneOidcRequiredScopes)

System Property:

-Dmockserver.controlPlaneOidcRequiredScopes=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_OIDC_REQUIRED_SCOPES=...

Property File:

mockserver.controlPlaneOidcRequiredScopes=...

Example:

-Dmockserver.controlPlaneOidcRequiredScopes="mockserver.read,mockserver.write"

Name of the claim holding granted scopes on a control plane OIDC token. Default scope is read as a space-delimited string; array claims such as scp, roles or groups are also supported.

This setting is startup-only: set it before MockServer starts (system property, environment variable, property file or Configuration). A PUT /mockserver/configuration request cannot change it (a different value is ignored and a warning is logged), so a caller of the control plane cannot change who may use it.

Type: string Default: scope

Java Code:

ConfigurationProperties.controlPlaneOidcScopeClaim(String controlPlaneOidcScopeClaim)

System Property:

-Dmockserver.controlPlaneOidcScopeClaim=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_OIDC_SCOPE_CLAIM=...

Property File:

mockserver.controlPlaneOidcScopeClaim=...

Example:

-Dmockserver.controlPlaneOidcScopeClaim="scp"

Once OIDC authentication verifies a principal, that principal's scopes/groups can be mapped to a coarse control-plane role (read, mutate or admin) and used to authorize individual admin operations — see Control-Plane Authorization for controlPlaneAuthorizationEnabled and controlPlaneScopeMapping.

 

Control Plane Basic Authentication

When Basic authentication is enabled, control plane requests can authenticate with a username and password sent in an authorization header (Authorization: Basic ...), which every HTTP client and browser supports. It suits shared test environments where issuing certificates or tokens is more than you need.

  • Passwords are never configured in plain text. Each user is configured with a bcrypt, argon2 or PBKDF2 hash of their password, for example the output of htpasswd -nbB -C 12 admin 'my password'.
  • HTTPS only. Credentials sent over plain HTTP are refused, so connect to MockServer with https:// (MockServer serves HTTP and HTTPS on the same port).
  • Password guessing is slowed down. After 5 wrong passwords from one address, that address must wait before trying again, starting at 1 second and doubling up to 60 seconds. Users who already logged in are not affected, but clients behind one shared address (a NAT gateway or a load balancer) share the wait for new logins.
  • It is an alternative, not an extra check. With mTLS, JWT or OIDC also enabled, a request is accepted if it has valid Basic credentials or passes the other enabled methods, so you can give scripts a password while services keep using tokens.
  • Who did what is recorded. The user name is the principal in the control plane audit log, and the optional scopes configured for a user decide its role when authorization is enabled.
  • A request refused over HTTPS gets a WWW-Authenticate: Basic challenge, so a browser opening the dashboard over HTTPS prompts for the username and password; over plain HTTP it does not, so a browser is never asked to send the password unencrypted.
  • Passwords are kept out of logs. Control plane requests are recorded in MockServer's log (what retrieve, the dashboard and the logged entries show) with their credentials masked, whether they succeed, fail or are cut short, at every log level. The exception is TRACE, which also prints the raw network traffic, headers included, to the console or log file, so do not run TRACE where those are shared. Every client warns if you configure Basic credentials on a plain HTTP connection.

The settings are fixed at startup and cannot be changed with PUT /mockserver/configuration. Every MockServer client can send Basic credentials, on its HTTP requests and on the WebSockets it opens for callbacks and breakpoints; for example in Java:

new MockServerClient("localhost", 1080)
    .withSecure(true)
    .withControlPlaneBasicAuthentication("admin", System.getenv("MOCKSERVER_PASSWORD"));

Accept HTTP Basic credentials (a username and password) for control plane interactions (i.e. create expectations, clear, reset, verify, retrieve, stop, etc). The users are configured with controlPlaneBasicAuthenticationCredentials or controlPlaneBasicAuthenticationUsersFile.

Basic credentials are only accepted over HTTPS: a request that sends them over plain HTTP is refused with a 401, because anyone on the network path could read the password, and a plain-HTTP 401 never asks a browser for a password. After 5 wrong passwords from one address, that address must wait (1 second, then 2, 4, ... up to 60 seconds) before new credentials are checked again. A user who already logged in successfully is not locked out. Clients that reach MockServer through one shared address, such as a NAT gateway or a load balancer that hides client addresses, share that wait, so one client guessing passwords slows down new logins for all of them.

Basic is an alternative to the other control plane authentication methods: when it is enabled alongside mTLS, JWT or OIDC, a request is accepted if it has valid Basic credentials or it passes the other enabled methods. The user name is recorded as the principal in the control plane audit log.

This setting is fixed at startup: PUT /mockserver/configuration cannot change it.

Type: boolean Default: false

Java Code:

ConfigurationProperties.controlPlaneBasicAuthenticationRequired(boolean controlPlaneBasicAuthenticationRequired)

System Property:

-Dmockserver.controlPlaneBasicAuthenticationRequired=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_BASIC_AUTHENTICATION_REQUIRED=...

Property File:

mockserver.controlPlaneBasicAuthenticationRequired=...

Example:

-Dmockserver.controlPlaneBasicAuthenticationRequired="true"

The users allowed to use the control plane with Basic authentication, each as username:passwordHash or username:passwordHash:scopes, separated by ; or new lines.

Plain text passwords are refused. The password must be given as a hash in one of these formats:

  • bcrypt ($2y$, $2b$, $2a$) — for example from htpasswd -nbB -C 12 admin 'my password', whose output line can be used as it is
  • argon2 ($argon2id$, $argon2i$, $argon2d$) — for example from echo -n 'my password' | argon2 "$(openssl rand -hex 8)" -id -e
  • PBKDF2 ($pbkdf2-sha256$, $pbkdf2-sha512$) — for example from Python's passlib: pbkdf2_sha256.hash('my password'). PBKDF2 needs no extra libraries, so use it when MockServer runs with BouncyCastle FIPS instead of the standard BouncyCastle library.

The optional scopes (separated by spaces or commas) give the user roles when control plane authorization is enabled: they are mapped to roles by controlPlaneScopeMapping, just like OIDC scopes.

Work factors must be sensible: bcrypt cost 4 to 16, PBKDF2 10,000 to 10,000,000 iterations, and argon2 at most 256 MiB of memory, 16 passes and 16 lanes, because every password check runs while requests wait. MockServer warns at startup about a hash below current OWASP guidance (bcrypt cost 10, PBKDF2-SHA256 600,000 iterations, argon2id 19 MiB with 2 passes) — htpasswd -B defaults to cost 5, so pass -C 12.

MockServer refuses to start if Basic authentication is enabled and no users are configured, or any entry is not in one of these formats or outside these limits. The value is hidden in the printed configuration and is never returned by GET /mockserver/configuration. It is fixed at startup.

Type: string Default: ""

Java Code:

ConfigurationProperties.controlPlaneBasicAuthenticationCredentials(String controlPlaneBasicAuthenticationCredentials)

System Property:

-Dmockserver.controlPlaneBasicAuthenticationCredentials=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_BASIC_AUTHENTICATION_CREDENTIALS=...

Property File:

mockserver.controlPlaneBasicAuthenticationCredentials=...

Example:

MOCKSERVER_CONTROL_PLANE_BASIC_AUTHENTICATION_CREDENTIALS='admin:$2y$12$Qv0yN...:platform-admins;ci:$2y$12$9fT2a...:qa-team'

Path to a file of control plane Basic authentication users, one username:passwordHash[:scopes] per line, in the same formats as controlPlaneBasicAuthenticationCredentials. This is the format htpasswd -B writes, so a file it maintains can be used directly. Blank lines and lines starting with # are ignored. Users from the file and from controlPlaneBasicAuthenticationCredentials are combined.

The file holds password hashes, so make it readable only by the user MockServer runs as. It is read when the server starts, and again whenever another control plane authentication setting changes while the server runs.

Type: string Default: ""

Java Code:

ConfigurationProperties.controlPlaneBasicAuthenticationUsersFile(String controlPlaneBasicAuthenticationUsersFile)

System Property:

-Dmockserver.controlPlaneBasicAuthenticationUsersFile=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_BASIC_AUTHENTICATION_USERS_FILE=...

Property File:

mockserver.controlPlaneBasicAuthenticationUsersFile=...

Example:

-Dmockserver.controlPlaneBasicAuthenticationUsersFile="/etc/mockserver/control-plane.htpasswd"

For tests only. Accept control plane Basic credentials sent over plain HTTP. Without TLS the password crosses the network in a form anyone on the path can decode, so never enable this where the network is shared. Behind a proxy that terminates TLS, have the proxy connect to MockServer over HTTPS instead. MockServer logs a warning at startup when this is enabled. It is fixed at startup.

Type: boolean Default: false

Java Code:

ConfigurationProperties.controlPlaneBasicAuthenticationAllowInsecure(boolean controlPlaneBasicAuthenticationAllowInsecure)

System Property:

-Dmockserver.controlPlaneBasicAuthenticationAllowInsecure=...

Environment Variable:

MOCKSERVER_CONTROL_PLANE_BASIC_AUTHENTICATION_ALLOW_INSECURE=...

Property File:

mockserver.controlPlaneBasicAuthenticationAllowInsecure=...

Example:

-Dmockserver.controlPlaneBasicAuthenticationAllowInsecure="true"
 

Control Plane Authorization

Once a principal has been authenticated, you can layer a coarse role-based authorization check on top. Authorization maps the verified principal's OIDC scopes or groups, or the scopes configured for a Basic authentication user, to one of three hierarchical roles and enforces them on every control-plane operation.

Prerequisite: Authorization requires a verified principal, so OIDC authentication must be configured. Without authentication there is no principal and authorization has nothing to enforce.

Important limitations:

  • The health/lifecycle probes /mockserver/status and /mockserver/ready are neither authenticated nor authorized — they are always reachable so health-check infrastructure never needs credentials. (/mockserver/bind and /mockserver/stop are authenticated when control-plane authentication is enabled.)
  • The dashboard (/mockserver/dashboard) and its live UI WebSocket require the same control-plane authentication as every other control-plane endpoint when it is enabled — otherwise anyone with network reach could read all captured traffic. The dashboard is a read, so a read-only role may view it. When no control-plane authentication is configured (the default) the dashboard stays open. Because a browser cannot attach a bearer token to a WebSocket, a token/OIDC-authenticated dashboard must be served through an authenticating reverse proxy (or use mutual TLS).
  • MockServer's own MCP control plane (/mockserver/mcp) is authenticated (the bearer token is validated), but per-tool authorization is not yet enforced. Treat any authenticated MCP session as mutate-capable.
  • The Prometheus scrape endpoint /mockserver/metrics goes through the same control-plane authentication/authorization gate as every other control-plane endpoint. Control-plane authentication is opt-in and off by default, so an unauthenticated Prometheus or OpenTelemetry scrape keeps working unchanged on a default instance; once you turn it on, the scraper needs control-plane credentials like any other client, and an unauthenticated scrape is refused like any other control-plane request. See Securing the metrics scrape endpoint below for what its labels can expose and how to lock it down further.
 

Roles

The three roles form a strict hierarchy. A principal granted a higher role satisfies every requirement at or below it:

RolePermitsExamples
readRead-only control-plane operationsretrieve (except with extractBodiesLargerThan or forwardUnmatchedTo, which change server state and need mutate), verify, verifySequence, explainUnmatched, explain, debugMismatch, lint
mutateEverything read permits, plus all mutating operationsexpectation, clear, reset, configuration, chaosExperiment, template/test, LLM endpoints
adminEverything mutate permits (reserved for future fine-grained admin operations)Currently identical to mutate
 

Configuration

Enable authorization with controlPlaneAuthorizationEnabled (default false) and map scope/group values to roles with controlPlaneScopeMapping:

PropertyEnvironment VariableDefaultDescription
mockserver.controlPlaneAuthorizationEnabled MOCKSERVER_CONTROL_PLANE_AUTHORIZATION_ENABLED false Enable coarse role-based authorization of all control-plane requests. Requires a verified principal (OIDC authentication must be configured).
mockserver.controlPlaneScopeMapping MOCKSERVER_CONTROL_PLANE_SCOPE_MAPPING empty Comma-separated scope=role pairs mapping a principal's OIDC scope or group value to a role (read, mutate, or admin). Example: platform-admins=admin,qa-team=mutate,viewers=read

Example — system property configuration:

-Dmockserver.controlPlaneAuthorizationEnabled=true
-Dmockserver.controlPlaneScopeMapping=platform-admins=admin,qa-team=mutate,viewers=read

Example — Java programmatic configuration:

ConfigurationProperties.controlPlaneAuthorizationEnabled(true);
ConfigurationProperties.controlPlaneScopeMapping(Map.of(
    "platform-admins", ControlPlaneRole.ADMIN,
    "qa-team",         ControlPlaneRole.MUTATE,
    "viewers",         ControlPlaneRole.READ
));
 

Behaviour

  • Fail-closed: a principal whose scopes do not map to any role in controlPlaneScopeMapping is denied every mutation (and every read unless a read-or-higher role is mapped). An unmapped or blank role value grants nothing.
  • Denied mutations return HTTP 403. The response body is a generic Forbidden for control plane message. The detailed reason (granted role vs. required role) is logged server-side only so authorization policy is not disclosed to the client.
  • Denials are recorded in the audit log with outcome=FORBIDDEN. Successful authorized requests are recorded with outcome=AUTHORIZED.
  • A principal may hold multiple scopes. The highest-ranked role from all matched scopes wins (e.g. a token with both viewers and qa-team scopes is granted mutate from the example mapping above).
 

Configuration Hardening

For the most security-focused deployment, set the configuration properties below to the values shown. Each can be set as a Java system property (-Dmockserver.<name>=<value>), an environment variable (MOCKSERVER_<NAME>), or in a properties file — see Configuration Properties for the exact syntax and full description of each.

 

Network exposure

  • mockserver.localBoundIP=127.0.0.1 — bind the listener to the loopback interface so MockServer is reachable only from the local host. When running inside a container, set this to 0.0.0.0 and restrict access at the container, network, or orchestration layer instead.
  • mockserver.attemptToProxyIfNoMatchingExpectation=false — return 404 Not Found for any request that matches no expectation, so MockServer serves only the traffic you have explicitly defined and does not forward unmatched requests upstream.
 

Securing the metrics scrape endpoint

The Prometheus scrape endpoint GET /mockserver/metrics goes through the same control-plane authentication and authorization gate as every other control-plane endpoint (/dashboard, /openapi.yaml, and all retrieve operations). Control-plane authentication is opt-in and off by default, so an unauthenticated Prometheus or OpenTelemetry scrape keeps working unchanged on a default instance. If you turn on control-plane authentication, the scraper must present control-plane credentials like any other client — there is no separate opt-out for this one endpoint, since leaving it open would contradict the operator's explicit intent to lock down the control plane.

On a default instance (control-plane authentication off), be aware of what its labels can reveal to anyone with network reach:

  • Upstream/proxy destinations — the forward and proxy observability series carry an upstream_host label (host only, never the full URL or path), exposing which backends MockServer forwards to. At most 500 distinct hosts get their own label; any further hosts are grouped under _other.
  • LLM cost and token metadata — when LLM mocking is used, mock_server_llm_input_tokens, mock_server_llm_output_tokens, and mock_server_llm_cost_usd are labelled by provider and model.

To secure it, choose whichever fits your deployment (they combine):

  • Disable it entirely — mockserver.metricsEnabled=false (the default) fully disables the endpoint: /mockserver/metrics returns 404 Not Found and no metrics are exposed. Leave it off unless you are actively scraping.
  • Restrict access at the network layer — don't expose the MockServer port publicly. Bind to loopback (mockserver.localBoundIP=127.0.0.1), keep it on an internal network, or restrict it with a firewall rule or Kubernetes NetworkPolicy that permits only your Prometheus scraper.
  • Prefer push-based export — both OpenTelemetry OTLP metrics export (mockserver.otelMetricsEnabled) and Prometheus Remote-Write (mockserver.prometheusRemoteWriteEnabled) push the same metrics to your backend and expose no scrape endpoint at all. With metrics pushed and metricsEnabled=false, there is nothing to lock down on the MockServer side.
 

Forwarding & proxying

  • mockserver.forwardProxyBlockPrivateNetworks=true — reject forward and proxy targets that resolve to loopback, link-local, RFC 1918 private, carrier-grade NAT (100.64.0.0/10), or cloud-metadata addresses (e.g. 169.254.169.254), keeping forwarded requests off internal networks (SSRF protection). It is fixed at startup, so a control-plane request cannot switch it off.
  • mockserver.forwardProxyAllowedHosts=api.example.com,*.partner.example and/or mockserver.forwardProxyDeniedHosts=10.0.0.0/8 — limit forwards, proxied and replayed requests, webhooks and OpenAPI spec fetches by URL to the hosts you list, or keep them away from hosts, domains and CIDR blocks you list (the deny list wins). CIDR blocks are matched against the address a name resolves to as well, so DNS rebinding cannot get round them when MockServer connects directly (an upstream proxy resolves names itself). Both are fixed at startup, so a control-plane request cannot widen them.
  • mockserver.forwardProxyTLSX509CertificatesTrustManagerType=JVM — validate upstream HTTPS certificates against the JDK trust store, exactly as a standard Java HTTPS client would. To trust a specific private CA, use =CUSTOM together with mockserver.forwardProxyTLSCustomTrustX509Certificates pointing at your CA bundle.
 

TLS protocols

  • mockserver.tlsAllowInsecureProtocols=false — negotiate TLSv1.2 and above only, excluding the deprecated TLSv1 and TLSv1.1 protocols. Add TLSv1.3 to mockserver.tlsProtocols to require the most modern protocol.
 

Response template execution

If you use response templates, note that templates cannot reach Java classes by default, so this hardening is already in place and nothing needs configuring (templates you do not use carry no risk):

  • mockserver.velocityDisallowClassLoading defaults to true — Velocity templates run with a secure uberspector so they cannot load arbitrary Java classes. Setting it to false re-opens that, which on an exposed control plane is a remote-code-execution path.
  • mockserver.javascriptAllowedClasses defaults to empty, meaning JavaScript templates resolve NO Java class via Java.type(...). Only list classes a template genuinely needs, and avoid the * wildcard (fully unrestricted) on any instance untrusted callers can reach.
 

Request parsing limits

The request line and headers are bounded by default (64 KiB and 256 KiB), so a single client cannot exhaust memory with an oversized request. If every client you expect sends ordinary requests, tighten the bounds further:

  • mockserver.maxInitialLineLength=8192 — cap the request line (method + URI + version) at 8 KiB.
  • mockserver.maxHeaderSize=16384 — cap the combined request headers at 16 KiB, over HTTP/1.1, HTTP/2 and HTTP/3 (where the URL counts as a header). The same cap applies to the response headers MockServer reads from an upstream server when it forwards or proxies.
  • mockserver.maxChunkSize=16384 — cap a single chunked-transfer-encoding chunk at 16 KiB.

The body-size limits mockserver.maxRequestBodySize and mockserver.maxResponseBodySize provide complementary bounds on payload size.

 

Control plane & CORS

  • Require authentication on every control-plane request — enable mTLS and/or JWT as described above.
  • mockserver.controlPlaneCorsAllowOrigin — by default only pages on localhost, and pages MockServer serves itself when reached by localhost, an IP address, a single-word name, a name ending in .svc, .svc.cluster.local or .internal, or a controlPlaneTrustedHostSuffixes entry, can use the control plane from a browser. Add only the origins you trust, never *, and keep mockserver.corsAllowCredentials=false unless credentialed cross-origin requests are genuinely required. mockserver.corsAllowOrigin only affects mocked and proxied responses. See CORS.
  • What the browser-origin check does not stop — a DNS-rebinding attack by someone who controls the victim's name lookups (a hostile Wi-Fi network, a spoofing machine on the local network, the cluster's DNS), which works on any trusted name except an IP address or localhost; a DNS-rebinding attack on a public name you have trusted through controlPlaneCorsAllowOrigin or controlPlaneTrustedHostSuffixes (a malicious site points that name at MockServer, so the browser treats MockServer as part of that site), and any site visited in a browser that uses MockServer as its proxy. Control-plane authentication stops all of these: the attacker's page has no credentials to send.

See Also