@aglyn/shared-util-http
v1.0.0-beta.176
Published
Small HTTP helpers for Fetch API and Next.js request handlers: CORS, request headers, an ID-token cookie, same-origin redirect checks, URL scheme allowlists, and an authenticated `fetch`. It is mainly a dependency of the larger Aglyn packages (`@aglyn/agl
Readme
@aglyn/shared-util-http
Small HTTP helpers for Fetch API and Next.js request handlers: CORS, request headers, an ID-token cookie, same-origin redirect checks, URL scheme allowlists, and an authenticated fetch. It is mainly a dependency of the larger Aglyn packages (@aglyn/aglyn, the plugins, the tenant runtime) and is usable on its own.
Beta. Published from the Aglyn monorepo under the
betadist-tag; APIs can change between beta releases.
Install
npm install @aglyn/shared-util-http@betaPeer dependency: next (16.3.3), optional. You need it when you use the helpers that take Next.js objects (NextRequest, NextResponse, NextApiRequest), such as the cookie helpers. The subpath modules below use only web standards.
What's in it
From the package root:
- CORS:
corsHandleResponse(req, res, options?)andcorsBuildResponseHandler(options?), which curries a reusable configuration. Deny-by-default: with nooriginoption the response is returned untouched.credentialsis never paired with a*origin. PreflightOPTIONSrequests are answered for you unlesspreflightContinueis set. Lower-level pieces:getOriginHeaders,getOriginHeadersFromRequest,getAllowedHeaders,isOriginAllowed. getRequestHeader(request, name)- reads a header from either a FetchRequestor aNextApiRequest.getAbsoluteUrl(path, request?)- builds an absolute URL from thehostheader (server) orwindow.location(browser).cookieGetUserIdToken(request)/cookieSetUserIdToken(request, response, token, options?)- read and write the user ID-token cookie,httpOnlyby default.- Types:
CorsOptions,StaticOrigin,OriginFn.
By subpath only (not re-exported from the root):
@aglyn/shared-util-http/safe-redirect-isSameOriginPath(candidate)andsafeSameOriginPath(candidate, fallback = '/'). Instead of pattern-matching the string, they resolve it with the URL parser against a probe origin and accept it only if the origin is unchanged, which catches//host,/\host, and tab or newline tricks alike.@aglyn/shared-util-http/safe-url-scheme-hasSafeLinkScheme(value)(http,https,mailto,tel,sms, or no scheme) andhasSafeMediaScheme(value)(http,https, or no scheme). They check the scheme only; you still have to escape the value into the attribute afterwards.@aglyn/shared-util-http/authorized-token-resolveIdToken(user, options?),authorizedFetch(user, input, init?, options?),describeCallFailure(error, fallback),AuthorizationUnavailableError,ID_TOKEN_TIMEOUT_MS.useris anything with agetIdToken()method. The token wait has a deadline, and when no token can be hadauthorizedFetchsends nothing and resolves to a401-shaped response carrying the reason.
Usage
import { corsBuildResponseHandler } from '@aglyn/shared-util-http'
import { safeSameOriginPath } from '@aglyn/shared-util-http/safe-redirect'
const cors = corsBuildResponseHandler({
origin: ['https://app.example.com'],
credentials: true,
})
export async function GET(req: Request) {
return cors(req, Response.json({ ok: true }))
}
// Anything that would leave the origin becomes '/'.
const next = safeSameOriginPath(new URL(location.href).searchParams.get('next'))How it fits
A shared package: generic, with no knowledge of Aglyn's model. Shared packages may only import other shared packages; this one depends on @aglyn/shared-data-enums (HTTP status codes and the cookie key). @aglyn/shared-util-next, @aglyn/shared-util-rest-api, @aglyn/shared-util-email, @aglyn/aglyn, the tenant runtime packages and most plugins depend on it.
License
Apache-2.0. Source: https://github.com/aglyn/aglyn/tree/main/libs/shared/util/http