@bonniernews/api-client
v0.0.12
Published
Parser middleware for api client token
Downloads
470
Maintainers
Keywords
Readme
@bonniernews/api-client
A dedicated Express middleware for resolving service-to-service (S2S) identity, primarily for use in Google Cloud environments. This parser implements a secure, cascading strategy to authenticate an incoming request against multiple sources (Direct Bearer token, Google IAP assertion, or development headers) and attaches the validated ApiClient object to req.apiClient.
It relies on a central apiClients registry and the jwk-cache module for token verification.
Installation
npm install @bonniernews/api-clientPublishing
This package is published to npm automatically via CI/CD when changes are merged to the main branch.
To publish a new version:
npm run bumpExamples
Example using the middleware with direct-invocation enabled
import express from 'express';
import { createApiClient } from '@bonniernews/api-client';
// import redisClient from './redis-client'; // Optional Redis instance
// 1. Define your allowed service accounts (clients)
const API_CLIENTS = {
"service-A": {
name: "service-A",
serviceAccount: "[email protected]",
paths: ["/api/a"],
},
"service-C-gcp": {
name: "service-C",
serviceAccount: "[email protected]",
paths: ["/api/c"],
}
};
// 2. Initialize the API client
const apiClient = createApiClient({
apiClients: API_CLIENTS,
parserOptions: {
useDirect: true, // Enable direct Bearer token check
useFakeApiClient: process.env.NODE_ENV === 'development', // Enable dev header
},
});
// 3. Mount the parser middleware
// NOTE: Must be mounted BEFORE any routes that need req.apiClient
const app = express();
app.use(apiClient.parser);
// Example route
app.post('/secure/data', (req, res) => {
if (req.apiClient) {
res.json({ clientName: req.apiClient.name, status: "Authenticated" });
} else {
res.status(403).send("Forbidden");
}
});Example enabled with solely iap check
import { createApiClient } from '@bonniernews/api-client';
const API_CLIENTS = {
"service-A": {
name: "service-A",
serviceAccount: "[email protected]",
paths: ["/api/a"],
},
"service-C-gcp": {
name: "service-C",
serviceAccount: "[email protected]",
paths: ["/api/c"],
}
};
// Initialize the API client
const apiClient = createApiClient({
apiClients: API_CLIENTS,
parserOptions: {
useDirect: false, // Only IAP check
},
});
const app = express();
app.use(apiClient.parser);
// Example route
app.post('/secure/data', (req, res) => {
if (req.apiClient) {
res.json({ clientName: req.apiClient.name, status: "Authenticated" });
} else {
res.status(403).send("Forbidden");
}
});Example iap with additionaConfig (client-specific configuration)
import { createApiClient } from '@bonniernews/api-client';
const API_CLIENTS = {
"service-A": {
name: "service-A",
serviceAccount: "[email protected]",
paths: ["/api/a"],
additionalConfig: {
"a": "b",
"b": "c"
}
},
"service-C-gcp": {
name: "service-C",
serviceAccount: "[email protected]",
paths: ["/api/c"],
}
};
// Initialize the API client
const apiClient = createApiClient({
apiClients: API_CLIENTS,
parserOptions: {
useDirect: false, // Only IAP check
},
});
const app = express();
app.use(apiClient.parser);
// Example route
app.post('/secure/data', (req, res) => {
if (req.apiClient) {
res.json({ clientName: req.apiClient.name, status: "Authenticated" });
} else {
res.status(403).send("Forbidden");
}
});Example replacing verifier function
import { createApiClient } from '@bonniernews/api-client';
const API_CLIENTS = {
"service-A": {
name: "service-A",
serviceAccount: "[email protected]",
paths: ["/api/a"],
additionalConfig: {
"a": "b",
"b": "c"
}
},
"service-C-gcp": {
name: "service-C",
serviceAccount: "[email protected]",
paths: ["/api/c"],
}
};
const newVerifierFunction = () => {
console.log("NewVerifierFunctionCalled);
return Promise.resolve();
}
// Initialize the API client
const apiClient = createApiClient({
apiClients: API_CLIENTS,
parserOptions: {
useDirect: false, // Only IAP check
verifier,
},
});
const app = express();
app.use(apiClient.parser);
// Example route
app.post('/secure/data', (req, res) => {
if (req.apiClient) {
res.json({ clientName: req.apiClient.name, status: "Authenticated" });
} else {
res.status(403).send("Forbidden");
}
});