@valbuild/next 0.122.0 → 0.123.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,93 +0,0 @@
1
- import { type ValToolAuth } from "@valbuild/server";
2
- /**
3
- * Verifying an OAuth access token, which is the whole of what makes this app a
4
- * resource server rather than a relay.
5
- *
6
- * The token is issued by Val's authorization server and presented by an MCP
7
- * client. This app holds no signing key for it and cannot mint one — it fetches
8
- * the issuer's *public* keys and checks a signature. That asymmetry is the
9
- * point: a verified `sub` is a fact about the token rather than a claim by
10
- * whoever sent it, which is what lets the tools attribute a patch to that
11
- * profile at all.
12
- *
13
- * ## Why this is not `jose`
14
- *
15
- * `jose` was the first choice and was rejected on a fact rather than a
16
- * preference: version 6 is ESM-only (`"type": "module"`, no CJS export). This
17
- * package is built by preconstruct and `require`d by Next.js server code, so an
18
- * ESM-only dependency here is a runtime failure in consumers' apps, not a build
19
- * inconvenience. Adding it would also put a dependency in every install of
20
- * `@valbuild/next` for one function.
21
- *
22
- * The actual cryptography is still not hand-rolled — `node:crypto` does the
23
- * ECDSA and the JWK import. What is written here is the JWS envelope and the
24
- * claim checks, and the rules that keep that safe are worth stating because
25
- * this repository has already shipped the counterexample (`decodeJwt`: `exp`
26
- * never checked, a non-constant-time compare, verification skippable):
27
- *
28
- * - **`alg` is pinned**, not read from the token. The header is only consulted
29
- * for `kid`. A verifier that honours the token's own `alg` can be handed
30
- * `HS256` and will treat the *published* public key as a shared secret.
31
- * - **Nothing is read from the payload before the signature verifies.** Claims
32
- * from an unverified token are attacker input.
33
- * - **Keys come only from the configured issuer's JWKS**, never from the token.
34
- * The key set is cached, but a token naming a `kid` the cache does not hold
35
- * provokes one rate-limited refetch rather than a refusal — see
36
- * {@link UNKNOWN_KID_REFETCH_INTERVAL_MS}. Without that, this server's own
37
- * cache turns any key rotation into an outage lasting the rest of the TTL.
38
- * - **ECDSA JWS signatures are raw `r||s`** (RFC 7518), not DER, which is what
39
- * `dsaEncoding: "ieee-p1363"` below is for. Omit it and every valid signature
40
- * is rejected — or worse, a future change makes it accept the wrong thing.
41
- */
42
- export type ValOAuthConfig = {
43
- /**
44
- * The authorization server, and therefore the expected `iss`.
45
- *
46
- * Also where the JWKS is fetched from, so it is the one value that decides
47
- * which keys can produce a token this app accepts. Configuration, never
48
- * request input — a request that could name its own issuer could name its own
49
- * key.
50
- */
51
- issuer: string;
52
- /**
53
- * This endpoint's absolute URL, and therefore the expected `aud` (RFC 8707).
54
- *
55
- * Audience binding is what stops a token minted for one Val site being
56
- * replayed against another: without it, any deployment the user has access to
57
- * would accept a token issued for any other.
58
- */
59
- resource: string;
60
- /**
61
- * Clock skew allowance, in seconds.
62
- *
63
- * Servers disagree about the time by more than you would like, and a token
64
- * refused for being a second early is indistinguishable, to the person using
65
- * it, from a broken login.
66
- */
67
- clockToleranceSeconds?: number;
68
- /** Test seam. Defaults to the global `fetch`. */
69
- fetchImpl?: typeof fetch;
70
- };
71
- export type ValAccessTokenResult = {
72
- status: "ok";
73
- auth: Extract<ValToolAuth, {
74
- type: "verified-profile";
75
- }>;
76
- } | {
77
- status: "refused";
78
- /** For the `WWW-Authenticate` challenge: RFC 6750 section 3.1. */
79
- error: "invalid_request" | "invalid_token" | "insufficient_scope";
80
- description: string;
81
- };
82
- /** Test seam: a fresh process would have an empty cache anyway. */
83
- export declare function clearValAccessTokenCache(): void;
84
- /**
85
- * Read `Authorization: Bearer …`.
86
- *
87
- * Exported because the refusal needs to know whether a token was presented at
88
- * all: RFC 6750 distinguishes "no credential" — a bare `401`, which is an
89
- * invitation to authenticate — from "a bad credential", and a client that gets
90
- * the second when it deserved the first will not start the authorization flow.
91
- */
92
- export declare function readBearerToken(request: Request): string | null;
93
- export declare function verifyValAccessToken(request: Request, config: ValOAuthConfig): Promise<ValAccessTokenResult>;
@@ -1,47 +0,0 @@
1
- import type { ValOAuthConfig } from "./valAccessToken.js";
2
- /**
3
- * The one document an MCP client needs before it can authorize: RFC 9728
4
- * Protected Resource Metadata, served by the *resource* server.
5
- *
6
- * This is how a client discovers where to authorize. It asks the resource — this
7
- * app — and the resource names its authorization server. Which is why this
8
- * belongs here and the RFC 8414 *authorization server* metadata does not: that
9
- * document lives at the issuer, describes the issuer's own endpoints, and is
10
- * served by the issuer. An app serving a copy would be asserting the issuer's
11
- * configuration on its behalf, and would be wrong the moment the issuer changed
12
- * anything.
13
- *
14
- * The flow, so the split reads as a whole:
15
- *
16
- * 1. client → `{app}/api/mcp` with no token → `401` naming this document
17
- * 2. client → `{app}/.well-known/oauth-protected-resource` → the issuer
18
- * 3. client → `{issuer}/.well-known/oauth-authorization-server` → endpoints
19
- * 4. client → issuer's `/authorize`, then `/token`
20
- * 5. client → `{app}/api/mcp` with the token
21
- */
22
- export type ValMcpMetadataHandlers = {
23
- /** The metadata document. */
24
- GET: (request: Request) => Response;
25
- /**
26
- * The CORS preflight.
27
- *
28
- * Required rather than defensive: the metadata document is fetched
29
- * cross-origin by browser-based clients, and without a preflight answer the
30
- * fetch fails before the document is read — which presents as "this connector
31
- * cannot authorize" with nothing in any log to explain it.
32
- */
33
- OPTIONS: (request: Request) => Response;
34
- };
35
- export declare function createValMcpMetadata(oauth: ValOAuthConfig, scopesSupported: string[]): ValMcpMetadataHandlers;
36
- /**
37
- * The `WWW-Authenticate` value for a refusal (RFC 6750 section 3, RFC 9728
38
- * section 5.1).
39
- *
40
- * `resource_metadata` is the load-bearing parameter: it is how a client that has
41
- * never seen this server learns where to authorize. A `401` without it is a dead
42
- * end — the client knows it needs a token and has no way to find out from where.
43
- */
44
- export declare function wwwAuthenticate(oauth: ValOAuthConfig, scopesSupported: string[], refusal?: {
45
- error: string;
46
- description: string;
47
- }): string;
@@ -1,13 +0,0 @@
1
- 'use strict';
2
-
3
- function _typeof(o) {
4
- "@babel/helpers - typeof";
5
-
6
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
7
- return typeof o;
8
- } : function (o) {
9
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
10
- }, _typeof(o);
11
- }
12
-
13
- exports._typeof = _typeof;
@@ -1,11 +0,0 @@
1
- function _typeof(o) {
2
- "@babel/helpers - typeof";
3
-
4
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
5
- return typeof o;
6
- } : function (o) {
7
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
8
- }, _typeof(o);
9
- }
10
-
11
- export { _typeof as _ };
@@ -1,13 +0,0 @@
1
- 'use strict';
2
-
3
- function _typeof(o) {
4
- "@babel/helpers - typeof";
5
-
6
- return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
7
- return typeof o;
8
- } : function (o) {
9
- return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
10
- }, _typeof(o);
11
- }
12
-
13
- exports._typeof = _typeof;