com.auth0.android.authentication.AuthenticationAPIClientTest.java Source code

Java tutorial

Introduction

Here is the source code for com.auth0.android.authentication.AuthenticationAPIClientTest.java

Source

/*
 * AuthenticationAPIClientTest.java
 *
 * Copyright (c) 2015 Auth0 (http://auth0.com)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

package com.auth0.android.authentication;

import android.content.Context;
import android.content.res.Resources;

import com.auth0.android.Auth0;
import com.auth0.android.request.internal.RequestFactory;
import com.auth0.android.result.Authentication;
import com.auth0.android.result.Credentials;
import com.auth0.android.result.DatabaseUser;
import com.auth0.android.result.Delegation;
import com.auth0.android.result.UserProfile;
import com.auth0.android.util.AuthenticationAPI;
import com.auth0.android.util.MockAuthenticationCallback;
import com.auth0.android.util.Telemetry;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.HttpUrl;
import com.squareup.okhttp.Interceptor;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.logging.HttpLoggingInterceptor;
import com.squareup.okhttp.mockwebserver.RecordedRequest;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;

import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import static com.auth0.android.util.AuthenticationAPI.GENERIC_TOKEN;
import static com.auth0.android.util.AuthenticationAPI.ID_TOKEN;
import static com.auth0.android.util.AuthenticationAPI.REFRESH_TOKEN;
import static com.auth0.android.util.AuthenticationCallbackMatcher.hasError;
import static com.auth0.android.util.AuthenticationCallbackMatcher.hasNoError;
import static com.auth0.android.util.AuthenticationCallbackMatcher.hasPayload;
import static com.auth0.android.util.AuthenticationCallbackMatcher.hasPayloadOfType;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.hasKey;
import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(RobolectricTestRunner.class)
@Config(constants = com.auth0.android.auth0.BuildConfig.class, sdk = 21, manifest = Config.NONE)
public class AuthenticationAPIClientTest {

    private static final String CLIENT_ID = "CLIENTID";
    private static final String DOMAIN = "samples.auth0.com";
    private static final String PASSWORD = "123123123";
    private static final String SUPPORT_AUTH0_COM = "support@auth0.com";
    private static final String SUPPORT = "support";
    private static final String MY_CONNECTION = "MyConnection";
    private static final String FIRST_NAME = "John";
    private static final String LAST_NAME = "Doe";
    private static final String COMPANY = "Auth0";
    private static final String OPENID = "openid";

    private AuthenticationAPIClient client;
    private Auth0 auth0;
    private Gson gson;

    private AuthenticationAPI mockAPI;

    @Before
    public void setUp() throws Exception {
        mockAPI = new AuthenticationAPI();
        final String domain = mockAPI.getDomain();
        auth0 = new Auth0(CLIENT_ID, domain, domain);
        client = new AuthenticationAPIClient(auth0);
        gson = new GsonBuilder().serializeNulls().create();
    }

    @After
    public void tearDown() throws Exception {
        mockAPI.shutdown();
    }

    @Test
    public void shouldSetUserAgent() throws Exception {
        Auth0 account = mock(Auth0.class);
        RequestFactory factory = mock(RequestFactory.class);
        OkHttpClient okClient = mock(OkHttpClient.class);
        AuthenticationAPIClient client = new AuthenticationAPIClient(account, factory, okClient);
        client.setUserAgent("nexus-5x");
        verify(factory).setUserAgent("nexus-5x");
    }

    @Test
    public void shouldSetTelemetryIfPresent() throws Exception {
        final Telemetry telemetry = mock(Telemetry.class);
        when(telemetry.getValue()).thenReturn("the-telemetry-data");
        RequestFactory factory = mock(RequestFactory.class);
        OkHttpClient okClient = mock(OkHttpClient.class);
        Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
        auth0.setTelemetry(telemetry);
        new AuthenticationAPIClient(auth0, factory, okClient);
        verify(factory).setClientInfo("the-telemetry-data");
    }

    @Test
    public void shouldNotSetTelemetryIfMissing() throws Exception {
        RequestFactory factory = mock(RequestFactory.class);
        OkHttpClient okClient = mock(OkHttpClient.class);
        Auth0 auth0 = new Auth0(CLIENT_ID, DOMAIN);
        auth0.doNotSendTelemetry();
        new AuthenticationAPIClient(auth0, factory, okClient);
        verify(factory, never()).setClientInfo(any(String.class));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void shouldEnableHttpLogging() throws Exception {
        Auth0 account = mock(Auth0.class);
        when(account.isLoggingEnabled()).thenReturn(true);
        RequestFactory factory = mock(RequestFactory.class);
        OkHttpClient okClient = mock(OkHttpClient.class);
        List list = mock(List.class);
        when(okClient.interceptors()).thenReturn(list);

        ArgumentCaptor<Interceptor> interceptorCaptor = ArgumentCaptor.forClass(Interceptor.class);
        new AuthenticationAPIClient(account, factory, okClient);

        verify(okClient).interceptors();
        verify(list).add(interceptorCaptor.capture());

        assertThat(interceptorCaptor.getValue(), is(notNullValue()));
        assertThat(interceptorCaptor.getValue(), is(instanceOf(HttpLoggingInterceptor.class)));
        assertThat(((HttpLoggingInterceptor) interceptorCaptor.getValue()).getLevel(),
                is(HttpLoggingInterceptor.Level.BODY));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void shouldDisableHttpLogging() throws Exception {
        Auth0 account = mock(Auth0.class);
        when(account.isLoggingEnabled()).thenReturn(false);
        RequestFactory factory = mock(RequestFactory.class);
        OkHttpClient okClient = mock(OkHttpClient.class);
        List list = mock(List.class);
        when(okClient.interceptors()).thenReturn(list);

        new AuthenticationAPIClient(account, factory, okClient);

        verify(okClient, never()).interceptors();
        verify(list, never()).add(any(Interceptor.class));
    }

    @SuppressWarnings("unchecked")
    @Test
    public void shouldHaveHttpLoggingDisabledByDefault() throws Exception {
        Auth0 account = mock(Auth0.class);
        RequestFactory factory = mock(RequestFactory.class);
        OkHttpClient okClient = mock(OkHttpClient.class);
        List list = mock(List.class);
        when(okClient.interceptors()).thenReturn(list);

        new AuthenticationAPIClient(account, factory, okClient);

        verify(okClient, never()).interceptors();
        verify(list, never()).add(any(Interceptor.class));
    }

    @Test
    public void shouldCreateClientWithAccountInfo() throws Exception {
        AuthenticationAPIClient client = new AuthenticationAPIClient(new Auth0(CLIENT_ID, DOMAIN));
        assertThat(client, is(notNullValue()));
        assertThat(client.getClientId(), equalTo(CLIENT_ID));
        assertThat(HttpUrl.parse(client.getBaseURL()), notNullValue());
        assertThat(HttpUrl.parse(client.getBaseURL()).scheme(), equalTo("https"));
        assertThat(HttpUrl.parse(client.getBaseURL()).host(), equalTo(DOMAIN));
        assertThat(HttpUrl.parse(client.getBaseURL()).pathSize(), is(1));
        assertThat(HttpUrl.parse(client.getBaseURL()).encodedPath(), is("/"));
    }

    @Test
    public void shouldCreateClientWithContextInfo() throws Exception {
        Context context = Mockito.mock(Context.class);
        Resources resources = Mockito.mock(Resources.class);
        when(context.getResources()).thenReturn(resources);
        when(resources.getIdentifier(eq("com_auth0_client_id"), eq("string"), anyString())).thenReturn(222);
        when(resources.getIdentifier(eq("com_auth0_domain"), eq("string"), anyString())).thenReturn(333);

        when(context.getString(eq(222))).thenReturn(CLIENT_ID);
        when(context.getString(eq(333))).thenReturn(DOMAIN);

        AuthenticationAPIClient client = new AuthenticationAPIClient(context);

        assertThat(client, is(notNullValue()));
        assertThat(client.getClientId(), is(CLIENT_ID));
        assertThat(client.getBaseURL(), equalTo("https://" + DOMAIN + "/"));
    }

    @Test
    public void shouldLoginWithUserAndPassword() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();

        client.login(SUPPORT_AUTH0_COM, "voidpassword", MY_CONNECTION).start(callback);

        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", MY_CONNECTION));
        assertThat(body, not(hasKey("realm")));
    }

    @Test
    public void shouldLoginWithUserAndPasswordSync() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final Credentials credentials = client.login(SUPPORT_AUTH0_COM, "voidpassword", MY_CONNECTION).execute();

        assertThat(credentials, is(notNullValue()));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", MY_CONNECTION));
        assertThat(body, not(hasKey("realm")));
    }

    @Test
    public void shouldLoginWithPasswordReamGrant() throws Exception {
        mockAPI.willReturnSuccessfulLogin();
        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();

        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(true);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
        client.login(SUPPORT_AUTH0_COM, "some-password", MY_CONNECTION).start(callback);
        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        Map<String, String> body = bodyFromRequest(request);

        assertThat(request.getPath(), equalTo("/oauth/token"));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("grant_type", "http://auth0.com/oauth/grant-type/password-realm"));
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "some-password"));
        assertThat(body, hasEntry("realm", MY_CONNECTION));
        assertThat(body, not(hasKey("connection")));
        assertThat(body, not(hasKey("scope")));
        assertThat(body, not(hasKey("audience")));
    }

    @Test
    public void shouldLoginWithUserAndPasswordUsingOAuthTokenEndpoint() throws Exception {
        mockAPI.willReturnSuccessfulLogin();
        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();

        client.login(SUPPORT_AUTH0_COM, "some-password").start(callback);
        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getPath(), is("/oauth/token"));
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("grant_type", "password"));
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "some-password"));
        assertThat(body, not(hasKey("realm")));
        assertThat(body, not(hasKey("connection")));
        assertThat(body, not(hasKey("scope")));
        assertThat(body, not(hasKey("audience")));
    }

    @Test
    public void shouldLoginWithUserAndPasswordSyncUsingOAuthTokenEndpoint() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final Credentials credentials = client.login(SUPPORT_AUTH0_COM, "some-password").execute();
        assertThat(credentials, is(notNullValue()));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getPath(), is("/oauth/token"));
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("grant_type", "password"));
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "some-password"));
        assertThat(body, not(hasKey("realm")));
        assertThat(body, not(hasKey("connection")));
        assertThat(body, not(hasKey("scope")));
        assertThat(body, not(hasKey("audience")));
    }

    @Test
    public void shouldFetchTokenInfo() throws Exception {
        mockAPI.willReturnTokenInfo();
        final MockAuthenticationCallback<UserProfile> callback = new MockAuthenticationCallback<>();

        client.tokenInfo("ID_TOKEN").start(callback);

        assertThat(callback, hasPayloadOfType(UserProfile.class));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/tokeninfo"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("id_token", "ID_TOKEN"));
    }

    @Test
    public void shouldFetchTokenInfoSync() throws Exception {
        mockAPI.willReturnTokenInfo();

        final UserProfile profile = client.tokenInfo("ID_TOKEN").execute();

        assertThat(profile, is(notNullValue()));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/tokeninfo"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("id_token", "ID_TOKEN"));
    }

    @Test
    public void shouldFetchUserInfo() throws Exception {
        mockAPI.willReturnTokenInfo();
        final MockAuthenticationCallback<UserProfile> callback = new MockAuthenticationCallback<>();

        client.userInfo("ACCESS_TOKEN").start(callback);

        assertThat(callback, hasPayloadOfType(UserProfile.class));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getHeader("Authorization"), is("Bearer ACCESS_TOKEN"));
        assertThat(request.getPath(), equalTo("/userinfo"));
    }

    @Test
    public void shouldFetchUserInfoSync() throws Exception {
        mockAPI.willReturnTokenInfo();

        final UserProfile profile = client.userInfo("ACCESS_TOKEN").execute();

        assertThat(profile, is(notNullValue()));

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getHeader("Authorization"), is("Bearer ACCESS_TOKEN"));
        assertThat(request.getPath(), equalTo("/userinfo"));
    }

    @Test
    public void shouldLoginWithOAuthAccessToken() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.loginWithOAuthAccessToken("fbtoken", "facebook").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/access_token"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", "facebook"));
        assertThat(body, hasEntry("access_token", "fbtoken"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldLoginWithOAuthAccessTokenSync() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final Credentials credentials = client.loginWithOAuthAccessToken("fbtoken", "facebook").execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/access_token"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", "facebook"));
        assertThat(body, hasEntry("access_token", "fbtoken"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(credentials, is(notNullValue()));
    }

    @Test
    public void shouldLoginWithPhoneNumberWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.loginWithPhoneNumber("+10101010101", "1234", MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", MY_CONNECTION));
        assertThat(body, hasEntry("username", "+10101010101"));
        assertThat(body, hasEntry("password", "1234"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldLoginWithPhoneNumber() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.loginWithPhoneNumber("+10101010101", "1234").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", "sms"));
        assertThat(body, hasEntry("username", "+10101010101"));
        assertThat(body, hasEntry("password", "1234"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldLoginWithPhoneNumberSync() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final Credentials credentials = client.loginWithPhoneNumber("+10101010101", "1234").execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", "sms"));
        assertThat(body, hasEntry("username", "+10101010101"));
        assertThat(body, hasEntry("password", "1234"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(credentials, is(notNullValue()));
    }

    @Test
    public void shouldLoginWithEmailOnlyWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.loginWithEmail(SUPPORT_AUTH0_COM, "1234", MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", MY_CONNECTION));
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "1234"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldLoginWithEmailOnly() throws Exception {
        mockAPI.willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.loginWithEmail(SUPPORT_AUTH0_COM, "1234").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", "email"));
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "1234"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldLoginWithEmailOnlySync() throws Exception {
        mockAPI.willReturnSuccessfulLogin().willReturnTokenInfo();

        final Credentials credentials = client.loginWithEmail(SUPPORT_AUTH0_COM, "1234").execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("connection", "email"));
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "1234"));
        assertThat(body, hasEntry("scope", OPENID));

        assertThat(credentials, is(notNullValue()));
    }

    @Test
    public void shouldCreateUser() throws Exception {
        mockAPI.willReturnSuccessfulSignUp();

        final MockAuthenticationCallback<DatabaseUser> callback = new MockAuthenticationCallback<>();
        client.createUser(SUPPORT_AUTH0_COM, PASSWORD, SUPPORT, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("username", SUPPORT));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(DatabaseUser.class));
    }

    @Test
    public void shouldCreateUserSync() throws Exception {
        mockAPI.willReturnSuccessfulSignUp();

        final DatabaseUser user = client.createUser(SUPPORT_AUTH0_COM, PASSWORD, SUPPORT, MY_CONNECTION).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("username", SUPPORT));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(user, is(notNullValue()));
    }

    @Test
    public void shouldCreateUserWithoutUsername() throws Exception {
        mockAPI.willReturnSuccessfulSignUp();

        final MockAuthenticationCallback<DatabaseUser> callback = new MockAuthenticationCallback<>();
        client.createUser(SUPPORT_AUTH0_COM, PASSWORD, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(DatabaseUser.class));
    }

    @Test
    public void shouldCreateUserWithoutUsernameSync() throws Exception {
        mockAPI.willReturnSuccessfulSignUp();

        final DatabaseUser user = client.createUser(SUPPORT_AUTH0_COM, PASSWORD, MY_CONNECTION).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(user, is(notNullValue()));
    }

    @Test
    public void shouldNotSendNullUsernameOnSignUp() throws Exception {
        mockAPI.willReturnSuccessfulSignUp();

        final MockAuthenticationCallback<DatabaseUser> callback = new MockAuthenticationCallback<>();
        //noinspection ConstantConditions
        client.createUser(SUPPORT_AUTH0_COM, PASSWORD, null, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(DatabaseUser.class));
    }

    @Test
    public void shouldNotSendNullUsernameOnSignUpSync() throws Exception {
        mockAPI.willReturnSuccessfulSignUp();

        //noinspection ConstantConditions
        final DatabaseUser user = client.createUser(SUPPORT_AUTH0_COM, PASSWORD, null, MY_CONNECTION).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(user, is(notNullValue()));
    }

    @Test
    public void shouldSignUpUser() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.signUp(SUPPORT_AUTH0_COM, PASSWORD, SUPPORT, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("username", SUPPORT));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest loginRequest = mockAPI.takeRequest();
        assertThat(loginRequest.getPath(), equalTo("/oauth/ro"));

        Map<String, String> loginBody = bodyFromRequest(loginRequest);
        assertThat(loginBody, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(loginBody, hasEntry("password", PASSWORD));
        assertThat(loginBody, hasEntry("connection", MY_CONNECTION));
        assertThat(loginBody, hasEntry("scope", OPENID));
        assertThat(loginBody, not(hasKey("realm")));
    }

    @Test
    public void shouldLoginWithUsernameSignedUpUserWithPasswordReamGrant() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(true);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
        client.signUp(SUPPORT_AUTH0_COM, PASSWORD, SUPPORT, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("username", SUPPORT));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest loginRequest = mockAPI.takeRequest();
        assertThat(loginRequest.getPath(), equalTo("/oauth/token"));

        Map<String, String> loginBody = bodyFromRequest(loginRequest);
        assertThat(loginBody, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(loginBody, hasEntry("password", PASSWORD));
        assertThat(loginBody, hasEntry("realm", MY_CONNECTION));
        assertThat(loginBody, not(hasKey("scope")));
        assertThat(loginBody, not(hasKey("connection")));
    }

    @Test
    public void shouldSignUpUserWithCustomFields() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        final Map<String, Object> custom = ParameterBuilder.newBuilder().set("first_name", FIRST_NAME)
                .set("last_name", LAST_NAME).set("company", COMPANY).asDictionary();

        client.signUp(SUPPORT_AUTH0_COM, PASSWORD, SUPPORT, MY_CONNECTION).addSignUpParameters(custom)
                .start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("username", SUPPORT));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));
        assertThat(body, hasEntry("first_name", FIRST_NAME));
        assertThat(body, hasEntry("last_name", LAST_NAME));
        assertThat(body, hasEntry("company", COMPANY));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldSignUpUserSync() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin().willReturnTokenInfo();

        final Credentials credentials = client.signUp(SUPPORT_AUTH0_COM, PASSWORD, SUPPORT, MY_CONNECTION)
                .execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("username", SUPPORT));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(credentials, is(notNullValue()));

        final RecordedRequest loginRequest = mockAPI.takeRequest();
        assertThat(loginRequest.getPath(), equalTo("/oauth/ro"));

        Map<String, String> loginBody = bodyFromRequest(loginRequest);
        assertThat(loginBody, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(loginBody, hasEntry("password", PASSWORD));
        assertThat(loginBody, hasEntry("connection", MY_CONNECTION));
        assertThat(loginBody, hasEntry("scope", OPENID));
    }

    @Test
    public void shouldSignUpUserWithoutUsername() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin().willReturnTokenInfo();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.signUp(SUPPORT_AUTH0_COM, PASSWORD, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest loginRequest = mockAPI.takeRequest();
        assertThat(loginRequest.getPath(), equalTo("/oauth/ro"));

        Map<String, String> loginBody = bodyFromRequest(loginRequest);
        assertThat(loginBody, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(loginBody, hasEntry("password", PASSWORD));
        assertThat(loginBody, hasEntry("connection", MY_CONNECTION));
        assertThat(loginBody, hasEntry("scope", OPENID));
        assertThat(loginBody, not(hasKey("realm")));
    }

    @Test
    public void shouldLoginSignedUpUserWithPasswordRealmGrant() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin().willReturnTokenInfo();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(true);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
        client.signUp(SUPPORT_AUTH0_COM, PASSWORD, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasPayloadOfType(Credentials.class));

        final RecordedRequest loginRequest = mockAPI.takeRequest();
        assertThat(loginRequest.getPath(), equalTo("/oauth/token"));

        Map<String, String> loginBody = bodyFromRequest(loginRequest);
        assertThat(loginBody, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(loginBody, hasEntry("password", PASSWORD));
        assertThat(loginBody, hasEntry("realm", MY_CONNECTION));
        assertThat(loginBody, not(hasKey("scope")));
        assertThat(loginBody, not(hasKey("connection")));
    }

    @Test
    public void shouldSignUpUserWithoutUsernameSync() throws Exception {
        mockAPI.willReturnSuccessfulSignUp().willReturnSuccessfulLogin().willReturnTokenInfo();

        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(false);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);
        final Credentials credentials = client.signUp(SUPPORT_AUTH0_COM, PASSWORD, MY_CONNECTION).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/signup"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("password", PASSWORD));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(credentials, is(notNullValue()));

        final RecordedRequest loginRequest = mockAPI.takeRequest();
        assertThat(loginRequest.getPath(), equalTo("/oauth/ro"));

        Map<String, String> loginBody = bodyFromRequest(loginRequest);
        assertThat(loginBody, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(loginBody, hasEntry("password", PASSWORD));
        assertThat(loginBody, hasEntry("connection", MY_CONNECTION));
        assertThat(loginBody, hasEntry("scope", OPENID));
        assertThat(loginBody, not(hasKey("realm")));
    }

    @Test
    public void shouldChangePassword() throws Exception {
        mockAPI.willReturnSuccessfulChangePassword();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/change_password"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldChangePasswordSync() throws Exception {
        mockAPI.willReturnSuccessfulChangePassword();

        client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/change_password"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, hasEntry("connection", MY_CONNECTION));
    }

    @Test
    public void shouldRequestChangePassword() throws Exception {
        mockAPI.willReturnSuccessfulChangePassword();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/change_password"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, not(hasKey("password")));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldRequestChangePasswordSync() throws Exception {
        mockAPI.willReturnSuccessfulChangePassword();

        client.resetPassword(SUPPORT_AUTH0_COM, MY_CONNECTION).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/dbconnections/change_password"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, not(hasKey("username")));
        assertThat(body, not(hasKey("password")));
        assertThat(body, hasEntry("connection", MY_CONNECTION));
    }

    @Test
    public void shouldCallDelegation() throws Exception {
        mockAPI.willReturnGenericDelegationToken();

        final MockAuthenticationCallback<Map<String, Object>> callback = new MockAuthenticationCallback<>();
        client.delegation().start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));

        Map<String, Object> payload = new HashMap<>();
        payload.put("token", GENERIC_TOKEN);
        assertThat(callback, hasPayload(payload));
    }

    @Test
    public void shouldCallDelegationSync() throws Exception {
        mockAPI.willReturnGenericDelegationToken();

        final Map<String, Object> response = client.delegation().execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));

        Map<String, Object> payload = new HashMap<>();
        payload.put("token", GENERIC_TOKEN);
        assertThat(response, is(equalTo(payload)));
    }

    @Test
    public void shouldGetNewIdTokenWithIdToken() throws Exception {
        mockAPI.willReturnNewIdToken();

        final MockAuthenticationCallback<Delegation> callback = new MockAuthenticationCallback<>();
        client.delegationWithIdToken(ID_TOKEN).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("api_type", "app"));
        assertThat(body, hasEntry("id_token", ID_TOKEN));

        assertThat(callback, hasPayloadOfType(Delegation.class));
    }

    @Test
    public void shouldGetNewIdTokenWithIdTokenSync() throws Exception {
        mockAPI.willReturnNewIdToken();

        final Delegation delegation = client.delegationWithIdToken(ID_TOKEN).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("api_type", "app"));
        assertThat(body, hasEntry("id_token", ID_TOKEN));

        assertThat(delegation, is(notNullValue()));
    }

    @Test
    public void shouldGetCustomizedDelegationRequestWithIdToken() throws Exception {
        mockAPI.willReturnNewIdToken();

        final MockAuthenticationCallback<Map<String, Object>> callback = new MockAuthenticationCallback<>();
        client.delegationWithIdToken(ID_TOKEN, "custom_api_type").setScope("custom_scope")
                .setTarget("custom_target").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("api_type", "custom_api_type"));
        assertThat(body, hasEntry("scope", "custom_scope"));
        assertThat(body, hasEntry("target", "custom_target"));
        assertThat(body, hasEntry("id_token", ID_TOKEN));
    }

    @Test
    public void shouldGetCustomizedDelegationRequestWithIdTokenSync() throws Exception {
        mockAPI.willReturnNewIdToken();

        client.delegationWithIdToken(ID_TOKEN, "custom_api_type").setScope("custom_scope")
                .setTarget("custom_target").execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("api_type", "custom_api_type"));
        assertThat(body, hasEntry("scope", "custom_scope"));
        assertThat(body, hasEntry("target", "custom_target"));
        assertThat(body, hasEntry("id_token", ID_TOKEN));
    }

    @Test
    public void shouldGetNewIdTokenWithRefreshToken() throws Exception {
        mockAPI.willReturnNewIdToken();

        final MockAuthenticationCallback<Delegation> callback = new MockAuthenticationCallback<>();
        client.delegationWithRefreshToken(REFRESH_TOKEN).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("api_type", "app"));
        assertThat(body, hasEntry("refresh_token", REFRESH_TOKEN));

        assertThat(callback, hasPayloadOfType(Delegation.class));
    }

    @Test
    public void shouldGetNewIdTokenWithRefreshTokenSync() throws Exception {
        mockAPI.willReturnNewIdToken();

        final Delegation delegation = client.delegationWithRefreshToken(REFRESH_TOKEN).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_JWT));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("api_type", "app"));
        assertThat(body, hasEntry("refresh_token", REFRESH_TOKEN));

        assertThat(delegation, is(notNullValue()));
    }

    @Test
    public void shouldSendEmailCodeWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.CODE, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "code"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendEmailCode() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.CODE).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "code"));
        assertThat(body, hasEntry("connection", "email"));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendEmailCodeSync() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.CODE).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "code"));
        assertThat(body, hasEntry("connection", "email"));
    }

    @Test
    public void shouldSendEmailLink() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.WEB_LINK).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "link"));
        assertThat(body, hasEntry("connection", "email"));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendEmailLinkWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.WEB_LINK, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "link"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendEmailLinkSync() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.WEB_LINK).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "link"));
        assertThat(body, hasEntry("connection", "email"));
    }

    @Test
    public void shouldSendEmailLinkAndroidWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.ANDROID_LINK, MY_CONNECTION)
                .start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "link_android"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendEmailLinkAndroid() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.ANDROID_LINK).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "link_android"));
        assertThat(body, hasEntry("connection", "email"));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendEmailLinkAndroidSync() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        client.passwordlessWithEmail(SUPPORT_AUTH0_COM, PasswordlessType.ANDROID_LINK).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("email", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("send", "link_android"));
        assertThat(body, hasEntry("connection", "email"));
    }

    @Test
    public void shouldSendSMSCodeWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithSMS("+1123123123", PasswordlessType.CODE, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "code"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendSMSCode() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithSMS("+1123123123", PasswordlessType.CODE).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "code"));
        assertThat(body, hasEntry("connection", "sms"));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendSMSCodeSync() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        client.passwordlessWithSMS("+1123123123", PasswordlessType.CODE).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "code"));
        assertThat(body, hasEntry("connection", "sms"));
    }

    @Test
    public void shouldSendSMSLinkWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithSMS("+1123123123", PasswordlessType.WEB_LINK, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "link"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendSMSLink() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithSMS("+1123123123", PasswordlessType.WEB_LINK).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "link"));
        assertThat(body, hasEntry("connection", "sms"));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendSMSLinkSync() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        client.passwordlessWithSMS("+1123123123", PasswordlessType.WEB_LINK).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "link"));
        assertThat(body, hasEntry("connection", "sms"));
    }

    @Test
    public void shouldSendSMSLinkAndroidWithCustomConnection() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithSMS("+1123123123", PasswordlessType.ANDROID_LINK, MY_CONNECTION).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "link_android"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendSMSLinkAndroid() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        final MockAuthenticationCallback<Void> callback = new MockAuthenticationCallback<>();
        client.passwordlessWithSMS("+1123123123", PasswordlessType.ANDROID_LINK).start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "link_android"));
        assertThat(body, hasEntry("connection", "sms"));

        assertThat(callback, hasNoError());
    }

    @Test
    public void shouldSendSMSLinkAndroidSync() throws Exception {
        mockAPI.willReturnSuccessfulPasswordlessStart();

        client.passwordlessWithSMS("+1123123123", PasswordlessType.ANDROID_LINK).execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/passwordless/start"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("phone_number", "+1123123123"));
        assertThat(body, hasEntry("send", "link_android"));
        assertThat(body, hasEntry("connection", "sms"));
    }

    @Test
    public void shouldFetchProfileAfterLoginRequest() throws Exception {
        mockAPI.willReturnSuccessfulLogin().willReturnTokenInfo();

        MockAuthenticationCallback<Authentication> callback = new MockAuthenticationCallback<>();
        client.getProfileAfter(client.login(SUPPORT_AUTH0_COM, "voidpassword", MY_CONNECTION)).start(callback);

        final RecordedRequest firstRequest = mockAPI.takeRequest();
        assertThat(firstRequest.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(firstRequest);
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "voidpassword"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        final RecordedRequest secondRequest = mockAPI.takeRequest();
        assertThat(secondRequest.getHeader("Authorization"), is("Bearer " + AuthenticationAPI.ACCESS_TOKEN));
        assertThat(secondRequest.getPath(), equalTo("/userinfo"));

        assertThat(callback, hasPayloadOfType(Authentication.class));
    }

    @Test
    public void shouldRenewAuthWithOAuthTokenIfOIDCConformant() throws Exception {
        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(true);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);

        mockAPI.willReturnSuccessfulLogin();
        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.renewAuth("refreshToken").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/token"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("refresh_token", "refreshToken"));
        assertThat(body, hasEntry("grant_type", "refresh_token"));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldRenewAuthWithOAuthTokenIfOIDCConformantSync() throws Exception {
        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(true);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);

        mockAPI.willReturnSuccessfulLogin();
        Credentials credentials = client.renewAuth("refreshToken").execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/oauth/token"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("refresh_token", "refreshToken"));
        assertThat(body, hasEntry("grant_type", "refresh_token"));

        assertThat(credentials, is(notNullValue()));
    }

    @Test
    public void shouldRenewAuthWithDelegationIfNotOIDCConformant() throws Exception {
        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(false);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);

        mockAPI.willReturnSuccessfulLogin();
        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.renewAuth("refreshToken").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("refresh_token", "refreshToken"));
        assertThat(body, hasEntry("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldRenewAuthWithDelegationIfNotOIDCConformantSync() throws Exception {
        Auth0 auth0 = new Auth0(CLIENT_ID, mockAPI.getDomain(), mockAPI.getDomain());
        auth0.setOIDCConformant(false);
        AuthenticationAPIClient client = new AuthenticationAPIClient(auth0);

        mockAPI.willReturnSuccessfulLogin();
        Credentials credentials = client.renewAuth("refreshToken").execute();

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getHeader("Accept-Language"), is(getDefaultLocale()));
        assertThat(request.getPath(), equalTo("/delegation"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("refresh_token", "refreshToken"));
        assertThat(body, hasEntry("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer"));

        assertThat(credentials, is(notNullValue()));
    }

    @Test
    public void shouldFetchProfileSyncAfterLoginRequest() throws Exception {
        mockAPI.willReturnSuccessfulLogin().willReturnTokenInfo();

        Authentication authentication = client
                .getProfileAfter(client.login(SUPPORT_AUTH0_COM, "voidpassword", MY_CONNECTION)).execute();

        final RecordedRequest firstRequest = mockAPI.takeRequest();
        assertThat(firstRequest.getPath(), equalTo("/oauth/ro"));

        Map<String, String> body = bodyFromRequest(firstRequest);
        assertThat(body, hasEntry("username", SUPPORT_AUTH0_COM));
        assertThat(body, hasEntry("password", "voidpassword"));
        assertThat(body, hasEntry("connection", MY_CONNECTION));

        final RecordedRequest secondRequest = mockAPI.takeRequest();
        assertThat(secondRequest.getHeader("Authorization"), is("Bearer " + AuthenticationAPI.ACCESS_TOKEN));
        assertThat(secondRequest.getPath(), equalTo("/userinfo"));

        assertThat(authentication, is(notNullValue()));
    }

    @Test
    public void shouldGetOAuthTokensUsingCodeVerifier() throws Exception {
        mockAPI.willReturnTokens().willReturnTokenInfo();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.token("code", "http://redirect.uri").setCodeVerifier("codeVerifier").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getPath(), equalTo("/oauth/token"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_AUTHORIZATION_CODE));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("code", "code"));
        assertThat(body, hasEntry("code_verifier", "codeVerifier"));
        assertThat(body, hasEntry("redirect_uri", "http://redirect.uri"));

        assertThat(callback, hasPayloadOfType(Credentials.class));
    }

    @Test
    public void shouldParseUnauthorizedPKCEError() throws Exception {
        mockAPI.willReturnPlainTextUnauthorized();

        final MockAuthenticationCallback<Credentials> callback = new MockAuthenticationCallback<>();
        client.token("code", "http://redirect.uri").setCodeVerifier("codeVerifier").start(callback);

        final RecordedRequest request = mockAPI.takeRequest();
        assertThat(request.getPath(), equalTo("/oauth/token"));

        Map<String, String> body = bodyFromRequest(request);
        assertThat(body, hasEntry("grant_type", ParameterBuilder.GRANT_TYPE_AUTHORIZATION_CODE));
        assertThat(body, hasEntry("client_id", CLIENT_ID));
        assertThat(body, hasEntry("code", "code"));
        assertThat(body, hasEntry("code_verifier", "codeVerifier"));
        assertThat(body, hasEntry("redirect_uri", "http://redirect.uri"));

        assertThat(callback, hasError(Credentials.class));
        assertThat(callback.getError().getDescription(), is(equalTo("Unauthorized")));
    }

    private Map<String, String> bodyFromRequest(RecordedRequest request) throws java.io.IOException {
        final Type mapType = new TypeToken<Map<String, String>>() {
        }.getType();
        return gson.fromJson(request.getBody().readUtf8(), mapType);
    }

    private String getDefaultLocale() {
        String language = Locale.getDefault().toString();
        return !language.isEmpty() ? language : "en";
    }
}