Anyone have any C# sample code to authenicate to the API and make some requests?

  • 1
  • Question
  • Updated 3 years ago
  • Answered
Not sure how to do Oauth2 authentication to a web API in C#. If anyone has done so already, could please share some sample code, so I don't have to re-invent the wheel.
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb

Posted 3 years ago

  • 1
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
Hey Todd,

There is an unofficial C# SDK available here which might be of help: https://github.com/grokify/ringcentral-sdk-csharp-simple

There are examples for just obtaining the RingCentral SDK Client, and a simple example for sending an SMS message once you've authenticated.
Photo of FirstLab Admin2

FirstLab Admin2

  • 100 Points 100 badge 2x thumb
All we want to do is download incoming faxes. Can we use the SDK to accomplish this, or do we need to use a regular HttpWebRequest?

Thank you for you help!
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
You can use either the SDK, or a standard REST API request directly.
Photo of FirstLab Admin2

FirstLab Admin2

  • 100 Points 100 badge 2x thumb
So, I was thinking we could use the standard REST API request directly. Which is why I asked if anyone has any sample code to authenticate. Sending and receiving JSON is pretty simple. They only tricky part is authenticating.

Do you have any code sample for how to do the authentication? Or do you suggest I just try to use the SDK?
(Edited)
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
Have you tried ripping the authentication code out of the community C# SDK?
Photo of FirstLab Admin2

FirstLab Admin2

  • 100 Points 100 badge 2x thumb
No, I looked for the authentication code but could not find it.  It was calling the SDK. I found this but it was calling the SKD.

public Client(string appKey, string appSecret, string serverUrl) { Sdk = new RingCentral.SDK.SDK(appKey, appSecret, serverUrl); }

So where is the code in the SDK that does the authentication? That's all I need.
Photo of FirstLab Admin2

FirstLab Admin2

  • 100 Points 100 badge 2x thumb
I went to here https://github.com/ringcentral/ringcentral-csharp and there is nothing. Just a readme.
Photo of VB

VB, Official Rep

  • 1,510 Points 1k badge 2x thumb
Could you have a look at this?https://github.com/grokify/ringcentral-sdk-csharp-simple

Its a unofficial SDK implementation inC# . You could use this as a reference or could start your own implementation keeping this as a base SDK.


Let us know if you need help.  
Photo of FirstLab Admin2

FirstLab Admin2

  • 100 Points 100 badge 2x thumb
I looked at it. It didn't help. You said I could use the REST API. Can you give me an example of some code to do the authentication rather than asking me to look at https://github.com/grokify/ringcentral-sdk-csharp-simple? Why can't you provide a sample for me? I know you can do it, but the source code is is not on GIT. Why is it hidden?
Photo of VB

VB, Official Rep

  • 1,510 Points 1k badge 2x thumb
C# SDK is still under prealpha stage and not ready to be made public. If you just want to see how it can be implemented in C# - you could even use my Java SDK as a reference :  https://github.com/vyshakhbabji/ringcentral-java

I could provide you some code snippets for C# Authentication. Please find it below: 

https://github.com/vyshakhbabji/ringcentral-csharp/blob/develop/RingCentral/platform/Platform.cs
public Response Authorize(string userName, string extension, string password, bool isRemember) {	var body = new Dictionary < string,
string > {
{
"username", userName
}, {
"password", Uri.EscapeUriString(password)
}, {
"extension", extension
}, {
"grant_type", "password"
}, {
"access_token_ttl", AccessTokenTtl
}, {
"refresh_token_ttl", isRemember ? RefreshTokenTtlRemember : RefreshTokenTtl
}
};
var request = new Request(TokenEndpoint, body);
var result = AuthCall(request);
Auth.SetRemember(isRemember);
Auth.SetData(result.GetJson());
_client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Auth.GetAccessToken());
return result;
}
(Edited)
Photo of John Wang

John Wang, Official Rep

  • 5,786 Points 5k badge 2x thumb
