question

Tammy Wolski avatar image
Tammy Wolski asked Tammy Wolski sent

Request for Token via JasonWebToken auth throws "unauthorized_client" error

I received an "End of Life" email from RingCentral about my "password-based auth" method of getting a token will no longer supported as of next March. I have been using this method of getting a token for a few years, so I know the code I am using is working correctly. The app my users use is a Windows .exe, built using the Lazarus IDE and the programming language FreePascal and the component I use is the Indy HTTP component. There is no SDK involved. To test my POST call, I use Postman along side my .exe just to eliminate the possibility that one or the other is coded/configured wrong. I have set up my POST request in Postman as explained in these instructions and I also changed the code in my own FreePascal app the same way. In both the Postman POST and my own Windows .exe, I get the exact same error message shown here:

{

"error": "unauthorized_client",

"errors": [

{

"errorCode": "OAU-251",

"message": "Unauthorized for this grant type"

}

],

"error_description": "Unauthorized for this grant type"

}

When making my JWT I chose "All apps from your organization"

I downloaded my production creds for this RingCentral production app into a JSON file. Here it is with the private info hidden:

{

"username": "+<HIDDEN>",

"password": "<YOUR ACCOUNT PASSWORD>",

"extension": "201",

"clientId": "<HIDDEN>",

"clientSecret": "<HIDDEN>",

"server": "https://platform.ringcentral.com",

"jwt": {

"RubiDialerJWT": "<HIDDEN>"

}

}

As you can see, the JWT was associated with this app, as I requested.

Here are the screen shots from my Postman attempt:

postman_sets.pdf

Here is the code I'm using in Lazarus:

procedure TfrmDialRC.GetTokenRCJasonWebToken;  
var
  htp: TIdHTTP;
  prms_stm: TStringStream;  s: String;
  tkn_ok: Boolean;
begin
  try
    htp := htpTkn;

    s := 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=' + GV.RingCentral.JWT;
    prms_stm := TStringStream.Create(s);

    if htp.Connected then
      htp.Request.Connection := 'close';
    htp.Request.Clear;

    htp.Request.Accept := 'application/json';
    htp.Request.ContentType := 'application/x-www-form-urlencoded';
    htp.Request.Username := GV.RingCentral.ClientID;
    htp.Request.Password := GV.RingCentral.ClientSecret;
    htp.Request.BasicAuthentication := True;

    htp.Post('https://platform.ringcentral.com/restapi/oauth/token', prms_stm);

  finally
    prms_stm.Free;
    htp.Request.Connection := 'close';
  end;

end;


Is there some other step that I have to take to make this work?

Thanks in advance for your help.



errors
1 |3000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Phong Vu avatar image
Phong Vu answered Tammy Wolski commented

The function you implemented to use the JWT token is totally incorrect. Why do you still specify the user name and password? And I don't know how the Request.BasicAuthentication := True sets the Authorization header.

I don't have sample code in Python. But I have native code in PHP showing how to use the JWT token to exchange for access tokens.

private function authenticate(){
      $url = $_ENV["RC_SERVER_URL"] . "/restapi/oauth/token";
      $basic = $_ENV["RC_CLIENT_ID"] .":". $_ENV["RC_CLIENT_SECRET"];
      $headers = array (
              'Content-Type: application/x-www-form-urlencoded; charset=UTF-8',
              'Accept: application/json',
              'Authorization: Basic '.base64_encode($basic)
            );
      $body = http_build_query(array (
              'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
              'assertion' => $_ENV["JWT_TOKEN"]
            ));
      try {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_POST, TRUE);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_TIMEOUT, 600);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);

        $strResponse = curl_exec($ch);
        $curlErrno = curl_errno($ch);
        if ($curlErrno) {
          throw new Exception($curlErrno);
        } else {
          $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
          curl_close($ch);
          if ($httpCode == 200) {
            $date = new DateTime();
            $jsonObj = json_decode($strResponse);
            $tokensObj = array(
              "tokens" => $jsonObj,
              "timestamp" => $date->getTimestamp()
            );
            // Logged in successfully => Save tokens in session or write to file/database for reuse
            $_SESSION['sessionAccessToken'] =  json_encode($tokensObj, JSON_PRETTY_PRINT);
            return;
          }else{
            throw new Exception($strResponse);
          }
        }
      } catch (Exception $e) {
        throw $e;
      }
    }

You can get the entire project from here and convert the essential code to Python.

1 comment
1 |3000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Tammy Wolski avatar image Tammy Wolski commented ·

Hi Phong. Username and Password in my code, is equivalent to your line:

"RC_CLIENT_ID"] .":". $_ENV["RC_CLIENT_SECRET"];

I have to include that or I get an unknown client error message from the RingCentral server. It must be included. My Postman request is set up the same way, using Basic Auth and client ID (username) and Secret (password). Both Postman and my own Windows .exe result in the same error message: "message": "Unauthorized for this grant type"

I logged into my RingCentral account, located the production APP, went into it's Settings, then changed the "Auth" to "JWT auth flow", and clicked Submit.

I tried doing a RingOut, using Password Flow and the token was granted. (It shouldn't. It's supposed to fail, because the app is now supposed to only allow JST).

I then tried doing a RingOut using JWT as shown in my original post, and a token was not granted, and I got the same error message shown in my original post.

It seems there is something I'm supposed to do with the RingCentral APP to make this work. My request follows the instructions at

https://developers.ringcentral.com/guide/authentication/jwt-flow

Is there someone I can hire for the 20 or 30 minutes it would take to get this figured out? I need someone who can ensure my RingCentral APP and JWT is set up correctly, then, I need them to build a Postman request that works, that requests a token. From Postman, I should be able to translate into Freepascal's HTTP component.



0 Likes 0 ·
Phong Vu avatar image
Phong Vu answered

I recommend you to submit a dev support ticket and someone can have a look at your app settings and help you out with postman API call too.

1 |3000

Up to 8 attachments (including images) can be used with a maximum of 1.0 MiB each and 10.0 MiB total.

Developer sandbox tools

Using the RingCentral Phone for Desktop, you can dial or receive test calls, send and receive test SMS or Fax messages in your sandbox environment.

Download RingCentral Phone for Desktop:

Tip: switch to the "sandbox mode" before logging in the app:

  • On MacOS: press "fn + command + f2" keys
  • On Windows: press "Ctrl + F2" keys