Registration Service Credentials

Anthony Westover Updated by Anthony Westover

This HelpDoc discusses the credentials system for the Registration service. The was recently improved with more features and greater security, as well as migrated from configuration files to the database.

Credential System Components

Previously, a command line tool was used to create tokens for authentication purposes. Generated tokens were shared where necessary. This often resulted in the credentials being exposed in source control and shared documents which is a significant vulnerability.

The credential system eliminates storing tokens directly. Instead, the components used to generate the token are saved and reloaded as necessary (and cached for a period of time) to be calculated and used for authentication. Further, during this migration effort the ability to expire tokens (and secrets) was added along with associating access controls to secrets. Doing all this requires more comprehensive documentation of the components involved in the new credential system.

Secrets

Secrets are the most sensitive variable in the credential system. Secrets are meant to be secret, and they enable valuable security features such as token rotation, access control, and self-service. Secrets should be associated with vendors, integrating applications, even staff – collectively these roles are referred to as “secret owners”. Secrets are the primary information fed into the token generation algorithm used to produce a token for use, and to control access if specified. For this reason, a more secure use of secrets entails more granular usage based on the principle of least privilege based on the secret owner’s role or needs.

Generated tokens are associated with secrets necessarily in order to determine their maximum life (by default), as well as their access. Access configuration will be covered in the following section. Maximum token life is associated per-secret and determines the maximum life of a token generated with the secret.

A secret can optionally have an expiration date specified. The primary use cases for utilizing this are when a secret owner should no longer have system access, or if the secret has been compromised. When a secret expires, all associated tokens are rendered inactive.

Access

Secrets can be restricted to only grant access to their associated tokens to specified endpoints. Access controls are an additional layer of security and the backbone of the principle of least privilege. Vendors can be restricted to only their necessary endpoints for their integration. Integrating applications can all have their access controlled as well; with restricted access, if an integrating application is infiltrated it is still only limited to its granted functions instead of enabling broad access to infiltrators.

If no access controls are specified, a secret’s tokens have broad access.

Tokens

Tokens are the specific information included in all HTTP requests used for service authentication. A new security measure is that the actual token itself is no longer stored anywhere in the system. Instead, information necessary to generate the token is stored in the database and calculated by the service.

Token data itself is limited, and its purpose is to enable token expiration, rotation, and self-service. Aside from its secret association, a token only stores its timestamp (implemented as an epoch offset) and its expiration date. Token timestamps are fed into the generation algorithm in order to create varying tokens from the same secret: this is what enables rotation and self-service. The expiration date determines when a token is rendered inactive. The associated secret determines the tokens expiration date (unless a sooner expiration date is specified during token creation). Tokens can also be explicitly expired via self-service; this may be necessary if a token is no longer used (keep it active is a security vulnerability) or if it has been potentially compromised. Token expiration is the first line of defense against infiltration.

Secret Creation

Secrets are created directly in the database instead of via API. Secrets constitute inserting a new row into the appropriate table ServiceApiSecret specifying the associated service (i.e. Registration), the secret, an optional expiration, maximum token lifespan, and any useful comments.

The secret text should be complex and difficult to guess – in practice, this behaves as a password. If a secret is guessed (or compromised) and fed into the self-service endpoint, valid tokens associated with the secret are generated. If the secret has been compromised, it should be expired and, if necessary, a new secret created.

Access Control Setup

Access controls are created directly in the database. If no access controls are specified, a secret’s tokens have broad access to the service. Access controls are set up by explicitly specifying each endpoint the secret grants access to. Access modifications entail adding and hard-deleting rows as necessary.

Token Creation

Tokens are created via a self-service endpoint. A valid secret must be specified in a request header field called BpsSecret or else an Unauthorized response is returned. Optionally, an expiration date can be specified for the token. If the specified expiration date exceeds the maximum lifespan allowed for a secret’s tokens, this passed expiration date is ignored and the default maximum lifespan is used instead.

The endpoint returns the generated token – which should be copied/entered where appropriate by the secret owner, as well as the expiration date which should also be noted. Once the expiration date is reached, the token is inactive.

Token Expiration

Tokens can be expired, i.e. rendered immediately inactive, via a self-service endpoint. This only requires calling the endpoint with the token specified in the BpsToken field, as required of all requests to the service. This is useful for when a secret owner believes a token is compromised or has determined that a particular token is no longer necessary.

Modifying a token’s expiration, but not rendering it inactive, must be done directly in the database. Discretion should be used when doing this, and this should not be used to mark a token inactive. The main issue is that credential information modified in the database is not immediately available; it requires the service to refresh its credentials cache to pick it up (or for the service to be manually restarted). The self-service endpoint flushes the credentials cache, forcing changes to be immediately detected by the database.

Credentials Table Schema

This section covers the table schema for each component of the credentials system.

