In REST Assured, what scheme object does auth().digest(user, password) actually install?
answer
- a real call with a misleading name
- no digest-specific scheme class ships
- return basic(userName, password)
- the HTTP client answers the challenge
- challenged only, never preemptive
basics
~10 sA BasicAuthScheme. REST Assured ships no digest-specific scheme class; the static RestAssured.digest(user, password) simply returns basic(user, password). The credentials are stored for the HTTP client, which answers whichever challenge the server sends.
solid answer
~30 sIt installs a `BasicAuthScheme` — the very same object `auth().basic(...)` installs. The static `RestAssured.digest(userName, password)` has a one-line body: `return basic(userName, password)`. There is no `DigestAuthScheme` type in the library. It still works against a Digest-protected ferry timetable endpoint because the scheme only registers a `UsernamePasswordCredentials` with the underlying Apache HttpClient under an `AuthScope` for the target host and port. When the server answers `401`, that client reads the challenge, picks a scheme it supports and computes the response. That is why the documentation says only *challenged* digest is supported, and why `preemptive().digest(...)` exists on neither preemptive surface.
code
java · 19 linesimport io.restassured.RestAssured;
import static io.restassured.RestAssured.given;
public class FerryDigestExample {
public static void main(String[] args) {
RestAssured.baseURI = "https://ferry-api.internal";
// Installs a BasicAuthScheme; the HTTP client answers whatever challenge arrives.
given().auth().digest("timetable-bot", "s3cret")
.when()
.get("/v1/routes/DOV-CAL/timetable")
.then()
.statusCode(200);
RestAssured.reset();
}
}go deeper
Recall that auth().digest(user, password) exists, takes the same two arguments as basic(), and only works when the server issues a challenge first.
Explain that the call installs a BasicAuthScheme, that the credential is registered with the underlying HTTP client, and that the client — not REST Assured — reads the challenge and computes the header.
Point out the operational risk: a service that stops challenging turns a digest() suite into unauthenticated traffic with no warning, and the DSL exposes nothing digest-specific to assert on.
Frame the general lesson for the team: method names on a wrapper describe intent, and the reviewable question is always which object a call installs and which layer does the work.
## The measured answer `given().auth().digest(userName, password)` assigns a **`BasicAuthScheme`** to the request's `authenticationScheme` field. Not a digest scheme — the same class that `auth().basic(userName, password)` installs, constructed from the same two arguments. The static twin is even blunter. `RestAssured.digest(String, String)` has a one-line body: ```java public static AuthenticationScheme digest(String userName, String password) { return basic(userName, password); } ``` There is no `DigestAuthScheme` type in the library. `io.restassured.authentication` ships `BasicAuthScheme`, `PreemptiveBasicAuthScheme`, `NTLMAuthScheme`, `CertAuthScheme`, `FormAuthScheme`, `OAuthScheme`, `OAuth2Scheme`, `PreemptiveOAuth2HeaderScheme`, `NoAuthScheme` and `ExplicitNoAuthScheme` — and that is the whole set. ## So why does the method work at all? Because the work happens one layer down. `BasicAuthScheme.authenticate(HTTPBuilder)` registers a `UsernamePasswordCredentials` object in the underlying Apache HttpClient's credentials provider, under an `AuthScope` built from the target URI's host and port. It writes nothing on the request. What goes out is decided later, by the client: 1. REST Assured sends `GET /v1/routes/DOV-CAL/timetable` with no credential attached. 2. The ferry API answers `401` with a challenge. 3. The HttpClient picks a scheme it supports from that challenge and computes the response using the credentials registered for the host and port. 4. The request is replayed with whatever header that scheme produced. If the challenge names Digest, the client's digest implementation does the work. If it names Basic, the client's basic implementation does. Your test called `digest(...)`, but the credential store does not remember which method you used — a user name and a password are all it holds. ## The consequences worth naming - `auth().basic(...)` and `auth().digest(...)` are **behaviourally identical** in REST Assured. Swapping one for the other changes nothing that goes on the wire. - The wiki's line that "only challenged digest authentication is supported" is precise, not a caveat: there is nothing to send preemptively because REST Assured never computes a digest response itself. - `preemptive().digest(...)` does not exist on either preemptive surface. Neither `PreemptiveAuthSpec` (the instance one) nor `PreemptiveAuthProvider` (the static one) declares it, and a digest response depends on a server-supplied challenge, so a preemptive form could not exist in principle either. - If your ferry timetable endpoint stops challenging — a gateway change, a rewritten security filter — a suite built on `digest(...)` silently sends unauthenticated requests and gets whatever the service does with them. Nothing in REST Assured raises a flag. - Because credentials are keyed by an `AuthScope` derived from host and port, a redirect to a different host leaves the challenge unanswered. That failure mode is shared with `basic(...)` and with `ntlm(...)`, which uses the same provider with `NTCredentials`. - The static and instance forms agree here for once. `RestAssured.digest(...)` delegates to `RestAssured.basic(...)`, and `AuthenticationSpecificationImpl.digest` assigns `new BasicAuthScheme(...)` directly, so whichever spelling you use you end up with the same object on the request. ## How to talk about it in an interview The trap in this question is confidence. The method name is real, the call compiles, the test passes against a Digest-protected service, and everything in your memory says a library that offers `digest(...)` must implement digest. The accurate sentence is layered: - **REST Assured's contribution:** store the credential and hand it to the HTTP client. - **The HTTP client's contribution:** read the challenge, pick a scheme, compute the header, replay. - **What the method name tells you:** your intent, not the mechanism. That framing generalises. The same "which object does this call install" question is what separates a usable answer from a memorised one across REST Assured's auth surface: `basic` and `digest` both give you `BasicAuthScheme`, `ntlm` gives `NTLMAuthScheme`, `none` gives `ExplicitNoAuthScheme`, and `preemptive().basic(...)` on the instance spec gives you no scheme at all — just an `Authorization` header it computed itself. ## A practical rule - If you want the credential to go out unprompted, use `preemptive().basic(...)`; `digest(...)` can never do that. - If you want a challenge-driven call, `digest(...)` and `basic(...)` are the same call, so pick the name that documents your intent and do not expect the choice to change behaviour. - If you genuinely need to assert something about the digest exchange itself — the parameters in the challenge, or the header the client produced — inspect it with a logging filter or a custom `Filter`, because the DSL exposes no digest-specific surface to assert on. - If you are reviewing someone else's suite, treat a `digest(...)` call as a documentation comment about the server, not as evidence that REST Assured is doing anything digest-specific.
- Given that, is there any behavioural difference between auth().basic(...) and auth().digest(...)?None. Both assign a `BasicAuthScheme` built from the same user name and password, and both register the same `UsernamePasswordCredentials` with the HTTP client. The only difference is what the call communicates to a reader of the test. Nothing on the wire changes if you swap them.
- Why is there no preemptive digest form in REST Assured?Neither `PreemptiveAuthSpec` nor `PreemptiveAuthProvider` declares `digest`, and it could not be added meaningfully: a digest response is computed from parameters the server supplies in its challenge, so there is nothing to send before the challenge arrives. Preemptive sending only works for schemes whose credential is self-contained.
saying these in an interview costs you the question
- Claiming REST Assured computes the digest response itself
- Naming a DigestAuthScheme class that does not exist
- Believing digest() sends a hashed password on the first request
- Expecting preemptive().digest(...) to compile
- Assuming basic() and digest() produce different traffic