In this tutorial, we'll analyze how we can authenticate with REST Assured to test and validate a secured API properly.
The tool provides support for several authentication schemes:
- Basic Authentication
- Digest Authentication
- Form Authentication
- OAuth 1 and OAuth 2
And we'll see examples for each one.
2. Using Basic Authentication
The basic authentication scheme requires the consumer to send user id and a password encoded in Base64.
REST Assured provides an easy way to configure the credentials that the request requires:
given().auth() .basic("user1", "user1Pass") .when() .get("http://localhost:8080/spring-security-rest-basic-auth/api/foos/1") .then() .assertThat() .statusCode(HttpStatus.OK.value());
2.1. Preemptive Authentication
As we've seen on a previous post on Spring Security authentication, a server might use a challenge-response mechanism to indicate explicitly when the consumer needs authenticate to access the resource.
By default, REST Assured waits for the server to challenge before sending the credentials.
This can be troublesome in some cases, for example, where the server is configured to retrieve a login form instead of the challenge response.
For this reason, the library provides the preemptive directive that we can use:
given().auth() .preemptive() .basic("user1", "user1Pass") .when() // ...
With this in place, REST Assured will send the credentials without waiting for an Unauthorized response.
We hardly ever are interested in testing the server's ability to challenge. Therefore, we can normally add this command to avoid complications and the overhead of making an additional request.
3. Using Digest Authentication
This is due to the fact that this scheme avoids sending the password in cleartext.
Despite this difference, implementing this form of authentication with REST Assured is very similar to the one we followed in the previous section:
given().auth() .digest("user1", "user1Pass") .when() // ...
Note that, currently, the library supports only challenged authentication for this scheme, so we can't use preemptive() as we did earlier.
4. Using Form Authentication
Many services provide an HTML form for the user to authenticate by filling in the fields with their credentials.
When the user submits the form, the browser executes a POST request with the information.
Normally, the form indicates the endpoint that it'll call with its action attribute, and each input field corresponds with a form parameter sent in the request.
If the login form is simple enough and follows these rules, then we can rely on REST Assured to figure out these values for us:
given().auth() .form("user1", "user1Pass") .when() // ...
This is not an optimal approach, anyway, since REST Assured needs to perform an additional request and parse the HTML response to find the fields.
We also have to keep in mind that the process can still fail, for example, if the webpage is complex, or if the service is configured with a context path that is not included in the action attribute.
Therefore, a better solution is to provide the configuration ourselves, indicating explicitly the three required fields:
given().auth() .form( "user1", "user1Pass", new FormAuthConfig("/perform_login", "username", "password")) // ...
Apart from these basic configurations, REST Assured ships with functionality to:
- detect or indicate a CSRF token field in the webpage
- use additional form fields in the request
- log information about the authentication process
5. OAuth Support
OAuth is technically an authorization framework, and it doesn't define any mechanism for authenticating a user.
Still, it can be used as the basis for building an authentication and identity protocol, as is the case of OpenID Connect.
5.1. OAuth 2.0
REST Assured allows configuring the OAuth 2.0 access token to request a secured resource:
given().auth() .oauth2(accessToken) .when() .// ...
The library doesn't provide any help in obtaining the access token, so we'll have to figure out how to do this ourselves.
For the Client Credential and Password flows this is a simple task since the Token is obtained by just presenting the corresponding credentials.
On the other hand, automating the Authorization Code flow might not be that easy, and we'll probably need the help of other tools as well.
To understand correctly this flow and what it takes to obtain an Access Token, we can have a look at this great post on the subject.
5.2. OAuth 1.0a
In the case of OAuth 1.0a, REST Assured supplies a method that receives a Consumer Key, Secret, Access Token and Token Secret to access a secured resource:
given().accept(ContentType.JSON) .auth() .oauth(consumerKey, consumerSecret, accessToken, tokenSecret) // ...
This protocol requires user input, therefore obtaining the last two fields won't be a trivial task.
Note that we'll need to add the scribejava-apis dependency in our project if we're using OAuth 2.0 features with a version prior to 2.5.0, or if we're making use of the OAuth 1.0a functionality.
In this tutorial, we've learned how we can authenticate to access secured APIs using REST Assured.
The library simplifies the process of authentication for practically any scheme that we implemented.
As always, we can find working examples with instructions on our Github repo.