BPSUtility.Utility.ServiceApiSecret

This table stores the secrets and is the primary data entry point into the credential system.

Column Name

Type

Comment

sasId

INT, PK, NOT NULL

The ID for the secret

sasServiceName

NVARCHAR(32), NOT NULL

The service for the secret; this enables other services utilizing this credential system in the future

sasSecret

NVARCHAR(32), NOT NULL

The actual secret used to generate tokens

sasExpiryDate

DATETIME

Expiration date for the secret

sasComment

NVARCHAR(256)

Comments, i.e. description of secret owner

BPSUtility.Utility.ServiceApiAccess

Access configuration associated with a given secret.

Column Name

Type

Comment

saaId

INT, PK, NOT NULL

The ID for the access control

saasasId

INT, NOT NULL

The associated secret Id

saaServiceMethod

NVARCHAR(64), NOT NULL

The ActionName (not the URL path) for the endpoint

BPSUtility.Utility.ServiceApiToken

The actual tokens that are used to access the system.

Column Name

Type

Comment

satId

INT, PK, NOT NULL

The ID for the token

satsasId

INT, NOT NULL

The associated secret Id

satEpochOffset

INT, NOT NULL

The “timestamp” for the token, the variable component of token generation. This is an epoch offset, the number of seconds since midnight May 1, 2025

satExpiryDate

DATETIME

Expiration date for the token

Self-Service Endpoints

There are two self-service endpoints which secret owners can use to generate and expire tokens.

/api/Authorization/GenerateToken

  • Verb: POST
  • Required HTTP Header: BpsSecret
Request Body
The request body is optional. If not needed, exclude it entirely from the request.

Field Name

Type

Format

ExpirationDate

string

yyyy-mm-ddThh-MM-ss

Response

Field Name

Type

Comment

Token

string

The generated token hash. This is what to include in the BpsToken field for all requests.

ExpirationDate

string

The expiration date in yyyy-mm-ddThh-MM-ss format

/api/Authorization/ExpireToken

  • Verb: POST
  • Required HTTP Header: BpsToken
Request Body

None. The token in the BpsToken request header is what is expired.

Response

No response body, returns an HTTP 200 upon success.

Appendix: “Legacy” Tokens

Existing tokens have been ported to this new system as “legacy” tokens. For the initial import, these tokens had no expiration date and no epoch offset. Expiration date was set to null, and epoch offset set to 0. This triggers special logic in the service to run the original algorithm to generate the associated token hash. This enabled removing these legacy tokens from source control and configuration files.

Do not add epoch offsets to legacy tokens. Lacking an epoch offset indicates to the system that these are legacy tokens and to use the legacy hashing algorithm. Therefore, adding an epoch offset breaks the legacy token and renders their existing hashes useless.
Expirations for legacy tokens have been set to null. These can, and should, have expiration dates set in the future or they should be expired via the self-service endpoint. Alternatively, the secret itself can be expired, expiring the legacy token as well.
Legacy tokens can have access controls associated with them by configuring access controls for their associated secret. This was done for Avela’s associated secret, which vicariously applied to their existing legacy token.

Appendix: Token Hashing Algorithm

The token hashing algorithm deliberately lacks specifics here, and is available in source control. It should not be modified, as it will break all authentication. What is covered here are the variables entered into the hashing algorithm.

Secret

The actual secret text. Keeping a secret secure is crucial since, effectively, this behaves as a password and can be cracked/infiltrated through similar means (i.e. rainbow tables, brute force, etc.) to generate tokens.

Offset

The epoch offset is formatted consistently and included in the hash algorithm. For simplicity, this is why an epoch offset is used instead of a long, potentially variably formatted datetime string. Epoch offsets are a count of the number of seconds from a certain time. The most well known is the Unix epoch: January 1, 1970 midnight UTC. For this system, May 1, 2025 midnight EST is used. “Legacy” tokens lack an offset, therefore the offset is not included in the hash algorithm.

Salt

An internal service salt, not saved anywhere in the database, is included in the hashing algorithm. This should be unique to a service and should not be changed, or else it broadly breaks all existing tokens. Salts are a common and effective security measure, which can be either static (as in our case) or dynamic (usually relative to some required user/system information). Salts are added to a hashing algorithm to obscure the true secret/key/password/whatever.

The intent with salts is to make reverse engineering secrets/keys/passwords/whatever nearly impossible from the hash alone. For example, if a token (i.e. the hash) is compromised, the means for generating the token – i.e. the secret – are obscured because the salt, which isn’t used when generating a new token, is included as part of the hash. Once the compromised token is expired, an infiltrator has no recourse if they don’t know the secret – which they can’t reasonably determine from the hash alone – and therefore cannot generate their own tokens.

How did we do?

Editing Ticket Fields in Kace via email

Contact