Skip to main content
Skip table of contents

API Key Authentication

Introduction

API keys allow autonomous applications to access an instance of the WebTSM Services when other means of authentication are impractical.

Such applications require the storage of credentials to be used for authentication. Storing credentials for Basic authentication creates a security issue, since if they are compromised the entire account secured by the username/password combination is at risk. Changing the password may require many applications to be reconfigured or redeployed potentially causing excessive downtimes.

Access tokens as issued by OpenIDConnect/OAuth identity providers are short lived and therefore not suitable for long running autonomous applications. Storing credentials used to request new tokens automatically bears the same security risk mentioned for storing Basic credentials above.

API keys allow one user to issue long-lived tokens that can be used by an application to gain access to a service without the need for user interaction (i.e. logging in). If an API key is compromised, the user can invalidate that particular token. Since an API key cannot be used to impersonate the user in other scenarios, the impact such a leak would have is minimized. In addition, other applications (using their own API key) do not have to be reconfigured in case one applications credentials are compromised and have to be revoked.

Underneath the hood, API keys are cryptographically signed Json Web Tokens (JWTs) similar to any other access token, but contain special information to allow for their proper validation by the service.

Prerequisites

For API keys to be used effectively, the service should support at least one other method of authentication (i.e. Basic authentication, the integrated OpenIDConnect identity provider or an external OpenIDConnect identity provider like Microsoft Entra ID)

Configuration

In order to allow clients to use API keys, several settings have to be added to the services HAKOM.Config file.

Note that there are technically two scenarios possible:

  1. If the service should only accept API keys as a form of credentials

  2. If the service should also allow users to manage their API keys.

In most cases, one service will be configured to support both, i.e. the second case. We will focus on how to configure that case.

Enabling API Keys

In order for API keys to be accepted by the WebTSM Services at all, they must be enabled (at the HAKOM Framework level).

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <Enabled>true</Enabled>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products>
</HAKOMConfiguration>

If this value is set to false or not set at all, users can not authenticate using API keys and requests made with an API key in the Authorization header will receive a “401 (Unauthorized)” response.

Configuring Key Persistence

Information about API keys is stored in a database. The name of the database to use for storage must be configured as well. The value of this setting should correspond with the name of a configured <dbconnection> entry in the HAKOM.Config.

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <Repository>KEY_REPOSITORY</Repository>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products
</HAKOMConfiguration>

Note that the fact that the keys are stored in one repository does not limit their use to that particular repository.

Configuring Key Content

Issuer Template

When a new API key is generated, its iss field of the token should contain information about the user that issued that key. This is required in order to

  • authorize actions such as deleting/invalidating the key.

  • check if the maximum number of API keys that can be created has been exceeded.

This is done by providing a template string that is added to the iss field of the API key.

Let’s assume the user creating a new API key has the following claims:

JSON
{
  "iss": "https://login.microsoftonline.com/...",
  "preferred_username": "sarah",
  "sub": "jkdpcossdoas00sdasdks89",
  "company": "ACME Ltd."
}

Then given the following configuration:

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <IssuerTemplate>{company}</IssuerTemplate>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products
</HAKOMConfiguration>

the generated API key will have an iss field equivalent to

api-key://company:ACME Ltd./jkdpcossdoas00sdasdks89

Please note:

  • The iss field will always starts with api-key://

  • The iss field will always end on / followed by the issuing users sub claim or any other claim type configured in <UserClaimType>

The <UserClaimType> configures which claim type of the users claims should be used for the end of the iss field. The default is the sub claim type as seen in the example above. If the configuration from that example is changed to following:

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <IssuerTemplate>{company}</IssuerTemplate>
          <UserClaimType>preferred_username</UserClaimType>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products>
</HAKOMConfiguration>

the generated API key will have an iss field equivalent to

api-key://company:ACME Ltd./sarah

The value generated is important for setting up proper authorization rules and key limits (see Customization below).

This means that the value for <IssuerTemplate> depends heavily on the specific use case.

How do you as an operator want to limit access to API keys? Do you want to configure an administrator capable of invalidating other users API keys? What kind of limits do you want to impose? Should all users be alotted the same number of API keys? Or should it depend on some attribute of the user, i.e. their company, role or department?

These questions must be adressed before enabling and configuring API key authentication as these decisions will influence how you as an operator will be able to control their use.

Copied Claims

The permissions that the API key should have are defined via the <CopiedClaims> setting in the HAKOM.Config. Here you can specify one or more claim types, separated by commas. Claims with these types are then copied from the user who generated this API key. This ensures that the API key has the same or a subset of the permissions that the user has who created the the key.

Example

Let’s assume the user creating a new API key has the following claims:

JSON
{
  "iss": "https://login.microsoftonline.com/...",
  "preferred_username": "sarah",
  "sub": "jkdpcossdoas00sdasdks89",
  "company": "ACME Ltd.",
  "department": "Sales"
}

Then given the following configuration:

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <CopiedClaims>department,company</CopiedClaims>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products>
</HAKOMConfiguration>

the generated API key will be associated with the following claims on authentication

JSON
{
  "department": "sales",
  "company": "ACME Ltd."
}

So every authorization rule that applies to the claimvalue sub: "jkdpcossdoas00sdasdks89" or company: "ACME Ltd." also applies to requests made with this users API keys.

Important Notes

  • At least one CopiedClaim must be defined.

  • “sub” should not be added to the list of copied claims (doing so may cause adverse effects that are difficult to debug)

  • When a users claims are edited (i.e. the user is added to or removed from a role), these changes are currently not automatically reflected in the users API keys and thus, authorization rules may diverge between a user and their keys. It is advisable to invalidate existing API keys when making such changes to a user.

Configuring API Key Caching

Enabling API Key Caching

