Authentication Routine Using JSON

Discussions related to HTTPAPI (An HTTP Client Package for RPG programming.) http://www.scottklement.com/httpapi/
Post Reply
markl
Posts: 6
Joined: Mon Jan 20, 2025 9:16 pm

Authentication Routine Using JSON

Post by markl »

New poster, long time RPG developer but somewhat new to interfacing with web servers. HTTPAPI_VERSION 1.48

I have a simple application that needs to POST a couple static JSON fields (or one JSON field with JSON formatting) to an authentication server which should retrieve a token if authenticated, POST the token with a request to a web service and store the retrieved file in the IFS. We've used HTTPAPI for other applications and I have been able to post to a web service and retrieve a file to the IFS. The issue is the authentication. I'm attempting to use the http_mfd_encoder routines to create a .JSON tempfile but I can't even get this program to compile. I started with code from example7 and I've attempted to modify it for encoding JSON.

(variable definitions same as EXAMPLE7)

tempFile = http_tempfile();

enc = http_mfd_encoder_open( tempFile // line 66
: 'application/json' // line 67
: ContentType
: '<root§httpapi.org>'
: 'application/json' );


if (enc = *NULL);
msg = http_error();
dsply msg;
msg = http_error();
dsply msg;
return;
endif;

http_mfd_encoder_addvar_s(enc:'clientId':'#####')
http_mfd_encoder_addvar_s(enc:'clientSecret':'xxxxxxx');


http_mfd_encoder_close( enc );

rc = http_url_post_stmf('https://xxxx/authenicate'
: tempFile
: '/tmp/http_result.txt'
: HTTP_TIMEOUT
: HTTP_USERAGENT
: ContentType );

if (rc <> 1);
msg = http_error();
dsply msg;
return;
endif;

QCMDEXC('DSPF ''/tmp/http_result.txt''': 200);

unlink('/tmp/http_result.txt');
unlink(tempFile);

The compile lists 3 errors:
*RNF7542 30 3782 006700 Parameter 2 is not valid as a parameter passed by reference.
*RNF5407 20 3781 006600 More parameters were passed in the prototyped call than are allowed.
*RNF5407 20 3781 006600 More parameters were passed in the prototyped call than are allowed.

Is the content type application/json not allowed or are there other errors?
Can the static json code be imbedded in variables as I've done or would it be better to have them stored in a .json file in the IFS?

Any help would be appreciated. If there are examples somewhere that I missed, please point me to them.

Thanks,

Mark
Scott Klement
Site Admin
Posts: 856
Joined: Sun Jul 04, 2021 5:12 am

Re: Authentication Routine Using JSON

Post by Scott Klement »

I'm having a hard time gleaning what you are trying to do.

http_mfd_encoder_open() and the other http_mfd_xxx routines are used to create multipart/form-data documents. It is not capable of creating a JSON document. The second parameter (your line 67) is an OUTPUT parameter, it must contain a variable to contain the content-type that gets calculated by the http_mfd_encoder_open() routine. It cannot be used as input, yet you are hard-coding an input value to it.

There are many ways to create JSON. The open source YAJL tool is the one I use most often.

But.. is your question how to create JSON? this is where I'm lost... are you trying to create JSON, or do you have it already and trying to create a multipart document? What does your expected output look like?
markl
Posts: 6
Joined: Mon Jan 20, 2025 9:16 pm

Re: Authentication Routine Using JSON

Post by markl »

After working with the authentication server web developer, we have determined that sending JSON to his authentication routine is not required. He was able to CURL and URL encode the variables to the server and retrieve the (JSON) security token. This is his CURL and JSON output which I'm attempting to emulate.

