BookmarkSubscribeRSS Feed
vfarmak
Pyrite | Level 9

Hi Community!

 

I am trying to use the GA4 with SAS Enterprise Guide Proc HTTP.

I have created a test application in Google Analytics and I have enabled the APIs & Service to create an OAuth 2.0 Client Id which is set to Desktop.

I have retrieved the client-id, secret-id, built a URL to authorize my account for this application and run the below code:

%let auth_code=xxx;
%let client_id=yyy;
%let client_secret=zzz;

filename pbody temp;

data _null_;
    file pbody lrecl=32767;
    put "code=&auth_code" @;
    put "&" @;
    put "client_id=&client_id" @;
    put "&" @;
    put "client_secret=&client_secret" @;
    put "&" @;
    put "redirect_uri=urn:ietf:wg:oauth:2.0:oob" @;
    put "&" @;
    put "grant_type=authorization_code";
run;


/* === 3. Send token request === */
filename tokresp temp;
filename hedresp temp;

proc http
    url="https://oauth2.googleapis.com/token"
    method="POST"
    in=pbody
    ct="application/x-www-form-urlencoded"
    out=tokresp
    headerout=hedresp
    headerout_overwrite;
run;

/* === 4. Print Headers === */
data _null_;
    infile hedresp lrecl=32767;
    input;
    put 'HEADER: ' _infile_;
run;

/* === 5. Print Body (raw dump, works for all cases) === */
data _null_;
    infile tokresp recfm=n lrecl=32767;
    input c $char1. @;
    put c $char1. @;
run;

Even though I run the code, I get the following errors:

NOTE: The file PBODY is:
      Filename=E:\SAS\Temp\_TD35700_SASBI_\#LN00105,
      RECFM=V,LRECL=32767,File Size (bytes)=0,
      Last Modified=19Mar2026:17:04:34,
      Create Time=19Mar2026:17:04:34
2                                                          The SAS System                             16:58 Thursday, March 19, 2026


NOTE: 1 record was written to the file PBODY.
      The minimum record length was 269.
      The maximum record length was 269.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      user cpu time       0.00 seconds
      system cpu time     0.00 seconds
      memory              574.18k
      OS Memory           21340.00k
      Timestamp           03/19/2026 05:04:34 PM
      Step Count                        13  Switch Count  0
      

51         
52         
53         /* === 3. Send token request === */
54         filename tokresp temp;
55         filename hedresp temp;
56         
57         proc http
58             url="https://oauth2.googleapis.com/token"
59             method="POST"
60             in=pbody
61             ct="application/x-www-form-urlencoded"
62             out=tokresp
63             headerout=hedresp
64             headerout_overwrite;
65         run;

NOTE: 400 Bad Request
NOTE: PROCEDURE HTTP used (Total process time):
      real time           0.25 seconds
      user cpu time       0.00 seconds
      system cpu time     0.01 seconds
      memory              486.50k
      OS Memory           21596.00k
      Timestamp           03/19/2026 05:04:34 PM
      Step Count                        14  Switch Count  3
      

66         
67         /* === 4. Print Headers === */
68         data _null_;
69             infile hedresp lrecl=32767;
70             input;
71             put 'HEADER: ' _infile_;
72         run;

NOTE: The infile HEDRESP is:
      Filename=E:\SAS\Temp\_TD35700_SASBI_\#LN00107,
      RECFM=V,LRECL=32767,File Size (bytes)=398,
      Last Modified=19Mar2026:17:04:34,
      Create Time=19Mar2026:17:04:34

HEADER: HTTP/1.1 400 Bad Request
HEADER: Content-Type: application/json; charset=utf-8
HEADER: Vary: X-Origin
3                                                          The SAS System                             16:58 Thursday, March 19, 2026

HEADER: Vary: Referer
HEADER: Date: Thu, 19 Mar 2026 15:04:34 GMT
HEADER: Server: scaffolding on HTTPServer2
HEADER: X-XSS-Protection: 0
HEADER: X-Frame-Options: SAMEORIGIN
HEADER: X-Content-Type-Options: nosniff
HEADER: Alt-Svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
HEADER: Accept-Ranges: none
HEADER: Vary: Origin,Accept-Encoding
HEADER: Transfer-Encoding: chunked
HEADER: 
NOTE: 14 records were read from the infile HEDRESP.
      The minimum record length was 0.
      The maximum record length was 55.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      user cpu time       0.01 seconds
      system cpu time     0.00 seconds
      memory              597.40k
      OS Memory           21596.00k
      Timestamp           03/19/2026 05:04:34 PM
      Step Count                        15  Switch Count  0
      

73         
74         /* === 5. Print Body (raw dump, works for all cases) === */
75         data _null_;
76             infile tokresp recfm=n lrecl=32767;
77             input c $char1. @;
78             put c $char1. @;
79         run;

NOTE: UNBUFFERED is the default with RECFM=N.
NOTE: The infile TOKRESP is:
      Filename=E:\SAS\Temp\_TD35700_SASBI_\#LN00106,
      RECFM=N,LRECL=32767,File Size (bytes)=108,
      Last Modified=19Mar2026:17:04:34,
      Create Time=19Mar2026:17:04:34

