1. Alessandro Malaguti
  2. PowerBuilder
  3. Wednesday, 7 April 2021 20:10 PM UTC

Hello, Using PB 2019 R3

I should get JWT authentication with the following parameters:

"Authorization":"Basic " + base64Urlencode(clientID:clientSecret)

"grant_type":"client_credentials"

"client_id":clientID

"scope":"CamDistributorTenant"

I have tried with the examples povided by this site, but I wasn't able to get the Token code

Instead I succeeded with C# in Visual Studio IDE but I need to take a lot of data from many json requests and in PowerBuilder it's all so much easier to manage this data.

I tried to use:

RESTClient   and   Getjwttoken

where I put all above data in json format like this:

Getjwttoken("https://dryrcmapi-ec1.srv.ygles.com/camapi/v0/authorization/token", '{"Authorization":"Basic YzVlMjVj.....XFk=","grant_type":"client_credentials","client_id":"c5....cdxt","scope":"CamDistributorTenant"}', lToken)

but in lToken variable return "<!DOCTYPE HTML PUBLIC "-//W3C//DTD..... <H1>403 ERROR</H1>...."

then I tried also:

GetOauthtoken with TokenRequest parameter but here I don't know where I have to put the string "Basic " + base64Urlencode(clientID:clientSecret) so dosen't work 

Thanks for a hint

 

Accepted Answer
Daryl Foster Accepted Answer Pending Moderation
  1. Friday, 16 April 2021 08:31 AM UTC
  2. PowerBuilder
  3. # Permalink

Hi Alessandro,

 

I think all you need to do is replace this line:

lo_restclient.SetRequestHeader('Authorization', 'Bearer ' + ls_JWTToken, true)

With these two lines:

lo_restclient.ClearRequestHeaders()
lo_restclient.SetRequestHeader('Authorization', 'Bearer ' + ls_JWTToken)

 

Because you are reusing the lo_restclient for multiple requests, I find it easier to clear out the request headers from the previous request and set them anew.  The true argument for the SetRequestHeader is supposed to replace a header with the same name, but in this case it didn't seem to work.  Regardless, I don't think I've ever replaced a request header, I always like to set them explicitly whenever I can.

 

Comment
  1. Alessandro Malaguti
  2. Friday, 16 April 2021 10:43 AM UTC
your are right!

now works fine

but I thought that

lo_restclient.SetRequestHeaders("Authorization:Bearer " + ls_JWTToken)

it should work becouse it had to replace the previous Header

thank you

regards

alberto trebbi
  1. Helpful
There are no comments made yet.
Alessandro Malaguti Accepted Answer Pending Moderation
  1. Thursday, 15 April 2021 16:11 PM UTC
  2. PowerBuilder
  3. # 1

Hi Daryl,

after obtaining the Token, I'd get the data (list of devices) with this endpoint: 'https://dryrcmapi-ec1.srv.ygles.com/v1/devices/'

but the requests doesn't work, returns:

'{"errors":[{"code":"40130001","field":"","message":"Invalid token."}],"requestId":"1wHoo1N1mSPq0oGY"}'

//
string ls_url = 'https://drycamapi-ec1.srv.ygles.com/camapi/v0/authorization/token'
string ls_clientid = 'c5e25c58-ba3b-44....-3f3395c22980@338cdxt' // here I replaced whith my real client id here
string ls_clientsecret = '*QcAec8N....Lo\\Y' // here I replaced whith my real client secret here
string ls_scope = 'RcmDeviceRead RcmDevice' //to get a 'device list'; this for get the token 'CamDistributorTenant'
string ls_auth = ''
string ls_base64 = ''
string ls_body = ''
integer li_rc
string ls_token

RestClient lo_restclient
CoderObject lo_coderobject

lo_coderobject = create CoderObject
lo_restclient =  create RestClient

ls_auth = ls_clientid + ':' + ls_clientsecret
ls_base64 = lo_coderobject.Base64Encode(Blob(ls_auth, EncodingUTF8!))

// Set the authorization and content headers
lo_restclient.SetRequestHeader('Authorization', 'Basic ' + ls_base64)
lo_restclient.SetRequestHeader('Content-Type', 'application/x-www-form-urlencoded')