curl -X POST -k -H "Content-Type: application/x-www-form-urlencoded" -d "clientId=################" -d "clientSecret=##################################" https://xxxxxxxxxxx.com/api/authenticate
{ "Expires": 300, "AccessToken": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"}

This is now almost identical to the recent OATH2 post and I've used most of the code from that example. I'm now getting an "HTTP/1.1 400 Bad Request" error. We've tried several different variations of the code in an attempt to get it to accept the request.

I tried changing the size of ResultStr to 16384 but I got a compile error: The type and attributes of parameter 4 do not match those of the prototype.

I think this is the relevant portion from the log file:
senddoc(): entered
clientID=#######################&clientSecret=#####################################
recvresp(): entered
HTTP/1.1 400 Bad Request

Code: Select all

H DFTACTGRP(*NO)                                                          
H BNDDIR('HTTPAPI':'YAJL')                                                
                                                                          
 /include yajl_h                                                          
 /copy httpapi_h                                                          
 /copy ifsio_h                                                            
                                                                          
  dcl-s clientid       varchar(4096) inz('#####################');  
  dcl-s clientsecret   varchar(4096) inz(                                 
    '###########################################################');                       
  dcl-s sendData       varchar(16384);                                    
                                                                          
  dcl-ds authResult qualified;                                            
    Expires     int(10);                                                  
    AccessToken varchar(4096);                                            
  end-ds;                                                      
                                                               
dcl-s ResultStr      varchar(16000000);                 
                                                               
d QCMDEXC         pr                  extpgm('QCMDEXC')        
d  command                     200A   const                    
d  length                       15P 5 const                    
                                                               
d msg             s             52A                            
d rc              s             10I 0                          
                                                               
http_debug(*on);                                          
*inlr = *on;                                              
                                                               
//                                                        
//  Build the variables                                   
//                                                        
                                                               
sendData = 'clientID=' + http_urlEncode(clientid)         
   + '&clientSecret=' + http_urlEncode(clientsecret);          
                                                                     
//                                                                   
//  post the credentials to retrieve the token                       
//                                                                   
                                                                     
rc = http_req( 'POST'                                                
             :'https://xxxxxxxxxxxxxx.com/api/authenticate'  
             : *omit                                                 
             : resultStr // String to receive the results            
             : *omit                                                 
             : sendData                                              
             : 'application/x-www-form-urlencoded');                 
                                                                     
//                                                                   
// error checking                                                    
//                                                                   
                                                                     
if (rc <> 1);                      
                  msg = http_error();                      
   dsply msg;                               
   return;                                  
endif;                                      
                                            
msg = resultStr;                         
dsply msg;                               
                                            
data-into authResult %DATA(resultStr)       
                     %PARSER('YAJLINTO');   
                                            
//                                          
//  delete temp files                       
//                       

unlink(resultstr);     
unlink(sendData);      
                            
return;                
Any help would be appreciated.

-markl
emaxt6
Posts: 18
Joined: Mon Jun 05, 2023 4:02 pm

Re: Authentication Routine Using JSON

Post by emaxt6 »

I would check case sensitivity on the parameters first.

Is this code "AI generated"?? You seem to "unlink" string variables??
Scott Klement
Site Admin
Posts: 856
Joined: Sun Jul 04, 2021 5:12 am

Re: Authentication Routine Using JSON

Post by Scott Klement »

markl wrote: Mon Jan 27, 2025 8:46 pm After working with the authentication server web developer, we have determined that sending JSON to his authentication routine is not required. He was able to CURL and URL encode the variables to the server and retrieve the (JSON) security token. This is his CURL and JSON output which I'm attempting to emulate.

curl -X POST -k -H "Content-Type: application/x-www-form-urlencoded" -d "clientId=################" -d "clientSecret=##################################" https://xxxxxxxxxxx.com/api/authenticate
{ "Expires": 300, "AccessToken": "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%"}


so you are posting a form with two variables. That's easy enough.
markl wrote: Mon Jan 27, 2025 8:46 pm This is now almost identical to the recent OATH2 post and I've used most of the code from that example. I'm now getting an "HTTP/1.1 400 Bad Request" error. We've tried several different variations of the code in an attempt to get it to accept the request.
FWIW: It is called OAUTH2 (Open Authentication version 2) not OATH2.
markl wrote: Mon Jan 27, 2025 8:46 pm I tried changing the size of ResultStr to 16384 but I got a compile error: The type and attributes of parameter 4 do not match those of the prototype.
it needs a 4-byte prefix, so VARCHAR(16384:4). You'll get the compile error with a 2-byte prefix.
markl wrote: Mon Jan 27, 2025 8:46 pm I think this is the relevant portion from the log file:
senddoc(): entered
clientID=#######################&clientSecret=#####################################
recvresp(): entered
HTTP/1.1 400 Bad Request
that part looks like the same as the curl example.

Code: Select all

H DFTACTGRP(*NO)                                                          
H BNDDIR('HTTPAPI':'YAJL')                                                
                                                                          
 /include yajl_h                                                          
 /copy httpapi_h                                                          
 /copy ifsio_h                                                            
                                                                          
  dcl-s clientid       varchar(4096) inz('#####################');  
  dcl-s clientsecret   varchar(4096) inz(                                 
    '###########################################################');                       
  dcl-s sendData       varchar(16384);                                    
                                                                          
  dcl-ds authResult qualified;                                            
    Expires     int(10);                                                  
    AccessToken varchar(4096);                                            
  end-ds;                                                      
                                                               
dcl-s ResultStr      varchar(16000000);                 
                                                               
d QCMDEXC         pr                  extpgm('QCMDEXC')        
d  command                     200A   const                    
d  length                       15P 5 const                    
                                                               
d msg             s             52A                            
d rc              s             10I 0                          
                                                               
http_debug(*on);                                          
*inlr = *on;                                              
                                                               
//                                                        
//  Build the variables                                   
//                                                        
                                                               
sendData = 'clientID=' + http_urlEncode(clientid)         
   + '&clientSecret=' + http_urlEncode(clientsecret);          
                                                                     
//                                                                   
//  post the credentials to retrieve the token                       
//                                                                   
                                                                     
rc = http_req( 'POST'                                                
             :'https://xxxxxxxxxxxxxx.com/api/authenticate'  
             : *omit                                                 
             : resultStr // String to receive the results            
             : *omit                                                 
             : sendData                                              
             : 'application/x-www-form-urlencoded');                 
                                                                     
//                                                                   
// error checking                                                    
//                                                                   
                                                                     
if (rc <> 1);                      
                  msg = http_error();                      
   dsply msg;                               
   return;                                  
endif;                                      
                                            
msg = resultStr;                         
dsply msg;                               
                                            
data-into authResult %DATA(resultStr)       
                     %PARSER('YAJLINTO');   
                                            
//                                          
//  delete temp files                       
//                       

unlink(resultstr);     
unlink(sendData);      
                            
return;                
Any help would be appreciated.

-markl
[/quote]


I don't understand the use of unlink() here. FWIW: unlink() is used to delete a file from the IFS. You are passing strings containing data to it, not filenames, so it doesn't make any sense at all.

I don't see anything wrong with what you've posted. But of course, you've removed most of what was in the log file.
Scott Klement
Site Admin
Posts: 856
Joined: Sun Jul 04, 2021 5:12 am

Re: Authentication Routine Using JSON

Post by Scott Klement »

emaxt6 wrote: Mon Feb 03, 2025 1:56 pm I would check case sensitivity on the parameters first.
Ah, that's a good point, he did capitalize clientId differently... good catch.
markl
Posts: 6
Joined: Mon Jan 20, 2025 9:16 pm

Re: Authentication Routine Using JSON

Post by markl »

Thank you for the response.

I did find a difference in case but that didn't make a difference - same error: HTTP/1.1 400 Bad Request

The unlink opcode is new to me. I misinterpreted one of the examples I was reviewing. They're for IFS files. I removed that code.

Any other suggestions?
Scott Klement
Site Admin
Posts: 856
Joined: Sun Jul 04, 2021 5:12 am

Re: Authentication Routine Using JSON

Post by Scott Klement »

I feel like there's more going on here that you haven't shown us. Is that true?

If this is everything, then I'm not sure what to do next other than ask you how I can reproduce it. If I can run both curl and HTTPAPI I can tell what's different.
markl
Posts: 6
Joined: Mon Jan 20, 2025 9:16 pm

Re: Authentication Routine Using JSON

Post by markl »

This issue has been resolved. I had an error in the clientId. The web developer said he was sending a "Bad Request - ClientId/ClientSecret invalid." but I was only seeing "HTTP/1.1 400 Bad Request"

Now that the web service is returning the authorization token, I'm trying to use the YAJL DATA-INTO procedure to parse the JSON data and I'm getting an error with that process. I posted that issue in the YAJL-ILE forum.

Thanks for your help,

markl
Scott Klement
Site Admin
Posts: 856
Joined: Sun Jul 04, 2021 5:12 am

Re: Authentication Routine Using JSON

Post by Scott Klement »

markl wrote: Mon Feb 03, 2025 8:29 pm This issue has been resolved. I had an error in the clientId. The web developer said he was sending a "Bad Request - ClientId/ClientSecret invalid." but I was only seeing "HTTP/1.1 400 Bad Request"
It would be in "resultStr" in your example. And in the log.
Post Reply