In REST Assured, how do you authenticate every request by default and opt one test out?
answer
- one public static field, not a config object
- static factories return the scheme object
- default applies only when nothing else set
- none() is the per-request opt-out
- reset() restores it to NoAuthScheme
basics
~10 sAssign a scheme to the static field RestAssured.authentication, for example RestAssured.basic(user, pass). It applies to any request that sets no scheme of its own. A single request opts out with given().auth().none().
solid answer
~40 s`RestAssured.authentication` is a public static field of type `AuthenticationScheme`, defaulting to a `NoAuthScheme`. Assign it a scheme built by one of the static factories — `RestAssured.basic(u, p)`, `ntlm(...)`, `digest(...)`, `preemptive().basic(u, p)` — and every subsequent call inherits it. The inheritance is conditional: the default is substituted in only while the request's own `authenticationScheme` is still the implicit `NoAuthScheme`. Any per-request `auth()` call replaces it outright; nothing is merged. To make one request anonymous, use `given().auth().none()`. It installs `ExplicitNoAuthScheme`, drops auth filters and removes any `Authorization` header, so the global default is not substituted in. Call `RestAssured.reset()` afterwards to put the static back to its default.
code
java · 29 linesimport io.restassured.RestAssured;
import static io.restassured.RestAssured.basic;
import static io.restassured.RestAssured.given;
public class FerryDefaultAuthExample {
public static void main(String[] args) {
RestAssured.baseURI = "https://ferry-api.internal";
RestAssured.authentication = basic("timetable-bot", "s3cret");
// Inherits the default scheme.
given()
.queryParam("routeCode", "DOV-CAL")
.when()
.get("/v1/sailings")
.then()
.statusCode(200);
// Opts out for this one call.
given().auth().none()
.when()
.get("/v1/sailings/9f31/manifest")
.then()
.statusCode(401);
RestAssured.reset();
}
}go deeper
Know that RestAssured.authentication is the field to assign, that the static factories build the scheme it holds, and that given().auth().none() makes one call anonymous.
Explain the substitution rule — the default only applies while the request's own scheme is the implicit NoAuthScheme — and why none() installs a distinct class to defeat it.
Talk about the static as shared mutable process state: where you set it, why reset() belongs in teardown, and when a RequestSpecification carrying setAuth is the safer container.
Decide the suite convention: whether credentials live in a global static, in a shared specification, or per call, and how that choice keeps negative authentication coverage honest.
## The static field that every request reads `io.restassured.RestAssured` exposes a public static field, `authentication`, typed `AuthenticationScheme`. It starts life as `DEFAULT_AUTH`, which is a `NoAuthScheme` — a scheme whose `authenticate(HTTPBuilder)` method does nothing at all. Assigning to it is how you say "every call in this JVM is authenticated unless told otherwise": ```java RestAssured.baseURI = "https://ferry-api.internal"; RestAssured.authentication = RestAssured.basic("timetable-bot", "s3cret"); ``` The right-hand side matters. The static `RestAssured.basic(userName, password)` is a **factory**: it builds and returns a `BasicAuthScheme` object. It is not the same thing as `given().auth().basic(...)`, which attaches a scheme to one request and returns a `RequestSpecification`. The static factories that return a scheme you can store are `basic`, `ntlm`, `digest`, `form`, `certificate`, `oauth`, `oauth2` and `preemptive().basic(...)`. ## Which static factory returns which scheme The factories on `RestAssured` are what you assign, and they are not interchangeable with the identically named methods on `given().auth()`: - `RestAssured.basic(userName, password)` returns a `BasicAuthScheme`. - `RestAssured.digest(userName, password)` also returns a `BasicAuthScheme` — its body is literally `return basic(userName, password)`. - `RestAssured.ntlm(userName, password, workstation, domain)` returns an `NTLMAuthScheme`. - `RestAssured.preemptive().basic(userName, password)` returns a `PreemptiveBasicAuthScheme`, and is the way to make the whole suite send its credential without waiting for a challenge. Each of those is an object you hold. The `given().auth()` methods of the same name return a `RequestSpecification` instead, because they attach the scheme rather than hand it to you. ## When the default is actually applied REST Assured does not merge the default into every request unconditionally. While it is building a request it performs one substitution: - If the request's own `authenticationScheme` is still the implicit `NoAuthScheme` **and** the static default is something other than a `NoAuthScheme`, the default is copied onto the request. - Otherwise the request keeps whatever it has. So the precedence rule is simple and one-directional: **a per-request `auth()` call wins, and there is no merging.** If a ferry timetable test says `given().auth().preemptive().basic("ops-reader", "hunter2")`, the global `timetable-bot` credential is never consulted for that call. ## Opting a single request out The opt-out is `given().auth().none()`. It is not a no-op and it is not the same as leaving `auth()` off the chain. `none()` does three things: 1. It sets the request's scheme to `ExplicitNoAuthScheme`. 2. It removes every `AuthFilter` from the request's filter list. 3. It removes any `Authorization` header already on the request. Step 1 is the load-bearing one. `ExplicitNoAuthScheme` implements `AuthenticationScheme` directly and is **not** a `NoAuthScheme`, so the substitution rule above sees a request that already has a scheme and leaves it alone. That single class distinction is why `none()` reliably produces an anonymous call while simply omitting `auth()` does not. This is exactly what you need for the negative half of your ferry timetable coverage: ```java given().auth().none() .when() .get("/v1/sailings/9f31/manifest") .then() .statusCode(401); ``` ## Where else a default can come from The static field is not the only place a scheme can be parked, and confusing them causes real puzzlement: - `RestAssured.requestSpecification` — a whole `RequestSpecification` applied to every call. If it was built by a `RequestSpecBuilder` with `setAuth(...)`, it carries a scheme too. - A `RequestSpecBuilder` **snapshots the statics in its constructor**, including `authentication`. A builder constructed before you assign `RestAssured.authentication` does not see the assignment. - `given().spec(someSpec)` overwrites the request's `authenticationScheme` outright rather than merging it, so call order decides which credential survives. ## Cleaning up after yourself `RestAssured.authentication` is process-wide mutable state. A suite that sets it in one test class and forgets affects every later class in the same JVM. Two habits keep that honest: - Set it once in a single place — a base class or a suite-level hook — rather than in individual tests. - Call `RestAssured.reset()` when you are done. It restores `authentication` to `DEFAULT_AUTH` along with `baseURI`, `basePath`, `rootPath`, `config`, `sessionId`, `proxy`, the filter list and both static specifications, and it puts `port` back to `UNDEFINED_PORT` (`-1`), not to `DEFAULT_PORT`. If you would rather not touch statics at all, build the credential into a `RequestSpecification` with `RequestSpecBuilder.setAuth(...)` and hand it to `given().spec(...)`. That keeps the scope explicit and makes the anonymous case the default rather than the exception — you get an unauthenticated call by simply not attaching the spec. ## The shape to remember - The default lives in one static field, `RestAssured.authentication`. - Static factories such as `RestAssured.basic(...)` produce the scheme object it holds. - The default is only substituted into requests that have set no scheme of their own. - `given().auth().none()` is the explicit per-request opt-out, and it works because the scheme it installs is a different class from the implicit one.
- Why is given().auth().none() different from simply leaving auth() off the chain?Omitting `auth()` leaves the request's scheme as the implicit `NoAuthScheme`, which is exactly the condition under which REST Assured substitutes the static default in. `none()` installs `ExplicitNoAuthScheme`, a different class, so the substitution is skipped and the call really goes out unauthenticated.
- What does RestAssured.reset() restore besides the authentication scheme?It restores `baseURI` to `http://localhost`, `basePath` and `rootPath` to empty, `urlEncodingEnabled` to true, `config` to a fresh `RestAssuredConfig`, and it nulls `requestSpecification`, `responseSpecification`, `defaultParser`, `sessionId` and `proxy` while emptying the filter list. Note `port` goes back to `UNDEFINED_PORT` (-1), not `DEFAULT_PORT`.
saying these in an interview costs you the question
- Looking for auth inside RestAssuredConfig instead of the static field
- Assuming a per-request auth() call merges with the global default
- Thinking omitting auth() is enough to get an anonymous request
- Setting the static in every test method and never resetting it
- Confusing RestAssured.basic(u, p) with given().auth().basic(u, p)