The source code for the C# SDK is in the `develop` branch of the GitHub repository available here: https://github.com/ringcentral/ringcentral-csharp/tree/develop

We are finalizing this SDK and will migrate the code in the develop branch to the master branch shortly.
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
I downloaded the sample project from the link you provided me and when I run the code it says "Access Expired". Please advise. Thank you for all your help.
Photo of VB

VB, Official Rep

  • 1,510 Points 1k badge 2x thumb
Can you share the Response Message ? And what is the HTTP status code? 
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
I tried following the tutorial first. https://developer.ringcentral.com/library/tutorials/get-started.html  Cause if I can make it work in the browser I should be able to replicate that in code.

The post is to https://platform.devtest.ringcentral.com/restapi/oauth/token

The response is.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?><errorEntity><error>invalid_grant</error><error_description>Invalid resource owner credentials.</error_description></errorEntity>

I was using 12154223514 as the username. I don't want to put the password here, but it is the same user name and password I use to log in to developer.ringcentral.com.

Should I be using a different username and password? We aren't going to have a user, it will just be running from our server.

Thanks for your help.
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
Here are the headers...


Host: platform.devtest.ringcentral.com
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Authorization: Basic WnZYMG94YVlRbW1JcWVVd3FYWWZBZzo2MVhNblh3N1JaR3ItbXRzZjZLMDh3b2VNbWJ4V25TZ21UZjlCcl9aVWZvZw==
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Content-Length: 60
Cookie: _ga=GA1.2.1582640206.1445977993; RCRoutingInfo=B:JjvG963zMhLp2i9ovcWFNByPb5vRnRQA539tb0pH+XWHl8qMEhGXRFDcYy5wxzWX
Connection: keep-alive
Proxy-Authorization: Negotiate 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
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
Did you follow the documentation for obtaining the access token?

