Production Ready Macros for SAS Application Developers
mv_getapptoken.sas
Go to the documentation of this file.
1 /**
2  @file
3  @brief Get an App Token and Secret
4  @details When building apps on SAS Viya, an app id and secret is required.
5  This macro will obtain the Consul Token and use that to call the Web Service.
6 
7  more info: https://developer.sas.com/reference/auth/#register
8  and: http://proc-x.com/2019/01/authentication-to-sas-viya-a-couple-of-approaches/
9 
10  The default viyaroot location is /opt/sas/viya/config
11 
12  M3 required due to proc http headers
13 
14  Usage:
15 
16  filename mc url "https://raw.githubusercontent.com/Boemska/macrocore/master/macrocore.sas";
17  %inc mc;
18 
19  %mv_getapptoken(client_id=client,client_secret=secret)
20 
21  @param client_id= The client name
22  @param client_secret= client secret
23  @param groups= List of groups of users who will have access to the app.
24  space seperated. The user will be prompted for each of these when logging in.
25  @param grant_type= valid values are "password" or "authorization_code" (unquoted)
26 
27  @version SAS 9.4M3
28  @author Allan Bowe
29  @source https://github.com/Boemska/macrocore
30 
31  <h4> Dependencies </h4>
32  @li mf_abort.sas
33  @li mf_getuniquefileref.sas
34  @li mf_getuniquelibref.sas
35  @li mf_loc.sas
36 
37 **/
38 
39 %macro mv_getapptoken(client_id=someclient
40  ,client_secret=somesecret
41  ,groups=*
42  ,grant_type=authorization_code
43  );
44 %local consul_token fname1 fname2 fname3 libref access_token;
45 
46 %mf_abort(iftrue=(&grant_type ne authorization_code and &grant_type ne password)
47  ,mac=&sysmacroname
48  ,msg=%str(Invalid value for grant_type: &grant_type)
49 )
50 
51 /* first, get consul token needed to get client id / secret */
52 data _null_;
53  infile "%mf_loc(VIYACONFIG)/etc/SASSecurityCertificateFramework/tokens/consul/default/client.token";
54  input token:$64.;
55  call symputx('consul_token',token);
56 run;
57 
58 /* request the client details */
59 %let fname1=%mf_getuniquefileref();
60 filename &fname1 TEMP;
61 proc http method='POST' out=&fname1
62  url='http://localhost/SASLogon/oauth/clients/consul?callback=false&serviceId=app';
63  headers "X-Consul-Token"="&consul_token";
64 run;
65 
66 %let libref=%mf_getuniquelibref();
67 libname &libref JSON fileref=&fname1;
68 
69 /* extract the token */
70 data _null_;
71  set &libref..root;
72  call symputx('access_token',access_token);
73 run;
74 %put &=access_token;
75 
76 /**
77  * register the new client
78  */
79 %let fname2=%mf_getuniquefileref();
80 filename &fname2 TEMP;
81 data _null_;
82  file &fname2;
83  clientid=quote(trim(symget('client_id')));
84  clientsecret=quote(trim(symget('client_secret')));
85  granttype=quote(trim(symget('grant_type')));
86  groups=symget('groups');
87  length grouplist $1024;
88  do x=1 to countw(groups);
89  grouplist=cats(grouplist,",",quote(scan(groups,x)));
90  end;
91  put '{"client_id":' clientid ',"client_secret":' clientsecret
92  ',"scope": ["openid"' grouplist
93  '],"authorized_grant_types": [' granttype ',"refresh_token"],'
94  '"redirect_uri": "urn:ietf:wg:oauth:2.0:oob"}';
95 run;
96 
97 %let fname3=%mf_getuniquefileref();
98 filename &fname3 TEMP;
99 proc http method='POST' in=&fname2 out=&fname3
100  url='http://localhost/SASLogon/oauth/clients';
101  headers "Content-Type"="application/json"
102  "Authorization"="Bearer &access_token";
103 run;
104 
105 /* show response */
106 data _null_;
107  infile &fname3;
108  input;
109  putlog _infile_;
110 run;
111 
112 %put Please provide the following details to the developer:;
113 %put ;
114 %put CLIENT_ID=&client_id;
115 %put CLIENT_SECRET=&client_secret;
116 %put;
117 %if &grant_type=authorization_code %then %do;
118  %put The developer must also register below and select 'openid' to get the grant code:;
119  %put ;
120  %put &SYSTCPIPHOSTNAME/SASLogon/oauth/authorize?client_id=&client_id%str(&)response_type=code;
121  %put; %put;
122 %end;
123 
124 /* clear refs */
125 filename &fname1 clear;
126 filename &fname2 clear;
127 filename &fname3 clear;
128 libname &libref clear;
129 
130 %mend;