REST Assured has no auth().bearer() method - so how do you attach a bearer token to a request?
answer
- no bearer method on the DSL
- the oauth2 call carries it
- HEADER is the default signature
- PreemptiveOAuth2HeaderScheme writes the header
basics
~20 sUse given().auth().oauth2(token) - REST Assured has no bearer method at all. With the default HEADER signature that call installs a PreemptiveOAuth2HeaderScheme, which writes a plain Authorization: Bearer header on the request, with no signing and no challenge round trip.
solid answer
~40 sREST Assured's `AuthenticationSpecification` declares `basic`, `ntlm`, `digest`, `form`, `certificate`, `oauth`, `oauth2`, `preemptive()` and `none()` - there is no `bearer(...)` and there never has been, so a bearer credential rides on `given().auth().oauth2(accessToken)`. That single-argument call delegates to `oauth2(accessToken, OAuthSignature.HEADER)`, which installs a `PreemptiveOAuth2HeaderScheme`; the scheme's `generateAuthToken()` is literally `"Bearer " + accessToken`, so the wire header is `Authorization: Bearer <token>`, written on the very first request with no signing and no challenge round trip beforehand; REST Assured never inspects, decodes or refreshes the string you hand it. The more explicit spelling, `given().auth().preemptive().oauth2(accessToken)`, produces exactly the same header. Neither form needs the optional `scribejava-apis` dependency - only OAuth 1 and `oauth2(token, OAuthSignature.QUERY_STRING)` do. To cover a whole harvest-log suite, assign `RestAssured.authentication = RestAssured.oauth2(token)`, which builds that same scheme object.
code
java · 22 linesimport io.restassured.RestAssured;
import static io.restassured.RestAssured.given;
import static org.hamcrest.Matchers.equalTo;
public class HarvestLogBearerExample {
public static void main(String[] args) {
RestAssured.baseURI = "https://harvest-log.example.com";
String accessToken = System.getenv("HARVEST_LOG_TOKEN");
given()
.auth().oauth2(accessToken) // installs PreemptiveOAuth2HeaderScheme
.pathParam("harvestId", "H-2026-0412")
.when()
.get("/v1/harvests/{harvestId}")
.then()
.statusCode(200)
.body("blockCode", equalTo("NORTH-SLOPE-7"))
.body("varietal", equalTo("pinot noir"));
}
}go deeper
Memorise the shape: given().auth().oauth2(accessToken). Be ready to say out loud that no bearer() method exists, and that the header REST Assured writes is Authorization: Bearer followed by your token.
Explain the delegation: the one-argument call becomes oauth2(token, OAuthSignature.HEADER), which installs PreemptiveOAuth2HeaderScheme. Name that class and say the header value is a plain string concatenation, not a signature.
Show where the token comes from and where it must not end up: an environment variable or a setup call rather than a literal, and a header REST Assured blacklists in request logs. Say why the preemptive path suits a suite.
Own the house convention. Decide whether the token is wired on the static, on a shared request specification, or per test, and make the choice survive parallel runs and token rotation rather than leaving four spellings in the codebase.
## The method everyone types first When the vineyard harvest-log API asks for `Authorization: Bearer <token>`, the natural guess in REST Assured's fluent DSL is `given().auth().bearer(token)`. It does not compile, and it never has. The interface behind `given().auth()` is `io.restassured.specification.AuthenticationSpecification`, and it declares exactly these methods and no others: - `basic(String userName, String password)` - `ntlm(String userName, String password, String workstation, String domain)` - `digest(String userName, String password)` - `form(String, String)` and `form(String, String, FormAuthConfig)` - `certificate(String, String)` and `certificate(String, String, CertificateAuthSettings)` - `oauth2(String accessToken)` and `oauth2(String accessToken, OAuthSignature signature)` - `oauth(String, String, String, String)` plus a five-argument overload ending in `OAuthSignature` - `preemptive()`, which returns a `PreemptiveAuthSpec`, and `none()` `bearer` is simply absent from that list. A bearer credential travels on `oauth2`, and the mismatch between the name of the method and the thing it puts on the wire is exactly why interviewers ask. ## What `auth().oauth2(token)` actually does The single-argument instance method delegates straight to `oauth2(accessToken, OAuthSignature.HEADER)`. That two-argument method branches on the signature: for `HEADER` it sets the request specification's `authenticationScheme` to a `PreemptiveOAuth2HeaderScheme` holding your token. When the request is finally sent, the scheme's `authenticate(...)` hook puts one header on the outgoing request, and the value comes from `generateAuthToken()`, whose entire body is `"Bearer " + accessToken`. Everything interesting about that path is what it does **not** do: - It computes no signature over the method, the URI or the body. - It waits for no challenge response; the header rides on the very first attempt. - It never fetches, refreshes, decodes or validates the token — you hand it a string. - It pulls in no extra dependency: the optional `com.github.scribejava:scribejava-apis` artifact stays untouched. - It replaces whatever authentication scheme the specification already carried, including one inherited from the `RestAssured.authentication` static. ## Attaching it to a harvest-log request ```java given() .auth().oauth2(accessToken) .when() .get("/v1/blocks/NORTH-SLOPE-7/harvests") .then() .statusCode(200) .body("[0].varietal", equalTo("pinot noir")); ``` That is the whole recipe. If the harvest-log service rejects the credential you get its ordinary status code back — typically `401` — because REST Assured has no opinion about the token's contents. ## The more explicit spelling `given().auth().preemptive().oauth2(accessToken)` reaches `io.restassured.specification.PreemptiveAuthSpec`, an interface that declares two methods: `basic(String, String)` and `oauth2(String)`. On the wire it produces the identical `Authorization: Bearer <token>`, and the project wiki states plainly that the two forms do the same thing, with `auth().oauth2(..)` surviving largely for backward compatibility. Be precise about which `preemptive()` you mean, though: the static `RestAssured.preemptive()` returns `io.restassured.authentication.PreemptiveAuthProvider`, which declares `basic(...)` **only**. There is no static `preemptive().oauth2(...)`, and `preemptive().digest(...)` exists on neither surface. ## The token-bearing calls side by side | call | what it installs | needs `scribejava-apis` | |---|---|---| | `auth().oauth2(token)` | `PreemptiveOAuth2HeaderScheme` | no | | `auth().preemptive().oauth2(token)` | the `Authorization` header, written directly | no | | `auth().oauth2(token, OAuthSignature.QUERY_STRING)` | `OAuth2Scheme` | yes | | `auth().oauth(key, secret, token, tokenSecret)` | `OAuthScheme`, the OAuth 1 path | yes | `OAuthSignature` is an enum with exactly two constants, `HEADER` and `QUERY_STRING`. Only the second one signs anything, and only the second one drags in the optional dependency. ## Setting it once for the whole suite The static factory `RestAssured.oauth2(accessToken)` returns the same `PreemptiveOAuth2HeaderScheme` object, so `RestAssured.authentication = RestAssured.oauth2(token)` makes every request in the suite carry the bearer header. A `RequestSpecBuilder.setAuth(...)` holding the same scheme, attached with `given().spec(spec)`, does the job per specification instead. Watch the arity: the **two**-argument static `RestAssured.oauth2(token, OAuthSignature.HEADER)` builds an `OAuth2Scheme` rather than the plain header writer, which is a different code path with a different classpath requirement. ## Failure modes worth recognising 1. `given().auth().bearer(token)` — a compile error rather than a test failure, which is why the fact is easy to memorise once and never forget. 2. `given().header("Authorization", "Bearer " + accessToken)` — this does work and is what the scheme ends up doing, but it bypasses `auth()`, so `auth().none()` in a later call will not clear it and a globally configured scheme can still overwrite the request's credential. 3. Passing an already-prefixed value such as `oauth2("Bearer eyJhbGciOi...")` — the scheme concatenates unconditionally, so the harvest-log service receives `Bearer Bearer eyJhbGciOi...` and answers `401`. 4. Expecting a challenge round trip: this path is preemptive by construction, so a test that means to observe the service's unauthenticated behaviour must use `auth().none()` instead. ## The one-line answer There is no `bearer()` in REST Assured. `given().auth().oauth2(accessToken)` — or the equally valid `given().auth().preemptive().oauth2(accessToken)` — installs the plain-header path and sends `Authorization: Bearer <token>` on the first request, with no signing and no extra dependency.
- Does REST Assured inspect or refresh the token you pass to auth().oauth2(...)?No. `PreemptiveOAuth2HeaderScheme` stores the string and `generateAuthToken()` returns `"Bearer " + accessToken`. Nothing decodes, validates or renews it, so an expired value simply produces whatever the harvest-log service answers, usually `401`. Acquiring and refreshing the credential is your test setup's job, not the library's.
- How would you make every request in a REST Assured suite carry the same bearer token?Assign the scheme to the static: `RestAssured.authentication = RestAssured.oauth2(token)`, which returns the same `PreemptiveOAuth2HeaderScheme`. Alternatively hold it on a `RequestSpecBuilder` with `setAuth(...)` and attach the built spec. Use the single-argument static - the two-argument `oauth2(token, signature)` static builds a different scheme object.
saying these in an interview costs you the question
- Claims given().auth().bearer(token) is the real API
- Thinks auth().oauth2() signs the request by default
- Expects a 401 challenge before the header is sent
- Believes scribejava-apis is needed for a bearer token
- Assumes oauth2() also performs the token-granting flow
- Passes an already-prefixed "Bearer ..." string to oauth2()