// Create the body
ls_body = 'grant_type=client_credentials' 
ls_body += '&client_id=' + ls_clientid
ls_body += '&scope=' + ls_scope

// Get the token with GetJWTToken (this returns the full json of the response which needs to be parsed to get the token)
li_rc = lo_restclient.GetJWTToken(ls_url, ls_body, ls_token)

string ls_JWTToken
JsonPackage ljpk_JWTINF
ljpk_JWTINF = Create JsonPackage
ljpk_JWTINF.Loadstring( ls_token )
If ljpk_JWTINF.ContainsKey( "access_token" ) Then
    ls_JWTToken = ljpk_JWTINF.GetValueString( "access_token" )
End If

//--- endpoint 
ls_url = 'https://dryrcmapi-ec1.srv.ygles.com/v1/devices/'
ls_base64 = lo_coderobject.base64encode( blob(ls_JWTToken, EncodingUTF8!))   //ok x encode

//other attempts
//lo_restclient.SetRequestHeaders("Content-Type:application/x-www-form-urlencoded;charset=UTF-8;~r~nAuthorization:Bearer " + ls_base64)
//lo_restclient.SetRequestHeaders("Content-Type:application/x-www-form-urlencoded;charset=UTF-8;~r~nAuthorization:Bearer " + ls_JWTToken)
//lo_restclient.SetRequestHeaders("Authorization:Bearer " + ls_base64)
//lo_restclient.SetRequestHeaders("Authorization:Bearer " + ls_JWTToken)
//lo_restclient.SetRequestHeader('Authorization', 'Bearer ' + ls_base64, true)

lo_restclient.SetRequestHeader('Authorization', 'Bearer ' + ls_JWTToken, true)

string ls_response
lo_restclient.SendGetRequest(ls_url, ls_response)

string ls_msg 
ls_msg = "Status Code: " + String(lo_restclient.GetResponseStatusCode()) + '~r~n' + &
            "Status Text: " + String(lo_restclient.GetResponseStatusText()) + '~r~n' + &
            "Response Body: " + ls_response

return lo_restclient.GetResponseStatusCode()

instead the same request works in c#.

Attached you can find software of my app If you want to see the code.

Best regards,

alberto trebbi

 

Attachments (2)
Comment
There are no comments made yet.
Alessandro Malaguti Accepted Answer Pending Moderation
  1. Monday, 12 April 2021 16:20 PM UTC
  2. PowerBuilder
  3. # 2

Hi Daryl,

Ok! I can't believe....

work well the first 2 methods that I tried

It was a very bad mistake, I  spent a lot of time .... but I learned a lot of things about this topic

I want to thank you so much for all helpful information

alberto trebbi

Comment
  1. Daryl Foster
  2. Tuesday, 13 April 2021 01:16 AM UTC
No worries mate, glad I could help.
  1. Helpful
There are no comments made yet.
Daryl Foster Accepted Answer Pending Moderation
  1. Sunday, 11 April 2021 07:37 AM UTC
  2. PowerBuilder
  3. # 3

Hi Alessandro,

 

I think I found one big problem with your code.  You seem to be using the wrong URI in your Powerbuilder code.  You are using https://dryrcmapi-ec1.srv.ygles.com/camapi/v0/authorization/token, but in your C# code you are using https://drycamapi-ec1.srv.ygles.com/camapi/v0/authorization/token (drycamapi instead of dryrcmapi).

I managed to get it working in Powerbuilder 2019R2.  Here is some code, you'll need to add your client id and client secret but it should all work.  I haven't added any error checking, so obviously that needs to be added.  I've included the three different methods you could use.  The GetOauthtoken is probably the easiest because it returns the token already parsed.

 

string ls_url = 'https://drycamapi-ec1.srv.ygles.com/camapi/v0/authorization/token'
string ls_clientid = 'c5e25c58....@338cdxt' // Add your real client id here
string ls_clientsecret = '*.....f|x..M|Lo\\Y' // Add your real client secret here
string ls_scope = 'CamDistributorTenant'
string ls_auth = ''
string ls_base64 = ''
string ls_body = ''
integer li_rc
string ls_token

RestClient lo_restclient
CoderObject lo_coderobject

lo_coderobject = create CoderObject
lo_restclient =  create RestClient