In order to improve performance, information about API keys can be cached in memory by the WebTSM Services. For this to take place at all, caching of API key information must be enabled (at the HAKOM Framework level).

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <Caching>
            <Enabled>true</Enabled> <!-- Default: false -->
          </Caching>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products>
</HAKOMConfiguration>

If this value is set to false or not set at all, information about keys and authorization rules relating to them will always be loaded directly from the underlying databases, resulting in a performance penalty.

On the other hand, disabling the cache can prevent stale data being used when making lots of changes to API keys in a short time. For this reason it might be advisable to disable caching during initial setup/configuration, then enable it in production.

Configuring API Key Caching Duration

The Expiration setting determines the length of time for which data associated with API keys remains in memory. If cached data (for example, the public key used to validate an API key) has been in memory for longer than that period, the cached version will be discarded and replaced with fresh data from the underlying database.

XML
<HAKOMConfiguration>
  <products>
    <HAKOMFramework>
      <settings>
        <ApiKeys>
          <!-- other settings omitted for brevity -->
          <Caching>
            <Expiration>00:01:00</Expiration> <!-- Default: 01:00:00 one hour -->
          </Caching>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </products>
</HAKOMConfiguration>

This setting is only considered if caching is enabled. If caching is enabled and no value has been set for Expiration, the default expiration value of one hour will be used.

Customization

In order to fully use all the features that API key authentication provides, there may be some customization necessary. Note that the changes below are currently only possible with direct access to the underlying repository in which the keys are stored (see Configuring Key Persistence above).

An API to make these adjustments may be made available at a later time.

Customizing Authorization Rules

By default, a user may only delete (invalidate) their own API keys. There may be situations in which some sort of administrative account should be able to invalidate other users API keys as well.

In order to do so, a new entry must be added to the table FWS_APIKEYS_AUTHORIZATION.

The ISSUER_PREFIX column specifies the API keys that this rule applies to. For example, if ISSUER_PREFIX is set to api-key://company-a then, the rule applies to all API keys with an issuer that starts with api-key://company-a.

The SUBJECT column specifies who that rule applies to.

An authorization rule can also be added for the scope of the entire repository. For that, a new entry needs to be added in FWS_REPOSITORY_AUTHORIZATION with an OBJECTTYPE of APIKEYS. The desired permissions can then be entered in last four colums. FWS_REPOSITORY_AUTHORIZATION entries where OBJECTTYPE is null only apply for API key management if there is no entry where OBJECTTYPE is APIKEYS.

image-20250422-094535.png

A user can perform an action, only if they have the relevant permission for the repository (FWS_REPOSITORY_AUTHORIZATION) AND the affected api key (FWS_APIKEYS_AUTHORIZATION).

Customizing Limits

As of now, customizing how many API keys can be created must be done directly in the database configured in <Repository> (see API Key Authentication | Configuring-Key-Persistence )

Limits, similar to authorization rules, can be created for a group of issuers, defined by their issuer prefix. In order to define one, a new entry must be added in the FWS_APIKEYS_LIMITS table. The first column contains the ISSUER_PREFIX which defines what group should be affected. This prefix however, should be entered without the api-key:// at the start.

This configuration limits the amount of keys a group can collectively have at a time. Another way to define limits is for each member of a group individually. This is done by putting the desired claim in curved brackets in the issuer_prefix column. If I want to limit each user individually for example I could enter {preferred_username}.

The LIMIT value is a simple integer that defines the amount of keys the given group can have active at a time.

Examples

This example will guide you through the customization process starting with authorization rules and continuing on with limits.

Authorization

In this example, we will create an admin - user relationship in which the admin can delete keys of users but not the other way round. The API keys are configured in a way where the preferred username defines the issuer. In reality it would be more practical to use a attribute like teams, divisions etc.

CODE
<HAKOMConfiguration>
  <HttpConnections>
    <HAKOMFramework>
      <settings>  
        <ApiKeys>
          <Enabled>true</Enabled>
          <Repository>TSM</Repository>
          <CopiedClaims>iss,sub</CopiedClaims>
          <IssuerTemplate>{preferred_username}</IssuerTemplate>
        </ApiKeys>
      </settings>
    </HAKOMFramework>
  </HttpConnections>
</HAKOMConfiguration>

I have created two users and one admin and created one API Key with each. The FWS_APIKEYS_AUTHORIZATION table now looks like this:

image-20250415-092310.png

The issuer_prefixdefines the keys affected by the rule and the claimvalue columns define who is allowed to perform the CRUD operations as defined in the last 4 columns. So these three already existing entries give each user permission to manage their own keys.

To add a rule that allows testadmin1 to delete keys of testuser1 and testuser2 we need to add the following entry:

image-20250415-093336.png

The issuer_prefix makes sure that all affected API key issuers start with this string. So, looking at the prefixes of our test users, we see that all of them start with apikey://preferred_username:testuser so that is what we put in that column. Next we take a look at owner_claimvalue_id and subject_claimvalue_id of our admin entry, which is 7 for both. As we want the admin to be able to manage the users keys, we put the 7 in its respective cells. Finally, we define the CRUD operations that the admin should be allowed to perform on the users keys.

After commiting these changes, it should now be possible for the admin to delete the users keys, but the users can only delete their own.

Limits

In this example we will first create a limit to a group as a whole and then for each member of their members.

Once again we are working with users testuser1 and testuser2. As their usernames start identically, we can define their group through that. Again, in an actual application it would be more sensical to use teams, divisions etc. To limit the test users to a single API key I add this entry:

image-20250415-113258.png

I can now add a key as testuser1 or testuser2 and then no more for either of them. If I want each user to be able to create a key independently from each other i can add this entry instead:

image-20250415-113609.png
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.