Skip to main content

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.



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.


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.




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.


Reply