{  "error": "unsupported_grant_type",  "error_description": "Invalid grant_type: authorization_code\r\n"}
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      user cpu time       0.00 seconds
      system cpu time     0.00 seconds
      memory              589.09k
      OS Memory           21596.00k
      Timestamp           03/19/2026 05:04:34 PM
      Step Count                        16  Switch Count  0
      

80         
81         %LET _CLIENTTASKLABEL=;
82         %LET _CLIENTPROCESSFLOWNAME=;
83         %LET _CLIENTPROJECTPATH=;
84         %LET _CLIENTPROJECTPATHHOST=;
85         %LET _CLIENTPROJECTNAME=;
86         %LET _SASPROGRAMFILE=;
87         %LET _SASPROGRAMFILEHOST=;
4                                                          The SAS System                             16:58 Thursday, March 19, 2026

88         
89         ;*';*";*/;quit;run;
90         ODS _ALL_ CLOSE;
91         
92         
93         QUIT; RUN;
94         

Does anyone from the community have an idea on what went wrong?

Best Regards,

Vasileios

 

#googleanalytics #sas #prochttp #GA4

 

5 REPLIES 5
Stu_SAS
SAS Employee

Hey @vfarmak! Looking at your error code, I notice that it is including CRLF. This means what's being sent is not "authorization_code", but "authorization_code\r\n". 

 

Three options to fix it:

 

1. Fastest: Add recfm=n to your pbody filename statement:

 

filename pbody temp recfm=n;

 

If we write this file out both with and without recfm=n, you'll notice that the file without recfm=n has a carriage return:

norecfm.png

 

Whereas the one with recfm=n does not:

withrecfm.png

 

This prevents sending CRLF within your payload.

 

2. Recommended: Use the form option in PROC HTTP to create name-value pairs and automatically URL encode values:

 

%let auth_code=xxx;
%let client_id=yyy;
%let client_secret=zzz;

filename tokresp temp;
filename hedresp temp;

proc http
    url="https://oauth2.googleapis.com/token"
    method="POST"
    ct="application/x-www-form-urlencoded"
    in=form(
        "code"="&auth_code"
        "client_id"="&client_id"
        "redirect_uri"="urn:ietf:wg:oauth:2.0:oob"
        "grant_type"="authorization_code"
    )
    out=tokresp
    headerout=hedresp
    headerout_overwrite;
run;

 

3. Less-preferred: write your payload to the in option directly with a macro variable, but that gets a bit harder to read, and you'll still need to URL encode anything that needs it.

 

%let auth_code=xxx;
%let client_id=yyy;
%let client_secret=zzz;
%let payload=code=&auth_code%nrstr(&)client_id=&client_id%nrstr(&)redirect_uri=urn:ietf:wg:oauth:2.0:oob%nrstr(&)grant_type=authorization_code;

filename tokresp temp;
filename hedresp temp;

proc http
    url="https://oauth2.googleapis.com/token"
    method="POST"
    in="&payload"
    ct="application/x-www-form-urlencoded"
    out=tokresp
    headerout=hedresp
    headerout_overwrite;
run;

 

vfarmak
Pyrite | Level 9

Thank your @Stu_SAS for your reply.

I tried the 2nd solution and it still gives me HTTP 404:Bad Request.

