public static function login($email, $password, $challenge = '', $code = '') {

        $requestParams = [
            'includePerms' => 'false', // We don't need these here
            'token_type' => 'eg1'
        ];

        if (empty($challenge) && empty($code)) {
            // Regular login
            $requestParams = array_merge($requestParams, [
                'grant_type' => 'password',
                'username' => $email,
                'password' => $password,
            ]);
        } else {
            $requestParams = array_merge($requestParams, [
                'grant_type' => 'otp',
                'otp' => $code,
                'challenge' => $challenge,
            ]);
        }

        // First, we need to get a token for the Unreal Engine client
        $data = FortniteClient::sendUnrealClientPostRequest(FortniteClient::EPIC_OAUTH_TOKEN_ENDPOINT, $requestParams);

        if (!isset($data->access_token)) {
            if ($data->errorCode === 'errors.com.epicgames.common.two_factor_authentication.required') {
                throw new TwoFactorAuthRequiredException($data->challenge);
            }

            throw new \Exception($data->errorMessage);
        }

        // Now that we've got our Unreal Client launcher token, let's get an exchange token for Fortnite
        $data = FortniteClient::sendUnrealClientGetRequest(FortniteClient::EPIC_OAUTH_EXCHANGE_ENDPOINT, $data->access_token, true);

        if (!isset($data->code)) {
            throw new \Exception($data->errorMessage);
        }

        // Should be good. Let's get our tokens for the Fortnite API
        $data = FortniteClient::sendUnrealClientPostRequest(FortniteClient::EPIC_OAUTH_TOKEN_ENDPOINT, [
            'grant_type' => 'exchange_code',
            'exchange_code' => $data->code,
            'includePerms' => false, // We don't need these here
            'token_type' => 'eg1'
        ], FortniteClient::FORTNITE_AUTHORIZATION);

        if (!isset($data->access_token)) {
            throw new \Exception($data->errorMessage);
        }

        return new self($data->access_token, $data->in_app_id, $data->refresh_token, $data->account_id, $data->expires_in);
    }