Unable to authenticate HTTP request to graphql API in C#

Hi all,

I wanted to work with the remote.it graphql API through a web app using ASP.NET, so I was following the authentication guide that was found here:

https://docs.remote.it/developer-tools/authentication

However, I kept getting an error 403 forbidden while doing the request through the RestSharp Client. I thought that it might have been due to my credentials issues, but I was able to get it working via the python http client as well as via bash scripts. Hence, I would appreciate if anyone is able to troubleshoot the following code below. (done in C# console app) I hardcoded the serviceId number just for quick testing purposes, but any other valid serviceId number tied to your account should work:

string endpoint = "https://api.remote.it/graphql/v1";
RestClient Client = new RestClient(endpoint);
private static readonly HMACSHA256 SignatureGenerator = new HMACSHA256(Convert.FromBase64String(ConfigurationManager.AppSettings.Get("R3_SECRET_ACCESS_KEY")));
var resp = await GenerateRemoteLink(Client);
Console.WriteLine(resp);

async Task<RestResponse> GenerateRemoteLink(RestClient _restClient)
{
    string date = DateTime.UtcNow.ToString("ddd, dd MMM yyy HH':'mm':'ss 'GMT'");
    string query = @"{""query"": ""mutation { " +
                @"setConnectLink(serviceId:80:00:00:00:01:27:32:27, enabled: true, password: somepassword) { " +
                @"url password enabled service { id name application } } } ""}";

  
    string signatureParams = "(request-target): post graphql/v1\n" +
        "host: api.remote.it\n" +
        $"date: {date}\n" +
        "content-type: application/json\n" +
        $"content-length: {query.Length}";
    string signature = Convert.ToBase64String(SignatureGenerator.ComputeHash(Encoding.UTF8.GetBytes(signatureParams)));
    RestRequest request = new RestRequest();
    request.AddHeader("Host", "api.remote.it");
    request.AddHeader("Date", date);
    request.AddHeader("Content-Length", query.Length.ToString());
 
    request.AddHeader("Authorization",
        $"Signature keyId=\"{ConfigurationManager.AppSettings.Get("R3_ACCESS_KEY_ID")}\"," +
            "algorithm=\"hmac-sha256\"," +
            "headers=\"(request-target) host date content-type content-length\"," +
            $"signature=\"{signature}\"");

    request.AddStringBody(query, ContentType.Json);
    try
    {
        var response = await _restClient.PostAsync(request);
        Console.WriteLine(response.Content);
        return response;
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex);
        throw new Exception("Not Successful: ", ex);
    }
}

I would have some questions about what version of .net you are using since there are slight syntax changes per version. I would need to setup my environment to match yours in order to help you with the syntax.
The graphQL body itself doesn’t seem to be formatted correctly. I do not see that the serviceId is set as a string, nor the password. I am not sure that RestClient is really built for GraphQL APIs.
Usually you can do the query or mutation itself and the library takes care of adding the query and escaping the characters as needed.

In addition, the setConnectLink for a public url will only work on a service that has a type of HTTP or HTTPS set in Remote.It.

Here is what I typically do with a request library that supports a graphQL query:

mutation {
    setConnectLink(serviceId:"80:00:00:00:01:27:32:27", enabled:true, password:"somepassword") {
        url
        password
        service {
           id
           name
           application
        }
   }
}

Look at the example below which is the actual output that should be the request body.

{"query" : "mutation {setConnectLink(serviceId: \"80:00:00:00:01:27:32:27\", enabled: true, password: \"somepassword\") {url, password, service {id name application}}"}

Hey Brenda, thanks for answering the question.

I was using .NET 6 for the following program. However, even after setting the serviceId / password fields as strings instead, I was still getting the 403 forbidden error. I used the Rest Client because I was just following the authentication quick start guide, and I thought it would be easiest to get things running.

Additionally, is there a way to add new devices to my account programmatically? I have a use case that would like to have devices be set up with remote.it via configured scripts, rather than through the desktop app.

Did you look at how the body is escaped? I don’t know if RestClient actually will do that for you. I am not seeing examples of it handling graphQL queries correctly. I have found a repository for a .NET graphQL client, of course you do not need to use it. I am providing it for reference.

This doesn’t handle the request signing, but I think you understand how to do that.
If you still continue to have issues, then please write me a direct message so that we can have a debug session.

As far as your second question, you will need to still install remote.it on your devices. If all of them will be the same, you may want to review our instructions for OEM production of devices. Registration with Pre-configured Services
If you are looking to just add services we do have an API available for that. Examples can be found in the graphQL Insomnia collection. Using Developer Tools

Let me know if you need further assistance on either topic. If you need further assistance on adding new devices to your account, please start a new topic so we make it easier for the community to find this topic.
Thanks

1 Like

Hey Brenda, it’s been a while since I was last working on this, but I’m still continuing to face issues regarding the query. If you don’t mind, I would appreciate having a debug session with you (I’m not too sure how to write you a direct message on this platform, hence I’m replying to this post again)