I think you're receiving the "Invalid Grant" and "Invalid Resource Owner Credentials" because you might not be using the proper values or URI in your POST request for the access token.

  1. To use the RingCentral API, an access and refresh token are needed. The simplest way to get an access token needed for production resources is to complete Two-legged Authorization Flow (OAuth 2.0). The required fields are below:

    • ApplicationKey — granted after successful application/developer registration. Required.

    • ApplicationSecret — granted after successful application/developer registration. Required.

    • UserName — main company number of a RingCentral account or direct extension phone number (unformatted, sequence of digits starting with country code). Required.

    • Extension — extension number to log into for the RingCentral account. Required if main company number is provided as a UserName.

    • Password — for the RingCentral account. Required.


  2. Once you have the ApplicationKey and ApplicationSecret for your app (You obtain these raw values from your application definition page available by selecting your application from the list of your defined apps here: https://developers.ringcentral.com/my-account.html#/applications ), you must Base64 encode them to be used in the request for an access/refresh token. A free tool is available at http://www.base64encode.org.

    In C# you can also create a method to encode base64 values:



    public static string Base64Encode(string plainText) {
    var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
    return System.Convert.ToBase64String(plainTextBytes);
    }


  3. Once you have the payload data to obtain an access token, you'll want to create an HTTP POST request to: https://platform.devtest.ringcentral.com/restapi/oauth/token (notice this URI is for your Sandbox environment, for a production environment just remove "devtest." from the URI).



    //Be sure to run "Install-Package Newtonsoft.Json -Version 7.0.1" from your nuget command line.
    //Be sure to run "Install-Package System.Net.Http -Version 4.0.0" from your nuget command line.

    HttpClient client = new HttpClient();

    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", "BASE64 ENCODED APPKEY:APPSECRET");<br>
    FormUrlEncodedContent form = new FormUrlEncodedContent(new Dictionary { { "username", "username" }, { "password", "password" }, { "grant_type": "password" }, { "extension": "extension" } } );

    Task message = client.PostAsync( "https://platform.devtest.ringcentral.com/restapi/oauth/token", form );
    String result = message.Result.Content.ReadAsStringAsync().Result;

    JObject RCAuth = JObject.Parse( result );
    string token = ( string )RCAuth["access_token"]
    string refreshToken = ( string )RCAuth["refresh_token"];
    string tokenExpires = ( string )RCAuth["access_token_expires_in"];
    string refreshTokenExpires = ( string )RCAuth["refresh_token_expires_in"];


  4. That should get you to the point you're able to begin making calls. You will want to use this token until around 80% of the expiration time, then you'll want to use the refresh token to request a new access and refresh token.
Let me know if this doesn't work for you, or if you hit snags.
(Edited)
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
Awesome! Thanks! I am working on other stuff, but I'll get to this sometime soon. I'll probably try it out from home first to rule out any corporate firewall issues. I'll let you know how it goes.
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
What should I be using for extension?
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
Simply put: the extension represents the RingCentral user (as defined by you in your Sandbox account RingCentral Admin panel).

There are many more complex ways to configure an account, but speaking from a developer's perspective (most simply stated) the extension represents the user who is logged into RingCentral (so your integration is able to show information pertinent to that particular user).

Using our Salesforce App as an example, when the person is logged into Salesforce, and they authenticate into the RingCentral Integration...the SFDC App is using the extension that user provides as a way to scope the data returned by the RingCentral API requests for that user.

Does that make sense and help?
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
Here is some tutorial content on setting up users and extensions in RingCentral. This applies to your Sandbox account as well.

http://success.ringcentral.com/RCSupportPortalLearningCenter?LCtabId=settings_0
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
Can I use "101" for the extension? We aren't going to have any users.
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
If that is the extension for the username (phone number) with which you're using to authenticate, yes.

If you're using your sandbox account, you will need to Configure Your Sandbox Account for Development:
Using the (Sandbox) Admin Web Portal to configure your development account:

  1. Go to https://service.devtest.ringcentral.com.

  2. Login with your sandbox account login (main company number) and password.

  3. Configure your sandbox account phone system. If you need help, please see instructions in our Learning Center’s

    http://success.ringcentral.com/RCSupportPortalLearningCenter?LCtabId=settings_21

Your sandbox account is ready to be used on https://platform.devtest.ringcentral.com environment.

The Getting Started Tutorial at https://developers.ringcentral.com/library/tutorials/get-started.htmlwill help you start working with it.

Please remember, that if you are trying to use call logs or any data created within accounts, you will need to create this data in the sandbox account (data in your production account is not accessible from your sandbox account).
Photo of Todd

Todd

  • 230 Points 100 badge 2x thumb
Official Response
Today I finally got the answer my original question. The code snippet below.


    public class Worker
    {
        private static string Base64Encode(string plainText)
        {
            var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
            return System.Convert.ToBase64String(plainTextBytes);
        }

        private string _accessToken;
       
       public async void WaitForAuthToken()
        {
            using (var client = new HttpClient())
            {
                var request = new HttpRequestMessage()
                {
                    RequestUri = new System.Uri($"{Settings.ServerUrl}restapi/oauth/token"),
                    Method = HttpMethod.Post,
                };
                 request.Headers.TryAddWithoutValidation("Content-Type", @"application/x-www-form-urlencoded;charset=UTF-8");
                request.Headers.Add("Authorization", $"Basic {Base64Encode($"{Settings.AppKey}:{Settings.AppSecret}")}"); 
                request.Content = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string, string>("grant_type", "password"),
                new KeyValuePair<string, string>("username", Settings.PhoneNumber),
                new KeyValuePair<string, string>("password", Settings.Password),
                new KeyValuePair<string, string>("extension", Settings.Extension)
            });

                var response = await client.SendAsync(request);
                var responseContent = await response.Content.ReadAsStringAsync();
                var d = (dynamic) Newtonsoft.Json.JsonConvert.DeserializeObject(responseContent);
                _accessToken = d.access_token;
            }
        }
    }




Simple really.
Photo of Benjamin Dean

Benjamin Dean, Alum

  • 8,662 Points 5k badge 2x thumb
Thanks for sharing this Todd...great help.

Love seeing the use of async in there that makes a ton of sense in addition to setting this up as a worker.