ls_auth = ls_clientid + ':' + ls_clientsecret
ls_base64 = lo_coderobject.Base64Encode(Blob(ls_auth, EncodingUTF8!))

// Set the authorization and content headers
lo_restclient.SetRequestHeader('Authorization', 'Basic ' + ls_base64)
lo_restclient.SetRequestHeader('Content-Type', 'application/x-www-form-urlencoded')

// Create the body
ls_body = 'grant_type=client_credentials'
ls_body += '&client_id=' + ls_clientid
ls_body += '&scope=' + ls_scope

// Get the token with GetJWTToken (this returns the full json of the response which needs to be parsed to get the token)
li_rc = lo_restclient.GetJWTToken(ls_url, ls_body, ls_token)

// Using the GetOauthToken function

// Create the token request
TokenRequest lo_tokenrequest

lo_tokenrequest.TokenLocation = ls_url
lo_tokenrequest.Method = 'POST'
lo_tokenrequest.GrantType = 'client_credentials'
lo_tokenrequest.ClientId = ls_clientid
lo_tokenrequest.ClientSecret = ls_clientsecret
lo_tokenrequest.UserName = ''
lo_tokenrequest.PassWord = ''
lo_tokenrequest.Scope = ls_scope

// Get token with GetOauthtoken (this returns the token as a string already parsed from the json response)
li_rc = lo_restclient.GetOauthtoken(lo_tokenrequest, ls_Token)

destroy lo_coderobject
destroy lo_restclient

// Doing it the old fashioned way with the HttpClient

HttpClient lo_httpclient
lo_httpclient = Create HttpClient
integer li_response
string ls_responsebody
string ls_responsestatustext
lo_httpclient.SetRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
lo_httpclient.SetRequestHeader('Authorization', 'Basic ' + ls_base64)

// Set the request for the token
li_rc = lo_httpclient.SendRequest('POST', ls_url, ls_body)

// Read the response manually if we get a 200 OK return code
ls_responsestatustext = lo_httpclient.GetResponseStatusText()
li_response = lo_httpclient.GetResponseStatusCode()
if li_response = 200 then
    // The full token json will be returned so the token will need to be parsed as with GetJWTToken above
    li_rc = lo_httpclient.GetResponseBody(ls_responsebody)
end if

destroy lo_httpclient

Comment
There are no comments made yet.
Alessandro Malaguti Accepted Answer Pending Moderation
  1. Saturday, 10 April 2021 15:54 PM UTC
  2. PowerBuilder
  3. # 4

Hi Daryl,
I fallowed your suggestions, I get it's right to use 64encode instead of 64Urlencode. Despite that my trials returned with the same negative results.
I attach the source  C#  code and the application
You can to run application test3.exe and press the button [jwt Authorization] so you will see the Token returned by the request.
The routine where elaborate the request is 'AuthenticateRequests'.
If you want to compile the source in Visual Studio, you have to install the Newtonsoft package.
Regards and Thank you
Alberto Trebbi

Attachments (2)
Comment
  1. Daryl Foster
  2. Saturday, 10 April 2021 20:59 PM UTC
Thanks Alessandro, I’ll have a look at your code a bit later. Did you try with both getoauthtoken and getjwttoken and they both fail? Did you want to post your Powerbuilder code here as well?
  1. Helpful
There are no comments made yet.
Daryl Foster Accepted Answer Pending Moderation
  1. Friday, 9 April 2021 22:42 PM UTC
  2. PowerBuilder
  3. # 5

Hi Alessandro,

 

I can see a couple of issues.  Firstly it looks like your request needs to be sent as application/x-www-form-urlencoded and not as json, so you'll need to replace your json header

Replace this

SetRequestHeader("Content-Type", "application/json")

with

SetRequestHeader("Content-Type", "application/x-www-form-urlencoded")

 

I also think your base64Urlencode might be wrong.  I think you just need to use base64Encode, so replace this:

k_base64 = co.base64Urlencode( blob(k_clientSecret, EncodingUTF8!))

with

k_base64 = co.base64Encode( blob(k_clientSecret, EncodingUTF8!))

 

For your GetJWTToken example, instead of sending json send the string as key value pairs separated by an ampersand.  You can make it neater but basically in your GetJWTToken call replace this:

