Article
· Feb 12, 2023 6m read

How to add Api-Key validation in REST requests

 

Hi! recently I have to apply api-key validation to a web app with a lot of endpoints and I'm going to tell you how I did it in a centralized way.

 

I'm going to explain you how we can apply in a generic way (or not) api-key validation to all the endpoints of our web app.

 

For this feature I take as a template the class Base.cls of this repository iris-rest-api-template

I modified a bit this class to be able to check api-key security. The idea is that in your features you copy this class in your projects and you extend it for your own implementations.

 

First I did was add a new Parameter to the class called ApiKey and initialised by empty.

Parameter ApiKey = "";

 

Next I modified the OnPreDispatch method. This method is called before process the request and I found the perfect place for add api-key validation.

 

In this method I add a call to a new method that I made called ValidateApiKey.

 

I implemented the ValidateApiKey method like this: 

ClassMethod ValidateApiKey(pUrl As %String, pMethod As %String, ByRef pContinue As %Boolean)  As %Status
{
  SET tSC = $$$OK
  QUIT:(..MustCheckApiKey(pUrl, pMethod)=0) tSC

  IF (..#ApiKey '= "")
    {
      IF ($D(%request.CgiEnvs("HTTP_API_KEY"))'=0)
      {

        SET apiKey=%request.CgiEnvs("HTTP_API_KEY")
        IF (apiKey'=..#ApiKey)
        {
          SET pContinue = 0
          DO ..ReportHttpStatusCode(..#HTTP401UNAUTHORIZED)
          SET tSC=$$$ERROR(..#HTTP401UNAUTHORIZED)
         
        }

      }
    }
  Quit tSC
}

 

In this method first t

In this method, the first thing we do is check whether or not we should validate the apiKey for this request in the MustCheckApiKey method. (We could have a public part of our api that we don't want to protect by apiKey)

I have created this method so that we can override it if we do not want it to apply to all requests since by default it always returns True

ClassMethod MustCheckApiKey(pUrl As %String, pMethod As %String) As %Boolean
{
  Quit 1
}

As you can see, it receives pUrl and pMethod:

pUrl contains the address to which the request is being made, example:

https://www.myApp.com/requestX

 

pMethod contains the request verb: GET, POST, PUT...

 

With this information we could filter to indicate if we want to apply apiKey validation or not.

 

Example: 

Overriding the MustCheckcApiKey method in our extended class we could made that if the request is a Get to Home, do not apply api Key validation

ClassMethod MustCheckApiKey(pUrl As %String, pMethod As %String) As %Boolean
{
  SET res = 1
  If (pUrl="/home")&(pMethod="GET")
  {
      Set res=0
  }

  Quit res
}

 

Next we validate if we have established a value for the ApiKey parameter in our class and if so, then we check that the value of the "api-key" property that will come in the request header matches the value of our ApiKey parameter.

 

(The value must be passed in the header as "api-key" or "api_key" either would do)

 

If so, it will return the information and otherwise it will return an "Unauthorized 401" error.

 

I give you an example of use that I have made on my project cos-url-shortener

This project is an example of how to make a URL shortener with an IRIS docker.

 

For this case, we may want to protect the short URL generation endpoint with an apiKey because we only want our clients to use it, but when a user tries to access a shortened link, it would not make sense to apply an api-key validation.

 

How would it be done?

First we make sure that our class extends the Base.cls class.

Class AQS.urlShortener.UrlREST Extends urlShortener.REST.Base

 

Then we overwrite the value of the ApiKey parameter:

Parameter ApiKey = "myRandomApiKeyValue";

 

Now if we do NOT want api-key security to be applied to all endpoints, we overwrite the MustCheckApiKey method, in my case it coincides that the GET requests are public and the POST requests are private, so I have overwritten it like this:

ClassMethod MustCheckApiKey(pUrl As %String, pMethod As %String) As %Boolean
{
  SET res = 1
  If (pMethod="GET")
  {
      Set res=0
  }

  Quit res
}

 

And ready! We already have our endpoints protected by an api-key.

I leave you some screenshots of what a blocked request and a correct one would look like:

 

Correct api-key:

 

Incorrect api-key or non-existent:

 

And here is a test of a GET request that without api-key works ok:

 

Complete Base.cls file (in case you want to copy and paste)

 
Base.cls

 

 

I hope it can be useful to you in your projects.

 

Now we can sit down to enjoy our new security:

 

 

Thanks for reading me!

Discussion (0)1
Log in or sign up to continue