Using REST-assured to Test OAuth 2.0 flow Examples

Amir Ghahrai

Amir Ghahrai

Follow on Twitter


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.

#api-testing #http