How to use HTTPAPI for OAuth 2.0 protocol authentication
-
- Site Admin
- Posts: 872
- Joined: Sun Jul 04, 2021 5:12 am
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
So is your question "why are they requiring a redirect_uri?" If so, you are asking the wrong person -- this error is coming from the API, not from me. You have to ask Stamps (or whomever it is that provides the API) why they are sending this error when you've previously discussed not using a redirect URI..
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
Hello Scott/John,
showing log to provider, they realized they have given me wrong information as far as what parameters required to call oauth/token for authorizaion code based call vs refresh_token based call. Here are the parameters and now i am getting access/refresh token. But my rc value after http_Req call is 1, i was expecting 200. Also in the debug log "SetError() #13: HTTP/1.1 200 OK", what this mean?
PostString = '{ "grant_type": "authorization_code", ' +
'"client_id":' + #Qd + %Trim(UEPCID) + #Qd + ',' +
'"client_secret":' + #Qd + %Trim(UEPCSC) + #Qd + ',' +
'"code":' + #Qd + %Trim(#Aut_Code) + #Qd + ',' +
'"redirect_uri":' + #Qd + %Trim(urr) + #Qd + '}';
rc = http_req('POST': urt: *omit : result : *omit : postsstring);
If rc > 199 and rc < 300 ;
Exsr ReadRefTkn;
Else;
ExSr ReadTknError;
EndIf;
DebugLog:
senddoc(): entered
{ "grant_type": "authorization_code", "client_id":"aShxEuP...
recvresp(): entered
HTTP/1.1 200 OK
Date: Fri, 02 Aug 2024 16:42:35 GMT
SetError() #13: HTTP/1.1 200 OK
recvresp(): end with 200
recvdoc parms: chunked 0
header_load_cookies() entered
chunk size = 1017
get_chunk_size returned 1017
calling comm_blockread
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCI
comm_blockread returned 1017
get_chunk_size(): entered
0
chunk size = 0
get_chunk_size returned 0
http_close(): entered
For my next step to make label API:
I have to call https://api.testing.stampsendicia.com/sera/v1/labels, according to documentation, i got to pass following in header
Headers:
Authorization: Bearer [Your Access Token]
Content-Type: application/json
I am doing http_req but do not see how to pass 2 pieces of header information in to http_req?
Note: postdata has body detail jason
rc = http_req( 'POST': url: *omit : result : *omit : postdata);
showing log to provider, they realized they have given me wrong information as far as what parameters required to call oauth/token for authorizaion code based call vs refresh_token based call. Here are the parameters and now i am getting access/refresh token. But my rc value after http_Req call is 1, i was expecting 200. Also in the debug log "SetError() #13: HTTP/1.1 200 OK", what this mean?
PostString = '{ "grant_type": "authorization_code", ' +
'"client_id":' + #Qd + %Trim(UEPCID) + #Qd + ',' +
'"client_secret":' + #Qd + %Trim(UEPCSC) + #Qd + ',' +
'"code":' + #Qd + %Trim(#Aut_Code) + #Qd + ',' +
'"redirect_uri":' + #Qd + %Trim(urr) + #Qd + '}';
rc = http_req('POST': urt: *omit : result : *omit : postsstring);
If rc > 199 and rc < 300 ;
Exsr ReadRefTkn;
Else;
ExSr ReadTknError;
EndIf;
DebugLog:
senddoc(): entered
{ "grant_type": "authorization_code", "client_id":"aShxEuP...
recvresp(): entered
HTTP/1.1 200 OK
Date: Fri, 02 Aug 2024 16:42:35 GMT
SetError() #13: HTTP/1.1 200 OK
recvresp(): end with 200
recvdoc parms: chunked 0
header_load_cookies() entered
chunk size = 1017
get_chunk_size returned 1017
calling comm_blockread
{"access_token":"eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCI
comm_blockread returned 1017
get_chunk_size(): entered
0
chunk size = 0
get_chunk_size returned 0
http_close(): entered
For my next step to make label API:
I have to call https://api.testing.stampsendicia.com/sera/v1/labels, according to documentation, i got to pass following in header
Headers:
Authorization: Bearer [Your Access Token]
Content-Type: application/json
I am doing http_req but do not see how to pass 2 pieces of header information in to http_req?
Note: postdata has body detail jason
rc = http_req( 'POST': url: *omit : result : *omit : postdata);
-
- Site Admin
- Posts: 872
- Joined: Sun Jul 04, 2021 5:12 am
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
This means the request was successful. http_req() always returns 1 if it was successful. 200 is the HTTP status code for success.sbehera00 wrote: ↑Fri Aug 02, 2024 6:00 pm showing log to provider, they realized they have given me wrong information as far as what parameters required to call oauth/token for authorizaion code based call vs refresh_token based call. Here are the parameters and now i am getting access/refresh token. But my rc value after http_Req call is 1, i was expecting 200. Also in the debug log "SetError() #13: HTTP/1.1 200 OK", what this mean?
This will work fine as long as there are no special characters in your data that need to be escaped, and the document is always run from a system with the same CCSID that it was compiled on.sbehera00 wrote: ↑Fri Aug 02, 2024 6:00 pm PostString = '{ "grant_type": "authorization_code", ' +
'"client_id":' + #Qd + %Trim(UEPCID) + #Qd + ',' +
'"client_secret":' + #Qd + %Trim(UEPCSC) + #Qd + ',' +
'"code":' + #Qd + %Trim(#Aut_Code) + #Qd + ',' +
'"redirect_uri":' + #Qd + %Trim(urr) + #Qd + '}';
rc = http_req('POST': urt: *omit : result : *omit : postsstring);
If rc > 199 and rc < 300 ;
Exsr ReadRefTkn;
Else;
ExSr ReadTknError;
EndIf;
However, you should consider using a JSON tool will work in all situations. I provide the open source YAJL (which can be used with the DATA-GEN and DATA-INTO opcodes) as a way to create and/or interpret JSON documents for free https://www.scottklement.com/yajl/
IBM also provides one in the SQL environment that can be called from RPG. I personally don't like the SQL one, but it works.
Content-type is a required header, as such it is a parameter to http_req. You cannot send data (legitmately) without also sending a content-type, so HTTPAPI will always add it for you. If you don't pass it (which seems to be the case, above) httpapi will use the default value in CONFIG_H (which I believe is text/xml)sbehera00 wrote: ↑Fri Aug 02, 2024 6:00 pm For my next step to make label API:
I have to call https://api.testing.stampsendicia.com/sera/v1/labels, according to documentation, i got to pass following in header
Headers:
Authorization: Bearer [Your Access Token]
Content-Type: application/json
I am doing http_req but do not see how to pass 2 pieces of header information in to http_req?
Authorization in HTTPAPI is handled by calling a routine named HTTP_setAuth. This must be called prior to the request.
Code: Select all
HTTP_setAuth( HTTP_AUTH_BEARER: '': YourAccessToken);
rc = http_req( 'POST': url: *omit : result : *omit : postdata: 'application/json');
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
Hello Scott,
thank you very much for your help. All authorization part is working fine now only the issue is for label API call, I need to pass Idempotency-Key in header. Question is
1. How to generate Idempotency-Key in as400 ?
2. How to pass Idempotency-Key in the header ?
note: from previous conversation, i am using YAJL tool to read (yajl_string_load_tree, yajl_object_find ) data returned from http_req but not while sending the request. Not sure what is use/difference/advantages of yajl_string vs DATA-GEN and DATA-INTO opcodes.
Debug log:
recvdoc(): Receiving 181 bytes.
{"error_reference_id":"0bba9a9a-4d90-4580-9d94-d95c46299c47","errors":[{"error_code":"800002","error_message":"Idempotency-Key header not found for enforced idempotent endpoint."}]}
SetError() #13: HTTP/1.1 400 Bad Request
http_close(): entered
thank you very much for your help. All authorization part is working fine now only the issue is for label API call, I need to pass Idempotency-Key in header. Question is
1. How to generate Idempotency-Key in as400 ?
2. How to pass Idempotency-Key in the header ?
note: from previous conversation, i am using YAJL tool to read (yajl_string_load_tree, yajl_object_find ) data returned from http_req but not while sending the request. Not sure what is use/difference/advantages of yajl_string vs DATA-GEN and DATA-INTO opcodes.
Debug log:
recvdoc(): Receiving 181 bytes.
{"error_reference_id":"0bba9a9a-4d90-4580-9d94-d95c46299c47","errors":[{"error_code":"800002","error_message":"Idempotency-Key header not found for enforced idempotent endpoint."}]}
SetError() #13: HTTP/1.1 400 Bad Request
http_close(): entered
-
- Site Admin
- Posts: 872
- Joined: Sun Jul 04, 2021 5:12 am
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
Idempotency Key is only used by a few APIs, it is not a common requirement. The 3 or so APIs I've seen it used in all generate it completely differently, so I can't say "generate it with X", because you have to know the specific API and what its requirement is.sbehera00 wrote: ↑Tue Aug 06, 2024 7:50 pm thank you very much for your help. All authorization part is working fine now only the issue is for label API call, I need to pass Idempotency-Key in header. Question is
1. How to generate Idempotency-Key in as400 ?
2. How to pass Idempotency-Key in the header ?
Once you've generated your Idempotency Key, you can add the header using the HTTP_POINT_ADDL_HDR xproc. (Like any other custom header.)
The YAJL subprocedures are more versatile and allow for the entire JSON specification.sbehera00 wrote: ↑Tue Aug 06, 2024 7:50 pm note: from previous conversation, i am using YAJL tool to read (yajl_string_load_tree, yajl_object_find ) data returned from http_req but not while sending the request. Not sure what is use/difference/advantages of yajl_string vs DATA-GEN and DATA-INTO opcodes.
DATA-INTO is somewhat easier to code and understand, but doesn't support 100% of the options of JSON.
DATA-GEN generates JSON... so it's like the yajl_genOpen, yajl_addChar, etc routines.
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
Hello Scott,
here is what provider documentation says
"Idempotency-keys must be a randomly-generated version-4 UUID. Most programming languages support generating random UUIDs out-of-the-box. If an invalid Idempotency-key is included with an request, an error will be returned."
If you can provode some help on how to generate this?
To proceed testing with label API, i got one time key from online and hardcoded to my code. When i run through debug, do see it waits for 20-30 second at the label API call then times out with error "SetError() #44: CommTCP_read: Socket has been shut down.".
I am thinking i may be passing Idempotency-key as additional header info incorrectly. Do not know how exactly to use xproc to pass additional info. Attaching my code and log, if you can help, please?
Code:
// Retrieve access token
rc = http_req('POST': urt: *omit : result : *omit : poststring);
// Set Authority
HTTP_setAuth( HTTP_AUTH_BEARER: '': #Acc_Token);
HTTP_XPROC( HTTP_POINT_ADDL_HEADER: %paddr(AddHeaders));
// Call label API
rc = http_req( 'POST': url: *omit : result : *omit : postdata :
'application/json');
........
P AddHeaders B
D AddHeaders PI
D addHdr 500A varying
/free
// Got the Idemp key from online for one time use until figured out how to generate in RPG
#Idemp_Code = '89b70a96-f5ff-4b7b-9172-259add9b53b6';
addHdr = #Qd + %Trim(#Idemp_Code) + #Qd;
/end-free
P E
Debug Log:
senddoc(): entered
{ "grant_type": "refresh_token", "client_id":"CID","client_secret":"CS","refresh_token":"RT"}
recvresp(): entered
HTTP/1.1 200 OK
chunk size = 953
get_chunk_size returned 953
calling comm_blockread
{"access_token":"RAT","scope":"offline_access","expires_in":900,"token_type":"Bearer"}
comm_blockread returned 953
chunk size = 0
get_chunk_size returned 0
http_close(): entered
HTTPAPI Ver 1.43 released 2021-04-19
NTLM Ver 1.4.0 released 2014-12-22
OS/400 Ver V7R3M0
http_setauth(): entered
POST /sera/v1/labels HTTP/1.1
Host: api.testing.stampsendicia.com
User-Agent: http-api/1.43
Content-Type: application/json
Accept: application/json
Content-Length: 879
Authorization: Bearer
senddoc(): entered
{ "from_address" : { "company_name" :
recvresp(): entered
SetError() #44: CommTCP_read: Socket has been shut down.
recvresp(): end with err
http_close(): entered
here is what provider documentation says
"Idempotency-keys must be a randomly-generated version-4 UUID. Most programming languages support generating random UUIDs out-of-the-box. If an invalid Idempotency-key is included with an request, an error will be returned."
If you can provode some help on how to generate this?
To proceed testing with label API, i got one time key from online and hardcoded to my code. When i run through debug, do see it waits for 20-30 second at the label API call then times out with error "SetError() #44: CommTCP_read: Socket has been shut down.".
I am thinking i may be passing Idempotency-key as additional header info incorrectly. Do not know how exactly to use xproc to pass additional info. Attaching my code and log, if you can help, please?
Code:
// Retrieve access token
rc = http_req('POST': urt: *omit : result : *omit : poststring);
// Set Authority
HTTP_setAuth( HTTP_AUTH_BEARER: '': #Acc_Token);
HTTP_XPROC( HTTP_POINT_ADDL_HEADER: %paddr(AddHeaders));
// Call label API
rc = http_req( 'POST': url: *omit : result : *omit : postdata :
'application/json');
........
P AddHeaders B
D AddHeaders PI
D addHdr 500A varying
/free
// Got the Idemp key from online for one time use until figured out how to generate in RPG
#Idemp_Code = '89b70a96-f5ff-4b7b-9172-259add9b53b6';
addHdr = #Qd + %Trim(#Idemp_Code) + #Qd;
/end-free
P E
Debug Log:
senddoc(): entered
{ "grant_type": "refresh_token", "client_id":"CID","client_secret":"CS","refresh_token":"RT"}
recvresp(): entered
HTTP/1.1 200 OK
chunk size = 953
get_chunk_size returned 953
calling comm_blockread
{"access_token":"RAT","scope":"offline_access","expires_in":900,"token_type":"Bearer"}
comm_blockread returned 953
chunk size = 0
get_chunk_size returned 0
http_close(): entered
HTTPAPI Ver 1.43 released 2021-04-19
NTLM Ver 1.4.0 released 2014-12-22
OS/400 Ver V7R3M0
http_setauth(): entered
POST /sera/v1/labels HTTP/1.1
Host: api.testing.stampsendicia.com
User-Agent: http-api/1.43
Content-Type: application/json
Accept: application/json
Content-Length: 879
Authorization: Bearer
senddoc(): entered
{ "from_address" : { "company_name" :
recvresp(): entered
SetError() #44: CommTCP_read: Socket has been shut down.
recvresp(): end with err
http_close(): entered
-
- Site Admin
- Posts: 872
- Joined: Sun Jul 04, 2021 5:12 am
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
- That's not a valid HTTP header. When you use the additional headers xproc, you need to code correctly for the HTTP protocol. HTTPAPI is allowing you to insert anything you want, it's your responsibility to know how to do it correctly for the protocol. It's very powerful, but somewhat dangerous.
- In this case, you're not providing the header name, separator or the CRLF that terminates the header.
- I have no idea what #Qd is... but I doubt it belongs here
- Ugh! fixed format!
Code: Select all
D*ame+++++++++++ETDsFrom+++To/L+++IDc.Keywords+++++++++++++++++++++++++
P AddHeaders B
D AddHeaders PI
D addHdr 32767A varying
/free
// Got the Idemp key from online for one time use until figured out how to generate in RPG
#Idemp_Code = '89b70a96-f5ff-4b7b-9172-259add9b53b6';
addHdr = 'Idempotency-Key: ' + %Trim(#Idemp_Code) + x'0d25';
/end-free
P E
Re: How to use HTTPAPI for OAuth 2.0 protocol authentication
Hello Scott,
did correct as you mentioned, all working fine now.
Thank you very much for your help...
did correct as you mentioned, all working fine now.
Thank you very much for your help...