I have copied and paste the code in a Notepad++ and checked for \r\n characters (basically I confirmed that when I use the let statement in SAS code, no \r\n occurs. Used the solution and produced the below log

1                                                          The SAS System                               10:52 Monday, March 23, 2026

1          ;*';*";*/;quit;run;
2          OPTIONS PAGENO=MIN;
3          %LET _CLIENTTASKLABEL='Retrieve Data 3';
4          %LET _CLIENTPROCESSFLOWNAME='Process Flow';
5          %LET _CLIENTPROJECTPATH='C:\Users\Vasilios.Farmakiotis\OneDrive - Generali Hellas Insurance Company SA\Projects\29.
5        ! Google Analytics Cloud\Snoopy\Google Analytics 4.egp';
6          %LET _CLIENTPROJECTPATHHOST='GHATH7777';
7          %LET _CLIENTPROJECTNAME='Google Analytics 4.egp';
8          %LET _SASPROGRAMFILE='';
9          %LET _SASPROGRAMFILEHOST='';
10         
11         ODS _ALL_ CLOSE;
12         OPTIONS DEV=SVG;
13         GOPTIONS XPIXELS=0 YPIXELS=0;
14         %macro HTML5AccessibleGraphSupported;
15             %if %_SAS_VERCOMP_FV(9,4,4, 0,0,0) >= 0 %then ACCESSIBLE_GRAPH;
16         %mend;
17         FILENAME EGHTML TEMP;
18         ODS HTML5(ID=EGHTML) FILE=EGHTML
19             OPTIONS(BITMAP_MODE='INLINE')
20             %HTML5AccessibleGraphSupported
21             ENCODING='utf-8'
22             STYLE=HTMLBlue
23             NOGTITLE
24             NOGFOOTNOTE
25             GPATH=&sasworklocation
26         ;
NOTE: Writing HTML5(EGHTML) Body file: EGHTML
27         
28         /* Parameteres for proc http */
29         %let auth_code=xxx;
30         %let client_id=yyy;
31         %let client_secret=zzz;
32         
33         /* filenames */
34         filename tokresp temp;
35         filename hedresp temp;
36         
37         proc http
38            url="https://oauth2.googleapis.com/token"
39            method="POST"
40            ct="application/x-www-form-urlencoded"
41            in=form(
42                "code"="&auth_code"
43                "client_id"="&client_id"
44                "redirect_uri"="urn:ietf:wg:oauth:2.0:oob"
45                "grant_type"="authorization_code"
46            )
47            out=tokresp
48            headerout=hedresp
49            headerout_overwrite;
50         run;

NOTE: 400 Bad Request
NOTE: PROCEDURE HTTP used (Total process time):
      real time           0.07 seconds
      user cpu time       0.00 seconds
      system cpu time     0.00 seconds
2                                                          The SAS System                               10:52 Monday, March 23, 2026

      memory              461.37k
      OS Memory           22108.00k
      Timestamp           03/23/2026 11:06:34 AM
      Step Count                        27  Switch Count  0
      

51         
52         %LET _CLIENTTASKLABEL=;
53         %LET _CLIENTPROCESSFLOWNAME=;
54         %LET _CLIENTPROJECTPATH=;
55         %LET _CLIENTPROJECTPATHHOST=;
56         %LET _CLIENTPROJECTNAME=;
57         %LET _SASPROGRAMFILE=;
58         %LET _SASPROGRAMFILEHOST=;
59         
60         ;*';*";*/;quit;run;
61         ODS _ALL_ CLOSE;
62         
63         
64         QUIT; RUN;
65         

I don't know whether it is the credential type or something else (below is the screenshot).Google Configuration.png

 

I will try to create another client ID (not a desktop one) to see if this is the case.

 

Stu_SAS
SAS Employee

Did PROC HTTP write anything to the out file? That can help determine what went wrong in the request.

vfarmak
Pyrite | Level 9

Hi @Stu_SAS 

I am still working on it. I have read that I need to setup a service account (because I will access with proc http the GA4 and ingest the data via the SAS DI Studio / SAS Enterprise Guide - ETL process).

I will ping you when I get some progress. There is a JWT option that needs to be setup with SAS Datastep (9.4M8 installation here).

As soon I get a result, I will let you know.

vfarmak
Pyrite | Level 9

Hi @Stu_SAS 

I had to rework on the following things:

  • Create a service account in GA4 (since this will be used for ETL extraction from SAS)
  • Associate the application in google analytics with the google cloud console service account via service account's email
  • Got the JSON file from GA4 and read in SAS Enterprise Guide (Step 1)
  • I had then to retrieve the access token from google by using python code (I tried with SAS but I couldn't deal with the base encoding 64 URL and got errors while parsing the private key from JSON (there were non legit characters) (Step 2)
  • Last but not least, while I retrieved the access token I used the proc http method and returned results (Step 3)

Below you will see the code in Steps.

/* Step 1 */
filename keyfile "C:\Users\Vasilios.Farmakiotis\Documents\Work\GA4\mobilehub-greece-3e8f337fe225.json";
libname keyjson json fileref=keyfile;

data svc;
    set keyjson.root;
    call symputx("PRIVATE_KEY", private_key);
    call symputx("CLIENT_EMAIL", client_email);
    call symputx("TOKEN_URI", token_uri);
run;
/* Step 2 */
/* Call Python script to generate token */
options noxwait noxsync;

/* Adjust path as needed */
x "python C:\Users\Vasilios.Farmakiotis\Documents\Work\GA4\get_ga4_token.py";

/* Read token from access_token.txt */
filename tok "C:\Users\Vasilios.Farmakiotis\Documents\Work\GA4\access_token.txt";

data _null_;
    infile tok;
    input;
    call symputx("ACCESS_TOKEN", _infile_);
run;

%put &=ACCESS_TOKEN;
/* Step 3 */
filename ga4req temp;
filename ga4resp temp;

/* Request body */
data _null_;
    file ga4req;
    put '{';
    put '  "property": "properties/999999999",';
    put '  "dateRanges": [{"startDate":"7daysAgo","endDate":"today"}],';
    put '  "metrics": [{"name":"activeUsers"}],';
    put '  "dimensions": [{"name":"country"}]';
    put '}';
run;

proc http
    method="POST"
    url="https://analyticsdata.googleapis.com/v1beta/properties/999999999:runReport" in=ga4req out=ga4resp; headers "Authorization" = "Bearer &ACCESS_TOKEN" "Content-Type" = "application/json"; run; libname ga4 json fileref=ga4resp;

I am still working on it. 

I will let you know.

 

 

 

Catch up on SAS Innovate 2026

Dive into keynotes, announcements and breakthroughs on demand.

Explore 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.

SAS Training: Just a Click Away

 Ready to level-up your skills? Choose your own adventure.

Browse our catalog!

Discussion stats
  • 5 replies
  • 524 views
  • 1 like
  • 2 in conversation