'{"grant_type":"client_credentials","client_id":"c5e25c58-ba3b-4464-b308-3f3395c22980@338cdxt","scope":"CamDistributorTenant"}'

with

"grant_type=client_credentials&client_id=c5e25c58-ba3b-4464-b308-3f3395c22980@338cdxt&scope=CamDistributorTenant"

I'm not a 100% sure, but you may need to use coder.UrlEncode on the client_id string.

 

 

 

 

Comment
There are no comments made yet.
Alessandro Malaguti Accepted Answer Pending Moderation
  1. Friday, 9 April 2021 13:31 PM UTC
  2. PowerBuilder
  3. # 6

Hi Zhao,

I tried to follow your kind hints, so I added 'SetRequestHeader':

lrc_P020.SetRequestHeader("Content-Type", "application/json")

lrc_P020.SetRequestHeader("Authorization", "Basic " + base64 with ID SECRET)

but GetOauthtoken returns -1 (general error)

I also tried put the all together into requests like this:

lrc_P020.SetRequestHeaders("Content-Type:application/json;charset=UTF-8~r~nAuthorization:Basic " + k_base64)

but returns the same result: -1

 

String ls_P020_Responsebody,ls_Token,ls_PostData
Long ll_InsertRow
Integer li__P020_SendReturn
Integer li_P020_GetTokenReturn
RestClient lrc_P020
lrc_P020 = Create RestClient



//Sets the token parameters
TokenRequest ltreq_Appeon
ltreq_Appeon.tokenlocation = "https://dryrcmapi-ec1.srv.ygles.com/camapi/v0/authorization/token"
ltreq_Appeon.method = "post"
ltreq_Appeon.GrantType = "client_credentials"
ltreq_Appeon.ClientId = "c5e25c58-ba3b-4464-b308-3f3395c22980@338cdxt"
ltreq_Appeon.ClientSecret = "*QcAe.......Lo\\Y"
ltreq_Appeon.UserName = ""
ltreq_Appeon.PassWord = ""
ltreq_Appeon.scope = "CamDistributorTenant"

lrc_P020.SetRequestHeader("Content-Type", "application/json")

CoderObject co
co = create CoderObject

string k_base64
k_base64 = co.base64Urlencode( blob("*QcAec8Nyf|x6M|Lo\\Y", EncodingUTF8!))
lrc_P020.SetRequestHeader("Authorization", "Basic " + k_base64)

//Gets token via RESTClient
li_P020_GetTokenReturn = lrc_P020.GetOauthtoken( ltreq_Appeon, ls_Token)

instead the other example about the requests with

GetJWTToken

retuns 1 (success) but in the token field (ls_P028_JWTToken, see below)  there is an error code =  403

'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>403 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
This distribution is not configured to allow the HTTP request method that was used for this request. The distribution supports only cachable requests.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: JIlo-n9mqCw5cohiSCbJgCsoQkxx2V-KukWVWgWlQncW7ssP-0okYA==
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>'

this is the source code:

String ls_P028_JWTToken
Integer li_P028_GetJWTTokenReturn
JsonPackage ljpk_JWTINF
ljpk_JWTINF =Create JsonPackage
RestClient lrc_P028
lrc_P028 = Create RestClient

CoderObject co
co = create CoderObject

string k_clientSecret="c5e25c58-ba3b-4464-b308-3f3395c22980@338cdxt:*QcAec.....|Lo\\Y"
string k_base64
k_base64 = co.base64Urlencode( blob(k_clientSecret, EncodingUTF8!))
//Sets the request header
lrc_P028.SetRequestHeaders("Content-Type:application/json;charset=UTF-8~r~nAuthorization:Basic " + k_base64)

//Gets the JWT token. The second parameter provides the value according to the token server request.
li_P028_GetJWTTokenReturn=lrc_P028.GetJWTToken("https://dryrcmapi-ec1.srv.ygles.com/camapi/v0/authorization/token" &
        , '{"grant_type":"client_credentials","client_id":"c5e25c58-ba3b-4464-b308-3f3395c22980@338cdxt","scope":"CamDistributorTenant"}' &
          , ls_P028_JWTToken)

