{"id":858,"date":"2020-10-12T19:29:32","date_gmt":"2020-10-12T23:29:32","guid":{"rendered":"http:\/\/salzlechner.com\/dev\/?p=858"},"modified":"2020-10-12T19:29:33","modified_gmt":"2020-10-12T23:29:33","slug":"starzen-rest-library-for-dataflex-webapp-authentication","status":"publish","type":"post","link":"http:\/\/salzlechner.com\/dev\/2020\/10\/12\/starzen-rest-library-for-dataflex-webapp-authentication\/","title":{"rendered":"StarZen REST library for DataFlex WebApp \u2013 Authentication"},"content":{"rendered":"<p>[et_pb_section fb_built=&#8221;1&#8243; _builder_version=&#8221;3.26.7&#8243;][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column _builder_version=&#8221;3.26.7&#8243; type=&#8221;4_4&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<p>A very important part of creating REST APIs is authentication.<\/p>\n<p>We need the ability to sedure API endpoints for different callers.<\/p>\n<p>Some endpoints are unsecured and can be called anonymously while most other endpoints will require some form of authentication.<\/p>\n<p>There are several methods for authentication in use for REST services.<\/p>\n<ul>\n<li>BASIC<\/li>\n<li>BEARER<\/li>\n<li>JWT<\/li>\n<li>OATUH<\/li>\n<li>&#8230;<\/li>\n<\/ul>\n<p>in addition to the type of authentication we also want to be able to secure different API routes with different methods and for different API users.<\/p>\n<p>Our REST library implements authentication on a per route basis but also allows definition per controller.<\/p>\n<p>It also allows multiple types of authentication for the same route.\u00a0<\/p>\n<p>One route could have BASIC authentication as well as BEARER authentication at the same time.\u00a0<\/p>\n<p>For example a good practice is to require authentication on the controller which automatically forces all routes of a controller to require authentication.<\/p>\n<p>Then, if a route is added that requires anonymous access we can override the authentication on that route only.<\/p>\n<p>&nbsp;<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column _builder_version=&#8221;3.26.7&#8243; type=&#8221;4_4&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<p>so to start we will create a new API controller as follows<\/p>\n<pre>Object oAuthSampleAPI is a cszWebAPIController\n    \/\/ The psPath property determines the path in the URL for which requests will be handled.\n    Set psPath to \"api\/v1\/authsample\"\n    \/\/ Use psVerbs to filter based on the HTTP Verbs. \n    Set psVerbs to \"*\"<br \/>\n    Procedure ManualGet \n        Integer hoJson\n        Get Create (RefClass(cJsonObject)) to hoJson\n        Send InitializeJsonType of hoJson jsonTypeObject\n\n        Send SetMemberValue to hoJson \"timestamp\" jsonTypeString (ConvertToClient(typeDateTime, CurrentDateTime()))\n        Send SetMemberValue to hoJson \"message\" jsonTypeString \"You can see this message\"\n\n        Send OutputJson hoJson\n        Send Destroy to hoJson\n    End_Procedure\n\n    Send RegisterPath \"GET\" \"\" (RefProc(ManualGet)) \n    Set pbPathScalar to True\n    Set psPathSummary to \"Manual API function\"\nEnd_Object\n<\/pre>\n<p>a very simple controller actually the same as the manual api we built earlier. At this time there is no authentication so we should be able to call the GET method and it will return the HTTP code 200 and the data.<\/p>\n<p>&nbsp;<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column _builder_version=&#8221;3.26.7&#8243; type=&#8221;4_4&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]<\/p>\n<p>to secure our API we can tell the controller that authentication is required by setting the following property<\/p>\n<pre>Set pbAuthRequired to True<\/pre>\n<p>running the API now will produce an error 401 and the controller will no longer return any data.<\/p>\n<p>lets see how we can BASIC authentication that will work for the whole controller<\/p>\n<p>first we need to enable BASIC authentication on the controller<\/p>\n<pre> Send AddAuth \"BASIC\"<\/pre>\n<p>now that BASIC authentication is enabled we need to validate credentials as they are used.<\/p>\n<p>For BASIC authentication we implement the following event<\/p>\n<pre>Function OnValidateAuthBasic String sVerb String sPath tWebAPIPath path String sUser String sPassword Returns Boolean\n    If (sUser=\"mike\" and sPassword=\"austrianthunder\") Begin\n        Function_Return True\n    End\nEnd_Function\n<\/pre>\n<p>what if we have a route in our controller that should allow anonymous access. As mentioned earlier it is always safer to force the full controller to authenticate and then override specific functions.<\/p>\n<p>Lets define a sample route with anonymous access<\/p>\n<pre> Send RegisterPathAuth \"GET\" \"\/anon\" (RefProc(ManualGet)) WEPAPI_AUTHMODE_ANONYMOUS \n Set pbPathScalar to True\n Set psPathSummary to \"Manual API function no auth\"<\/pre>\n<p>this will register the path \/anon with anonymous access.<\/p>\n<p>We can also declare a specific path with a specific type of authentication. For example for BASIC authentication<\/p>\n<pre> Send RegisterPathAuth \"GET\" \"\/basic\" (RefProc(ManualGet)) WEPAPI_AUTHMODE_REQUIRED \"BASIC\"\n Set pbPathScalar to True\n Set psPathSummary to \"Manual API basic auth only\"<\/pre>\n<p>or for both BASIC and BEARER authentication<\/p>\n<pre> \/\/ register path with BASIC and BEARER auth\n Send RegisterPathAuth \"GET\" \"\/bandb\" (RefProc(ManualGet)) WEPAPI_AUTHMODE_REQUIRED \"BASIC\"\n Send AddPathAuth \"BEARER\"\n Set pbPathScalar to True\n Set psPathSummary to \"Manual API basic and bearer auth\"<\/pre>\n<p>in our sample application we also added a simple database table to add users to authenticate the web APIs<\/p>\n<p>the code to validate BASIC authentication looks as follows<\/p>\n<p>Function OnValidateAuthBasic String sVerb String sPath tWebAPIPath path String sUser String sPassword Returns Boolean<br \/>\u00a0 \u00a0 Clear WEBAUTH<br \/>\u00a0 \u00a0 Move &#8220;BASIC&#8221; to WEBAUTH.TYPE<br \/>\u00a0 \u00a0 Move sVerb to WEBAUTH.VERB<br \/>\u00a0 \u00a0 Move path.sPath to WEBAUTH.PATH<br \/>\u00a0 \u00a0 Move sUser to WEBAUTH.TOKEN<br \/>\u00a0 \u00a0 Find EQ WEBAUTH by Index.1<br \/>\u00a0 \u00a0 If (Found) Begin<br \/>\u00a0 \u00a0 \u00a0 \u00a0 If (WEBAUTH.PASSWORD=sPassword) Function_Return True <br \/>\u00a0 \u00a0 End<\/p>\n<p>End_Function<\/p>\n<p>&nbsp;<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][et_pb_row _builder_version=&#8221;3.26.7&#8243;][et_pb_column _builder_version=&#8221;3.26.7&#8243; type=&#8221;4_4&#8243;][et_pb_text _builder_version=&#8221;3.26.7&#8243;]\n\t\t<div class='author-shortcodes'>\n\t\t\t<div class='author-inner'>\n\t\t\t\t<div class='author-image'>\n\t\t\t<img src='http:\/\/salzlechner.com\/dev\/wp-content\/uploads\/sites\/2\/2016\/02\/mike5crop-566174_60x60.jpg' alt='' \/>\n\t\t\t<div class='author-overlay'><\/div>\n\t\t<\/div> \n\t\t<div class='author-info'>\n\t\t\tMichael Salzlechner is the CEO of StarZen Technologies, Inc.<\/p>\n<p>He was part of the Windows Team at Data Access Worldwide that created the DataFlex for Windows Product before joining\u00a0StarZen Technologies. StarZen Technologies provides consulting services as well as custom Application development and third party products<\/p>\n\t\t<\/div>\n\t\t\t<\/div>\n\t\t<\/div>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>A very important part of creating REST APIs is authentication. We need the ability to sedure API endpoints for different callers. Some endpoints are unsecured and can be called anonymously while most other endpoints will require some form of authentication. There are several methods for authentication in use for REST services. BASIC BEARER JWT OATUH [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","ngg_post_thumbnail":0,"footnotes":""},"categories":[6,27],"tags":[],"class_list":["post-858","post","type-post","status-publish","format-standard","hentry","category-dataflex","category-dataflex-webapp"],"_links":{"self":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/858","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/comments?post=858"}],"version-history":[{"count":7,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/858\/revisions"}],"predecessor-version":[{"id":870,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/posts\/858\/revisions\/870"}],"wp:attachment":[{"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/media?parent=858"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/categories?post=858"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/salzlechner.com\/dev\/wp-json\/wp\/v2\/tags?post=858"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}