Kong Authentication
Source:
omni-web-catalog-pdp/src/services/auth/kong-authenticator.ts📐 ADR: ADR-0015 — Auth with API management — Decision: service credentials stored and rotated independently, never loaded directly into the app.
How It Works
Section titled “How It Works”- Credentials stored in Secrets Manager as JSON:
{ clientId, clientSecret, baseUrl } - ECS injects the secret as
AUTH_SECRETenvironment variable at container start KongAuthenticatorparses credentials on first use, fetches an OAuth token- Token is cached in-memory with proactive refresh before expiry
- Apollo Client (or REST) uses the token as
Authorization: Bearer <token>
Implementation
Section titled “Implementation”Authenticator Interface
Section titled “Authenticator Interface”export interface Authenticator { getToken(): Promise<string>;}KongAuthenticator
Section titled “KongAuthenticator”export class KongAuthenticator implements Authenticator { private static credentials: KongCredentials | null = null; private static tokenCache: TokenData | null = null; private static refreshPromise: Promise<TokenData> | null = null;
async getToken(): Promise<string> { // 1. Return cached token if valid and not near expiry // 2. If near expiry but still valid → trigger background refresh, return current // 3. If expired or missing → block and fetch new token }}Behaviors:
- Singleton credentials — parsed once, reused for process lifetime
- Proactive refresh — refreshes before expiry (default 5 min threshold)
- Deduplication — only one refresh request in-flight at a time
- Graceful degradation — if refresh fails, continues with current token until it expires
Usage with Apollo Client
Section titled “Usage with Apollo Client”export function createApolloQueryFn(authenticator: Authenticator) { const authLink = setContext(async (_, { headers }) => { const token = await authenticator.getToken(); return { headers: { ...headers, authorization: `Bearer ${token}` } }; });
const { query } = registerApolloClient(() => { const httpLink = new HttpLink({ uri: podsEndpoint }); return new ApolloClient({ link: from([authLink, httpLink]), cache: new InMemoryCache() }); }); return query;}Usage with REST
Section titled “Usage with REST”const authenticator = new KongAuthenticator();const token = await authenticator.getToken();const response = await fetch(`${BASE_API_URL}/endpoint`, { headers: { Authorization: `Bearer ${token}` },});Adding Kong Auth to a New MFE
Section titled “Adding Kong Auth to a New MFE”-
Add the secret to runtime parameters:
securityCredentials: this.getSecret('SecurityCredentials', `${globalPath}/auth`), -
Inject as ECS secret:
ecsSecrets: {AUTH_SECRET: ecs.Secret.fromSecretsManager(params.resolved.securityCredentials),} -
Create the authenticator in your service layer:
const authenticator = new KongAuthenticator(); -
Use it in your API clients (Apollo, REST, etc.)
Security Properties
Section titled “Security Properties”- Service token never exposed to client-side code (
server-onlyimport) - Credentials rotated via Secrets Manager (no app restart needed)
- Token cached in-memory only (not persisted to disk)
- Failed refresh doesn’t crash the app (graceful degradation)