in C# (Visual Studio) I used to do the requsts

       public static void AuthenticateRequests(List<string> scopeList, string clientId, string clientSecret)
        {
            authUrl = ValidateHttpUrl("https://drycamapi-ec1.srv.ygles.com/camapi/", nameof(authUrl));
            httpClient = NotNull(httpClient, nameof(httpClient));

            // Reset authorization header
            httpClient.DefaultRequestHeaders.Authorization = null;

            // DSF OAuth2 Token Resource URI
            var resourceUri = new Uri(authUrl, getAccessTokenRelativeUri);

            // OAuth2 Token Request (application/x-www-form-urlencoded)
            var requestBody = new FormUrlEncodedContent(new Dictionary<string, string>
            {
                [grantTypeKey] = grantTypeValue,
                [clientIdKey] = clientId,
                [scopeKey] = string.Join(" ", scopeList)
            });

            // Set Authorization Header: "Basic Base64({clientId}:{clientSecret})"
            var authToken = Convert.ToBase64String(Encoding.ASCII.GetBytes($"{clientId}:{clientSecret}"));
            httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(basicAuthScheme, authToken);

            try
            {
                // Send request
                var result = httpClient.PostAsync(resourceUri, requestBody).Result;
               .....

I followed the program in debug mode and I saw that the only difference is the last character of the string Base64 converted (one less  '='  at the end), everything else seems the same

It's all vary complicate to understand why it doesn't work...

Comment
There are no comments made yet.
Kai Zhao @Appeon Accepted Answer Pending Moderation
  1. Thursday, 8 April 2021 08:43 AM UTC
  2. PowerBuilder
  3. # 7

Hi Alessandro,

Did you test it on postman? You said you had made it work on C#, may I ask how did you set the relevant parameters?

For Getjwttoken:
As Daryl mentioned, it requires setting a request header for basic authentication, and it also requires setting Content-Type for post json data. Please refer to the article below for more details.
https://docs.appeon.com/pb2019r3/powerscript_reference/ch02s04s288.html

For example:

String ls_P028_JWTToken
Integer li_P028_GetJWTTokenReturn
RestClient lrc_P028
lrc_P028 = Create RestClient

lrc_P028.SetRequestHeader( "Content-Type","application/json" ) //Sets the request header
lrc_P028.SetRequestHeader( "Authorization", "Basic YzVlMjVj.....XFk=")

//Gets the JWT token. The second parameter provides the value according to the token server request.
li_P028_GetJWTTokenReturn=lrc_P028.Getjwttoken("https://dryrcmapi-ec1.srv.ygles.com/camapi/v0/authorization/token", '{"grant_type":"client_credentials","client_id":"c5....cdxt","scope":"CamDistributorTenant"}', ls_P028_JWTToken)

If li_P028_GetJWTTokenReturn = 1 Then

// Getjwttoken("https://dryrcmapi-ec1.srv.ygles.com/camapi/v0/authorization/token", '{"Authorization":"Basic YzVlMjVj.....XFk=","grant_type":"client_credentials","client_id":"c5....cdxt","scope":"CamDistributorTenant"}', lToken)
//Sets the JWT token
messagebox('ls_P028_JWTToken', ls_P028_JWTToken)

Else
//Prints the GetJWTToken error message if any
messagebox('li_P028_GetJWTTokenReturn', li_P028_GetJWTTokenReturn)
End If


For GetOauthtoken:
You can set the request header too, and please specify the GrantType, ClientId, etc for TokenRequest object. You can refer to the article below for the sample script.
https://docs.appeon.com/pb2019r3/powerscript_reference/ch02s04s304.html

Regards,
ZhaoKai

Comment
There are no comments made yet.
Daryl Foster Accepted Answer Pending Moderation
  1. Thursday, 8 April 2021 00:16 AM UTC
  2. PowerBuilder
  3. # 8

Hi Alessandro,

The Authorization line looks like a header for basic authentication.  If it is, it would need to be set before you send the request using the SetRequestHeaders function before calling Getjwttoken.  Have you got any documentation from the authorization service that you can share.  Or better still, can you post your working C# code so we can see how you did that?

 

Comment
There are no comments made yet.
  • Page :
  • 1


There are no replies made for this question yet.
However, you are not allowed to reply to this question.