Query on OAuth and Authentication Token for Webservice API as a provider
Posted: Tue May 06, 2025 4:33 pm
Hello,
Created a webservice API as an provider using Scott's YAJL services. This http url webservice API was tested in PostMan using Basic Auth (user/password). This works fine locally. This endpoint/url will be provided to Vendor to issue a "Post" API which will place the JSON file in AS400 IFS folder and processed further by RPGLE program.
For implementing this, Vendor has mandated two things - OAuth to be performed using a Certificate generated by us, which will be valid for at least one year. Also provide an additional endpoint at which Vendor can retrieve a new authentication token whenever a previous token expires. I need help on how to generate a OAuth and ideas on how to create additional endpoint for authentication token - should it be a separate source code - url webservice that I need to provide that has the Authentication token generator?
Source code included below'
Created a webservice API as an provider using Scott's YAJL services. This http url webservice API was tested in PostMan using Basic Auth (user/password). This works fine locally. This endpoint/url will be provided to Vendor to issue a "Post" API which will place the JSON file in AS400 IFS folder and processed further by RPGLE program.
For implementing this, Vendor has mandated two things - OAuth to be performed using a Certificate generated by us, which will be valid for at least one year. Also provide an additional endpoint at which Vendor can retrieve a new authentication token whenever a previous token expires. I need help on how to generate a OAuth and ideas on how to create additional endpoint for authentication token - should it be a separate source code - url webservice that I need to provide that has the Authentication token generator?
Source code included below'
Code: Select all
ctl-opt
Main(GETDSTRCMP)
pgminfo(*PCML:*MODULE:*DCLCASE)
option(*srcstmt:*nodebugio:*noshowcpy)
decedit('0.')
bnddir('YAJL':'QC2LE')
// debug
dcl-f QPRINT printer(132) usropn;
dcl-ds line len(132) inz qualified;
PrintString char(132);
end-ds;
dcl-s method varchar(10);
dcl-s request char(500);
dcl-s env pointer;
dcl-s errMsg varchar(500) inz('Error occurred during processing');
dcl-s webservice varchar(500);
dcl-s debug char(1);
// include the YAJL magic (this srcmbr lives in YAJL/QRPGLESRC by default)
/copy qcpysrc,yajlproc
// declare a data structure that is used to store the SUCCESS/FAIL status and
// the ERRORMSG value. This template is referenced through this program.
dcl-ds rtnCode_Template qualified template;
success ind inz(*off);
errorMsg varchar(500) inz('');
end-ds;
// Global Data Structure to webservice return codes
dcl-ds ds_RtnCode likeds(rtnCode_Template) inz(*likeds);
dcl-ds psds PSDS qualified;
program char(10) pos(1);
procedureName *PROC;
statusCode *STATUS;
prvStatus zoned(5) pos(16);
srcListLineNum char(8) pos(21);
routineName *ROUTINE;
nbrPassedParms *PARMS;
exceptionType char(3) pos(40);
exceptionNumber char(4) pos(43);
pgmLib char(10) pos(81);
ExceptionData char(80) pos(91);
messageText char(80) pos(91);
ExceptionId char(4) pos(171);
date char(8) pos(191);
year zoned(2) pos(199);
lastFileUsed char(8) pos(201);
fileErrorInfo char(35) pos(209);
rpgFileRoutine char(6) pos(214);
rpgStatement char(6) pos(214);
fileRecordFormat char(8) pos(236);
jobUserNumber char(26) pos(244);
job char(10) pos(244);
jobName char(10) pos(244);
User char(10) pos(254);
jobUser char(10) pos(254);
number zoned(6) pos(264);
jobnumber zoned(6) pos(264);
jobnumberalpha char(6) pos(264);
jobDate zoned(6) pos(270);
runDate zoned(6) pos(276);
runTime zoned(6) pos(282);
runtimeHour char(2) pos(282);
runtimeMinute char(2) pos(284);
runtimeSecond char(2) pos(286);
createDate char(6) pos(288);
createTime char(6) pos(294);
compilerLevel char(4) pos(300);
srcFile char(10) pos(304);
srcLib char(10) pos(314);
srcMbr char(10) pos(324);
currentPgmProc char(10) pos(334);
currentModule char(10) pos(344);
currentUser char(10) pos(358);
systemName char(8) pos(396);
end-ds;
//-- GETDSTRCMP - Process the incoming webservice JSON payload
//-- If a POST was requested (write) then read JSON payload and save to the IFS location
//-- returns *ON if successful, *OFF otherwise
dcl-proc GETDSTRCMP;
dcl-pi GETDSTRCMP end-pi;
monitor;
// Set SQL option, mainly to force cursor to close at endmodule
exec sql
set option naming=*sys,
commit=*none,
usrprf=*user,
dynusrprf=*user,
datfmt=*iso,
closqlcsr=*endmod;
// Initialize program variables
init();
// Now process the incoming method - only Post
select;
when method='POST';
methodPOST(ds_RtnCode);
other;
ds_RtnCode.errorMsg='* Fail - method('+method+') is not supported';
endsl;
if debug <> '';
line.printstring='Final:'+ds_RtnCode.errorMsg;
write QPRINT line;
close qprint;
endif;
//Send the JSON response document
sendBasicResponse(ds_RtnCode);
return;
on-error ;
dsply ('** ENDED ABNORMALLY ** ');
endmon ;
end-proc;
//-- methodPOST() : If a POST was requested (write) then read JSON
//-- payload and save to the IFS location
dcl-proc methodPOST;
dcl-pi *n ind;
ds_methodPOST likeds(rtnCode_Template);
end-pi;
dcl-s docNode like(yajl_val);
dcl-s errMsg varchar(500);
dcl-s load_ifs varchar(500);
load_ifs='/BG/DistroComplete/DC'+
%char(%timestamp:*iso0)+'-POST.json';
// get the JSON document loaded into memory
// **AND** save the payload direct to the IFS location
docNode=yajl_stdin_load_tree (*on: errMsg : load_ifs);
if (docNode=*NULL) or ((errMsg) <> '');
ds_methodPOST.success=*off;
ds_methodPOST.errorMsg='* Webservice('+%trim(psds.program)+
') failed with error: '+errMsg;
else;
ds_methodPOST.success=*on;
ds_methodPOST.errorMsg='Webservice('+%trim(psds.program)+
') Success. Json successfully stored at:'+
payload_ifs;
//Process the json to application files
endif;
yajl_tree_free(docNode);
return ds_methodPOST.success;
end-proc;
//-- init() : program Initilisation
dcl-proc init;
dcl-pi *n ind end-pi;
// This procedure will return the webservice METHOD
dcl-pr getenv pointer extproc('getenv');
*n pointer value options(*string:*trim);
end-pr;
clear ds_RtnCode;
// if the DEBUG=Y parm has come in from the webserver start the debug
// print and store a more detailed version of variable 'webserver'
if debug <> '';
open qprint;
webservice= %char(psds.jobNumber);
write QPRINT line;
endif;
// Retrieve the HTTP method - Default to GET if not provided
env = getenv('REQUEST_METHOD');
if env <> *null;
method=%str(env);
else;
method='GET';
endif;
return *On;
end-proc;
//-- sendBasicResponse() : Send the Basic JSON response to the calling
dcl-proc sendBasicResponse;
dcl-pi *n ind;
ds_sendBasicResponse likeds(rtnCode_Template) const;
end-pi;
yajl_genOpen(*on);
yajl_beginObj();
yajl_addBool('success': ds_sendBasicResponse.success);
yajl_addChar('errorMsg': ds_sendBasicResponse.errorMsg);
if debug <> '';
yajl_addChar('DEBUG': webservice);
else;
yajl_addChar('DEBUG': '');
endif;
yajl_endObj();
errMsg=ds_sendBasicResponse.errorMsg;
if ds_sendBasicResponse.success;
yajl_writeStdout(200: errMsg);
else;
yajl_writeStdout(500: errMsg);
endif;
yajl_genClose();
return ds_sendBasicResponse.success;
end-proc;
//-- sendDataResponse() : Send the Basic JSON response to the calling
dcl-proc sendDataResponse;
dcl-pi *n ind;
sendDataResponse likeds(rtnCode_Template) const;
end-pi;
yajl_genOpen(*on);
yajl_beginObj();
yajl_beginArray(%trim(psds.program));
yajl_beginObj();
yajl_addBool('success': sendDataResponse.success);
yajl_addChar('errorMsg': sendDataResponse.errorMsg);
yajl_endObj();
yajl_endArray();
yajl_endObj();
errMsg=sendDataResponse.errorMsg;
if sendDataResponse.success;
yajl_writeStdout(200: errMsg);
else;
yajl_writeStdout(500: errMsg);
endif;
yajl_genClose();
return sendDataResponse.success;
end-proc;