BookmarkSubscribeRSS Feed
☑ This topic is solved. Need further help from the community? Please sign in and ask a new question.
Hessner
Fluorite | Level 6

Hi,

 

I have skimmed through most articles on PROC HTTP and have been trying to get this work for days now but without success.

 

I am using SAS 9.4 M7.

 

I need access token from a server where I have username and password. When I use Postman for this, it works without any problems:

https://www.dropbox.com/s/2jv7wdy4tcqzrkc/Postman.jpg?dl=0

 

It should be a simple matter of transferring the commands from Postman into SAS but nothing works for me. I must be missing something simple in the PROC HTTP syntax.

 

Here is an example of what I have tried:

 

code 1.jpg

 

Another example:

 

code 2.jpg

Here is a spec for the API:

https://www.dropbox.com/s/l36f1ij2gx5j2iv/API%20spec.jpg?dl=0

 

I will be extremely grateful for any help with this issue.

 

Thanks.

1 ACCEPTED SOLUTION

Accepted Solutions
Hessner
Fluorite | Level 6

Here is the final, elegant solution that Chris did for me. It works like a charm.

filename resp temp;

/* must include content-type/CT= option */
proc http 
 url="https://serviceaddress/oauth/access_token"
 in='grant_type=client_credentials&client_id=XXXXXXXX&client_secret=YYYYYYYY' 
 ct="application/x-www-form-urlencoded"
 out=resp
 method='POST'
;
run;

%put &=SYS_PROCHTTP_STATUS_CODE;
data _null_;
 rc=jsonpp('resp','log');
run;

libname auth json fileref=resp;
data _null_;
 set auth.root;
 call symputx('token',access_token);
run;

%put &=token;

filename bldgs temp;
proc http 
 /* increase the number of records coming back to 1000*/
 url="https://serviceaddress/api/buildings?number=1000"
 method='GET'
 ct='application/json'
 out=bldgs;
 headers "Authorization" = "Bearer &token.";
 ;
run;
%put &=SYS_PROCHTTP_STATUS_CODE;
 
libname bldg json fileref=bldgs;

data bldgs;
 set bldg.data;
 finYear = input(financialYearStart,yymmdd10.);
 format finYear date9.;
run;

proc means data=bldgs;
 var managementFee;
 class finYear;
 format finYear year.;
run;

This API implementation has been quite unforgiving, meaning that everything in the code had to be just right for it to work. Moreover, the error messages were not helpful, it would send the generic 500 server error for every wrong attempt.

 

Many thanks for your help Chris!

View solution in original post

4 REPLIES 4
ChrisHemedinger
Community Manager

I do this all of the time from a variety of services. One difference from your Postman screenshot and your SAS code is that you are putting data on the URL (SAS) vs in the body (Postman). This is okay, but you want to make sure you're comparing the two equally.

 

proc http
 url="https://serviceaddress/oauth/access_token" method='POST'
 out=out
 in="grant_type=client_credentials&client_id=XXXXX&client_secret=XXXXX&scope=SCOPES";
 headerout=hdrs;
run;

If you take your working example in Postman and view its code (cURL version) and reply with that here (redacting any secrets), then we can help more.

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Hessner
Fluorite | Level 6

Hi Chris,

 

Thanks for your amazingly swift reply.

 

I tried your code. I tried both, with and without SCOPE at the end. It feels like it's almost about to work but I am still getting 400 Bad request.

 

With client_id=123456.XXXXXXXX and client_secret=YYYYYYYYYYY, this is what gets stored in the 'Pout' file:

{"code":101,"title":"UnsupportedGrantType","details":"Grant type not supported: client_credentials123456.XXXXXXXX=123456.XXXXXXXXYYYYYYYYYYY=YYYYYYYYY"}

 

Here is the cURL code:

 

