Using REST-assured to Test OAuth 2.0 flow Examples

OAuth 2.0 provides four different flows, but the main goal of each flow is to obtain an access_token and use it to access protected resources.

The four different flows are:

  • Authorization Code Grant
  • Implicit Grant Flow
  • Client Credential
  • Password Grant Flow

This tutorial provides code examples using REST-assured to test the OAuth 2.0 flows, Authorization Code Grant and Client Credential flows.

Authorization Code Grant Flow

This is the most common flow where a code is issued and used to obtain the access_token. This code is pushed to a front-end application (on the browser) after the user logs in. The access_token is issued on server side, authenticating the client with its password and the obtained code.

Three step process:

  • 1 - Get Auth Code
  • 2 - Get Access Token
  • 3 - Use Access Token (to access protected resources)

Get Auth Code

The first step is to get the code:

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;

import java.util.Base64;

public class RestAssuredOAuth2 {

    public static String clientId = "some_client_id";
    public static String redirectUri = "some_redirect_uri";
    public static String scope = "some_scope";
    public static String username = "some_email";
    public static String password = "some_password";

    public static String encode(String str1, String str2) {
        return new String(Base64.getEncoder().encode((str1 + ":" + str2).getBytes()));
    }

    public static Response getCode() {
        String authorization = encode(username, password);

        return
                given()
                        .header("authorization", "Basic " + authorization)
                        .contentType(ContentType.URLENC)
                        .formParam("response_type", "code")
                        .queryParam("client_id", clientId)
                        .queryParam("redirect_uri", redirectUri)
                        .queryParam("scope", scope)
                        .post("/oauth2/authorize")
                        .then()
                        .statusCode(200)
                        .extract()
                        .response();
    }

    public static String parseForOAuth2Code(Response response) {
        return response.jsonPath().getString("code");
    }

    @BeforeAll
    public static void setup() {
        RestAssured.baseURI = "https://some-url.com";
    }

    @Test
    public void iShouldGetCode() {
        Response response = getCode();
        String code = parseForOAuth2Code(response);

        Assertions.assertNotNull(code);
    }
}

Get Access Token

Once we obtain the authorization code, we can then request for access_token:

public static Response getToken(String authCode) {
    String authorization = encode(username, password);

    return
        given()
            .header("authorization", "Basic " + authorization)
            .contentType(ContentType.URLENC)
            .queryParam("code", authCode)
            .queryParam("redirect_uri", redirectUri)
            .queryParam("grant_type", grantType)
            .post("/oauth2/token")
            .then()
            .statusCode(200)
            .extract()
            .response();
    }

    public static String parseForAccessToken(Response loginResponse) {
        return loginResponse.jsonPath().getString("access_token");
    }

    @Test
    public void iShouldGetToken() {
        Response tokenResponse = getToken(code);
        String accessToken = parseForAccessToken(tokenResponse);
        Assertions.assertNotNull(accessToken);
    }

Using Access Token

Finally, when we have a valid access_token, we can then make requests to protected resources:

public static void getUsers() {
    given().auth()
        .oauth2(accessToken)
        .when()
        .get("/users")
        .then()
        .statusCode(200);
}

We can also send the access token as an Authorization Header with the Bearer prefix:

For example:

public static void getUsers() {
    given()
        .header("Authorization", "Bearer " + accessToken)
        .when()
        .get("/users")
        .then()
        .statusCode(200);
}

Client Credential Flow

The client credential flow has no UI (browser) involved and is mainly used for Machine-to-Machine authorization.

In REST-assured, this will look like:

import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import static io.restassured.RestAssured.given;
import static io.restassured.RestAssured.requestSpecification;

public class RestAssuredOAuth2 {

    public static Response response;
    private String userAdminClientId = System.getenv("M2M_USER_ADMIN_CLIENT_ID");
    private String userAdminClientSecret = System.getenv("M2M_USER_ADMIN_CLIENT_SECRET");

    private String oauth2Payload = "{\n" +
            "  \"client_id\": \"" + userAdminClientId + "\",\n" +
            "  \"client_secret\": \"" + userAdminClientSecret + "\",\n" +
            "  \"audience\": \"https://some-url.com/user\",\n" +
            "  \"grant_type\": \"client_credentials\",\n" +
            "  \"scope\": \"user:admin\" \n}";

    private static String createUserPayload = "{\n" +
            "  \"username\": \"api-user\",\n" +
            "  \"email\": \"api-user@putsbox.com\",\n" +
            "  \"password\": \"Passw0rd123!\",\n" +
            "  \"firstName\": \"my-first-name\",\n" +
            "  \"lastName\": \"my-last-name\",\n" +
            "  \"roles\": [\"read\"] \n}";

    public void userAdminConfigSetup() {
        requestSpecification = given().auth().oauth2(getAccessToken(oauth2Payload))
                .header("Accept", ContentType.JSON.getAcceptHeader())
                .contentType(ContentType.JSON);
    }

    public String getAccessToken(String payload) {
        return given()
                .contentType(ContentType.JSON)
                .body(payload)
                .post("/token")
                .then().extract().response()
                .jsonPath().getString("access_token");
    }

    @BeforeAll
    public static void setup() {
        RestAssured.baseURI = "https://some-url.com";
    }

    @Test
    public void createUser() {
        userAdminConfigSetup();
        response = given(requestSpecification)
                .body(createUserPayload)
                .post("/user")
                .then().extract().response();

        Assertions.assertEquals(201, response.statusCode());
    }
}

Conclusion

Here, we provided code examples with REST-assured on how to get access_token using the OAuth 2.0 flows. Once we get the access_token we can then make requests to protected resources.

Hope you found the above useful.