
Security News
The Hidden Blast Radius of the Axios Compromise
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.
@dvsa/appdev-api-common
Advanced tools
Common code used by the various serverless microservices withing AppDev systems, published as a NPM package.
.nvmrc for specific version)npm (If using n or nvm, this will be automatically managed)repo-security-scanner_<version>_Darwin_<architercture>.tar.gz and rename the executable inside the folder
to scanrepo - Add executable to path (using echo $PATH to find your path)npm install (or npm i)In order to simplify the publishing step, each file must be exported from the index.ts file.
In order to see the output of what will be published, run the following command:
npm publish --dry-run
There are two ways in which this package can/should be published:
main branch, the package will be published via a GHA workflow.To test our your changes before publishing to npm, you can use the following command:
npm run localLink
Then in the project you wish to use this package, run:
npm link @dvsa/appdev-api-common
Once you've completed your local testing and/or to start again from scratch, you can run:
npm unlink @dvsa/appdev-api-common
JWTAuthChecker is a utility class for verifying JSON Web Tokens (JWT) and enforcing role-based access control (RBAC) in an Express application using routing-controllers.
It performs authentication by extracting the JWT from the request headers, verifying its validity, and checking whether the user has the required roles to access a resource.
The JWTAuthChecker.execute method can be used in conjunction with the @Authorized decorator to enforce authentication and role-based access.
In the entry point to your service/application e.g. src/index.ts, bind the JWTAuthChecker.execute method to the authorizationChecker option in the createExpressServer function.
// ...other imports
import { JWTAuthChecker } from '@dvsa/appdev-api-common';
import { MyResource } from '@resources/MyResource';
import { createExpressServer } from 'routing-controllers';
export const app = createExpressServer({
cors: true,
defaultErrorHandler: false,
controllers: [MyResource],
authorizationChecker: JWTAuthChecker.execute,
});
If no roles are required, the function will simply verify the JWT token.
import { Authorized, Get, JsonController } from "routing-controllers";
@JsonController("/example")
export class ExampleController {
@Authorized()
@Get("/secure-endpoint")
secureEndpoint() {
return { message: "Access granted" };
}
}
If specific roles are required, they can be passed as an argument.
@JsonController("/admin")
export class AdminController {
@Authorized(["admin"])
@Get("/dashboard")
getAdminDashboard() {
return { message: "Admin access granted" };
}
}
The execute method can also be called manually within custom middleware or service logic.
import { Action } from "routing-controllers";
async function checkUserAuthorization(action: Action) {
try {
const isAuthorized = await JWTAuthChecker.execute(action, ["editor"]);
if (isAuthorized) {
console.log("User is authorized");
}
} catch (error) {
console.error("Authorization failed", error);
}
}
The behavior of the authentication check can be controlled using environment variables:
IS_OFFLINE: If set to true, the authentication check is bypassed (useful for local development).FORCE_LOCAL_AUTH: If set to true, authentication is enforced even in offline mode.Example .env file:
IS_OFFLINE=true
FORCE_LOCAL_AUTH=false
JWTAuthChecker throws an AuthError in case of authentication or authorization failures. The errors are structured with an HTTP status code and message.
Possible errors:
Example error response:
{
"status": 401,
"message": "Insufficient permissions",
"code": "UNAUTHORIZED"
}
ClientCredentials is a utility class for handling OAuth2 client credentials authentication. It fetches and manages an access token from an authorization server, caching it for reuse until it expires.
This implementation helps applications authenticate machine-to-machine (M2M) interactions by using client credentials to obtain a bearer token.
ClientCredentials Classimport { ClientCredentials } from '@dvsa/appdev-api-common';
const clientCredentials = new ClientCredentials(
"https://auth.example.com/token", // Token URL
"your-client-id", // Client ID
"your-client-secret", // Client Secret
"your-scope", // OAuth2 Scope
true // Debug mode (optional)
);
To obtain an access token, call the getAccessToken method. This method caches the token and only fetches a new one if the current token is expired or unavailable.
async function authenticate() {
try {
const accessToken = await clientCredentials.getAccessToken();
console.log("Access Token:", accessToken);
} catch (error) {
console.error("Failed to retrieve access token", error);
}
}
authenticate();
If debugMode is enabled (set to true during instantiation), the class will log debug messages indicating whether it is fetching a new token or using a cached one.
Example logs:
[DEBUG] New access token fetched: eyJhbGciOi...
[DEBUG] Using existing access token: eyJhbGciOi...
ClientCredentials throws an error if token retrieval fails. Ensure your application catches these errors to prevent failures in authentication-dependent workflows.
Possible errors:
Example error handling:
try {
const token = await clientCredentials.getAccessToken();
} catch (error) {
console.error("Authentication error:", error);
}
DateTime is a utility class built on dayjs to provide a structured and flexible way to handle date and time operations. It supports parsing, formatting, arithmetic operations, and comparisons.
DateTime Classimport { DateTime } from '@dvsa/appdev-api-common';
DateTime InstanceYou can create an instance of DateTime using a Date, string, or another DateTime instance.
const now = new DateTime(); // Current date and time
const fromString = new DateTime("15/03/2025", "DD/MM/YYYY");
const fromDate = new DateTime(new Date());
You can format a DateTime instance using the format method.
console.log(now.format("YYYY-MM-DD HH:mm:ss"));
The class provides helper methods for formatting dates in UK local formats:
console.log(DateTime.StandardUkLocalDateTimeAdapter(now)); // "DD/MM/YYYY HH:mm:ss"
console.log(DateTime.StandardUkLocalDateAdapter(now)); // "DD/MM/YYYY"
You can add or subtract time units to/from a DateTime instance.
const futureDate = now.add(5, "days");
const pastDate = now.subtract(2, "weeks");
const date1 = new DateTime("2025-03-10");
const date2 = new DateTime("2025-03-15");
console.log(date1.isBefore(date2)); // true
console.log(date2.isAfter(date1)); // true
console.log(date1.isBetween("2025-03-05", "2025-03-20")); // true
Get the difference in various units:
const daysDiff = date1.daysDiff(date2); // Number of whole days between dates
const hoursDiff = date1.diff(date2, "hour");
console.log(`Difference: ${daysDiff} days, ${hoursDiff} hours`);
const duration = date1.compareDuration(date2, "minute");
console.log(`Difference in minutes: ${duration}`);
const today = DateTime.today();
console.log(today);
Ensure that input dates are in a valid format when creating a DateTime instance. If an invalid format is provided, dayjs will handle parsing failures gracefully but may return an invalid instance.
Example error handling:
const invalidDate = new DateTime("invalid-date");
console.log(invalidDate.toString()); // Returns an invalid date string
DataCompression is a utility class to simplify the compression & decompression using Gzip and Gunzip algorithms.
DataCompression Classimport { DataCompression } from '@dvsa/appdev-api-common';
This is the process of taking a plain JSON object and compressing it using Gzip.
const data = { key: 'value' };
const compressedData = DataCompression.compress(data);
// H4sIAAAAAAAAA6tWyk6tVLJSKkvMKU1VqgUAv5wYPw8AAAA=
This is the process of taking a compressed JSON object and decompressing it using Gunzip.
const data = "H4sIAAAAAAAAA6tWyk6tVLJSKkvMKU1VqgUAv5wYPw8AAAA=";
const decompressedData = DataCompression.decompress(data);
// { key: 'value' }
FAQs
Utils library for common API functionality
We found that @dvsa/appdev-api-common demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 18 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
The Axios compromise shows how time-dependent dependency resolution makes exposure harder to detect and contain.

Research
A supply chain attack on Axios introduced a malicious dependency, plain-crypto-js@4.2.1, published minutes earlier and absent from the project’s GitHub releases.

Research
Malicious versions of the Telnyx Python SDK on PyPI delivered credential-stealing malware via a multi-stage supply chain attack.