curl --location --request POST 'https:/serviceaddress/oauth/access_token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Cookie: AWSALB=yvNLDYnADjC5+nHmYMiMNGIXOs6GxO0F+YWXSCXlP/judzxJpCNUxWp/2TvIfwGR14xZo+9h/If1zzlh9NHuZWnVaTojJo80UcBFWjbf0TRn1e7P/aOdq17n+OsD; AWSALBCORS=yvNLDYnADjC5+nHmYMiMNGIXOs6GxO0F+YWXSCXlP/judzxJpCNUxWp/2TvIfwGR14xZo+9h/If1zzlh9NHuZWnVaTojJo80UcBFWjbf0TRn1e7P/aOdq17n+OsD; PHPSESSID=b2bed2biifr3s5aij6b9hvbp03; csrftoken=fdd07e60e176fac6731cd81746eac14f3613' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=123456.XXXXXXXX' \
--data-urlencode 'client_secret=YYYYYYYYYYY'

 

Thanks for your help again, much appreciated!

 

ChrisHemedinger
Community Manager

think this is the PROC HTTP equivalent of that command.

 

filename temp out;
filename temp hdrs;

%let data = %sysfunc(urlencode(grant_type=client_credentials%str(&)client_id=123456.XXXXXXXX%str(&)client_secret=YYYYYYYYYYY));
proc http
 url="https://serviceaddress/oauth/access_token" method='POST'
 out=out
 in="&data."
 ct="application/x-www-form-urlencoded"
 headerout=hdrs;
run;

/* report HTTP response code and content */
%put &SYS_PROCHTTP_STATUS_CODE.;
data _null_;
 rc = jsonpp('out','log');
run;

 

Some REST API services are very picky -- you need to specify the content-type (CT= option here) and the data must be URL-encoded just so...even when it doesn't appear on the URL.

 

It's time to register for SAS Innovate! Join your SAS user peers in Las Vegas on April 16-19 2024.
Hessner
Fluorite | Level 6

Here is the final, elegant solution that Chris did for me. It works like a charm.

filename resp temp;

/* must include content-type/CT= option */
proc http 
 url="https://serviceaddress/oauth/access_token"
 in='grant_type=client_credentials&client_id=XXXXXXXX&client_secret=YYYYYYYY' 
 ct="application/x-www-form-urlencoded"
 out=resp
 method='POST'
;
run;

%put &=SYS_PROCHTTP_STATUS_CODE;
data _null_;
 rc=jsonpp('resp','log');
run;

libname auth json fileref=resp;
data _null_;
 set auth.root;
 call symputx('token',access_token);
run;

%put &=token;

filename bldgs temp;
proc http 
 /* increase the number of records coming back to 1000*/
 url="https://serviceaddress/api/buildings?number=1000"
 method='GET'
 ct='application/json'
 out=bldgs;
 headers "Authorization" = "Bearer &token.";
 ;
run;
%put &=SYS_PROCHTTP_STATUS_CODE;
 
libname bldg json fileref=bldgs;

data bldgs;
 set bldg.data;
 finYear = input(financialYearStart,yymmdd10.);
 format finYear date9.;
run;

proc means data=bldgs;
 var managementFee;
 class finYear;
 format finYear year.;
run;

This API implementation has been quite unforgiving, meaning that everything in the code had to be just right for it to work. Moreover, the error messages were not helpful, it would send the generic 500 server error for every wrong attempt.

 

Many thanks for your help Chris!

sas-innovate-2024.png

 

Secure your spot at the must-attend AI and analytics event of 2024: SAS Innovate 2024! Get ready for a jam-packed agenda featuring workshops, super demos, breakout sessions, roundtables, inspiring keynotes and incredible networking events.

 

Register by March 1 to snag the Early Bird rate of just $695! Don't miss out on this exclusive offer. 

 

Register now!

How to Concatenate Values

Learn how use the CAT functions in SAS to join values from multiple variables into a single value.

Find more tutorials on the SAS Users YouTube channel.

Click image to register for webinarClick image to register for webinar

Classroom Training Available!

Select SAS Training centers are offering in-person courses. View upcoming courses for:

View all other training opportunities.

Discussion stats
  • 4 replies
  • 4509 views
  • 3 likes
  • 2 in conversation