Skip to content

refactor(core,express): give the auth API contract values one home - #129

Merged
Bccorb merged 1 commit into
mainfrom
refactor/centralize-api-contract
Jul 30, 2026
Merged

refactor(core,express): give the auth API contract values one home#129
Bccorb merged 1 commit into
mainfrom
refactor/centralize-api-contract

Conversation

@Bccorb

@Bccorb Bccorb commented Jul 30, 2026

Copy link
Copy Markdown
Contributor

PR 4 of #72.

Problem

Values that seamless-auth-api defines were written out at each call site:

Value Copies
x-seamless-auth-delivery-mode: "external" 3 core handlers
issuer: "seamless-portal-api" / audience: "seamless-auth" 3 places in the adapter
"dev-main" key id fallback 3 places

Changing any of them is coordinated cross-repo work, and finding every copy was part of the job.

Change

New packages/core/src/apiContract.ts exporting AUTH_DELIVERY_MODE_HEADER, EXTERNAL_DELIVERY_MODE, EXTERNAL_DELIVERY_HEADERS, SERVICE_TOKEN_ISSUER, SERVICE_TOKEN_AUDIENCE, DEV_JWKS_KID, EXTERNAL_DELIVERY_TOKEN_SUBJECT, and buildExternalDeliveryAuthorization.

Every call site now reads from it. buildInternalServiceAuthorization in the adapter becomes a one-line delegation, keeping its name so nothing that imports it changes.

The reason the service-token issuer and audience are fixed, rather than the adopter's configured audience, is now stated where the constants are defined instead of in a comment at one of the three call sites.

No behavior change

The minted tokens are the same. Decoded from the built adapter:

{"header":{"alg":"HS256","kid":"test-main"},
 "iss":"seamless-portal-api","aud":"seamless-auth",
 "sub":"seamless-auth-external-delivery"}

A grep for the old literals across both packages now returns nothing outside apiContract.ts.

New tests

packages/core/tests/apiContract.test.js asserts each contract value literally. That is the point: these are the API's values, so a change should break a named test rather than surface as an upstream rejection at runtime. It also covers the token's header and claims, the dev-main fallback, verification against the service secret, that an adopter-supplied audience cannot override the service audience, and that the shared header object cannot be mutated by a caller.

What I did not do

The epic also lists route path strings. I left those alone deliberately. Unlike the values above, each upstream path appears exactly once, so there is no duplication to remove: centralizing them would add a lookup table and an indirection without collapsing anything, and a new adapter still has to write its own route registrations either way. Happy to do it if you disagree, but it looked like churn rather than the single-edit win the other three are.

Checks

pnpm build clean. pnpm test passes: 49 suites, 287 tests (up 7).

The external-delivery header and the service-token identity were written out
at each call site: the x-seamless-auth-delivery-mode header in three core
handlers, the fixed issuer and audience in three places across the adapter,
and the dev-main key id fallback in three more. Each is defined by
seamless-auth-api, so changing one is coordinated cross-repo work and
finding every copy was part of the job.

Move them to core as named constants, add buildExternalDeliveryAuthorization
for the external-delivery token, and point every call site at them.

No behavior change: the minted tokens carry the same header and claims,
confirmed by decoding them. A new test asserts each contract value
literally, so a change breaks a named test rather than surfacing as an
upstream rejection at runtime.

Refs #72
@Bccorb
Bccorb merged commit 519a1b0 into main Jul 30, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant