@gydr-ai/mcp-oauth 0.1.1 → 0.1.2

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.
Files changed (2) hide show
  1. package/README.md +63 -18
  2. package/package.json +4 -4
package/README.md CHANGED
@@ -12,9 +12,14 @@
12
12
  <img alt="MCP 2026-07-28" src="https://img.shields.io/badge/MCP-2026--07--28-6f42c1" />
13
13
  <img alt="OAuth 2.1 draft-17" src="https://img.shields.io/badge/OAuth_2.1-draft--17-0969da" />
14
14
  <img alt="CIMD draft-03" src="https://img.shields.io/badge/CIMD-draft--03-0969da" />
15
+ <img alt="Node.js 22.12+" src="https://img.shields.io/node/v/@gydr-ai/mcp-oauth" />
15
16
  <a href="LICENSE"><img alt="License: Apache-2.0" src="https://img.shields.io/badge/license-Apache--2.0-blue" /></a>
16
17
  </p>
17
18
 
19
+ <p align="center">
20
+ <sub>Built and maintained by <a href="https://gydr.ai"><strong>Gydr</strong></a></sub>
21
+ </p>
22
+
18
23
  ---
19
24
 
20
25
  A remote [Model Context Protocol](https://modelcontextprotocol.io) server
@@ -31,9 +36,9 @@ The provider's tokens never leave your server.
31
36
  ## Highlights
32
37
 
33
38
  - **Spec-complete for MCP.** Protected-resource and authorization-server
34
- metadata, Client ID Metadata Documents and (deprecated, still on by
35
- default) Dynamic Client Registration,
36
- PKCE, resource indicators and issuer identification: everything the
39
+ metadata, Client ID Metadata Documents, Dynamic Client Registration
40
+ (deprecated, still on by default), PKCE, resource indicators and issuer
41
+ identification: everything the
37
42
  [MCP Authorization specification](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization)
38
43
  asks of a server.
39
44
  - **No token passthrough.** Clients get tokens bound to your MCP endpoint.
@@ -62,6 +67,8 @@ The provider's tokens never leave your server.
62
67
  - [Security model](#security-model)
63
68
  - [Specification compliance](#specification-compliance)
64
69
  - [Compatibility](#compatibility)
70
+ - [Security](#security)
71
+ - [About Gydr](#about-gydr)
65
72
 
66
73
  ## How it works
67
74
 
@@ -282,9 +289,10 @@ const auth = createMcpAuth({
282
289
  literal `true` (or `{ allow: true }`) continues; `false`, any other value, a
283
290
  rejection or a throw refuses. A refusal may name a reason,
284
291
  `{ allow: false, reason: "no_seat" }` (1–64 characters of
285
- `A-Z a-z 0-9 _ . : -`), which reaches your error page as `policyReason`. Every hook receives deeply frozen copies of the data it inspects
286
- (the client, scopes, metadata, claims and grant), so it can read validated
287
- state but cannot change what the server goes on to use.
292
+ `A-Z a-z 0-9 _ . : -`), which reaches your error page as `policyReason`.
293
+ Every hook receives deeply frozen copies of the data it inspects (the
294
+ client, scopes, metadata, claims and grant), so it can read validated state
295
+ but cannot change what the server goes on to use.
288
296
 
289
297
  | Hook | Called | On refusal |
290
298
  | ------------------------ | -------------------------------------- | ----------------------------------------------------------------------------------------------------- |
@@ -410,10 +418,10 @@ or a delete that returns the row, never a read followed by a write.
410
418
  Expired records read as absent and may be deleted at any time, for example
411
419
  by a database TTL (`getConsentRequest` may also return an expired one).
412
420
  `deleteGrant` must make `getGrant` return nothing, and should resolve with
413
- the deleted record so the last stored upstream token is the one revoked. `getAuthorizationCode`
414
- reads a code, consumed or not, without using it up: the token endpoint
415
- checks the client, redirect URI, resource and PKCE verifier against it
416
- first.
421
+ the deleted record so the last stored upstream token is the one revoked.
422
+ `getAuthorizationCode` reads a code, consumed or not, without using it up:
423
+ the token endpoint checks the client, redirect URI, resource and PKCE
424
+ verifier against it first.
417
425
 
418
426
  Three methods are optional: `putConsentOutcome` / `getConsentOutcome`
419
427
  (answering a repeated consent submission) and `listGrantsBySubject`
@@ -439,9 +447,9 @@ evict the least recently used grant-less dynamic client first when full.
439
447
  `trustProxy` behind exactly one proxy you control). **Without
440
448
  `getClientIp` or `trustProxy`, every request shares the single key
441
449
  `"unknown"`**, so one busy client can exhaust the limit for everyone.
442
- Without `rateLimit`, `POST /register` is open to flooding. A starting point: 10
443
- registrations per address per hour, 30 authorization starts per
444
- address per minute.
450
+ Without `rateLimit`, `POST /register` is open to flooding. A starting
451
+ point: 10 registrations per address per hour, 30 authorization starts
452
+ per address per minute.
445
453
  - [ ] **Alerts** from `onEvent` on `refresh_token_replayed`,
446
454
  `authorization_code_replayed`, and bursts of `flow_binding_mismatch` or
447
455
  `client_metadata_refused`.
@@ -484,7 +492,7 @@ evict the least recently used grant-less dynamic client first when full.
484
492
  | `fetchClientMetadata(url, { signal })` | SSRF-safe fetcher | Replace how metadata documents are downloaded. Must stay SSRF-safe. |
485
493
  | `lifetimes` | see below | Token and flow lifetimes, in seconds. |
486
494
  | `limits` | see below | Sizes and counts. |
487
- | `refreshReuseGraceSeconds` | `10` | Retry window for a just-used refresh token. `0` treats any reuse as replay. |
495
+ | `refreshReuseGraceSeconds` | `10` | Retry window (0–300) for a just-used refresh token. `0` treats any reuse as replay. |
488
496
  | `consentReplaySeconds` | `10` | Window (0–60) in which a repeated consent submission from the same browser gets the same redirect. |
489
497
  | `scriptHashes` | none | `sha256-…` hashes of inline scripts a custom consent page may run. |
490
498
  | `paths` | `/authorize`, `/callback`, `/consent`, `/token`, `/register`, `/revoke` | Route paths under the issuer path: one leading `/`, no `//`, `\`, dot segments or whitespace, distinct, and never a metadata path or the resource path. |
@@ -555,6 +563,20 @@ evict the least recently used grant-less dynamic client first when full.
555
563
  | `createMemoryStore(options?)` | A correct **single-process, non-persistent** store for development and tests. |
556
564
  | `escapeHtml(text)` | The escaping the built-in pages use, for your own page renderers. |
557
565
 
566
+ ### Errors
567
+
568
+ These classes reach your own code, for example from
569
+ `getUpstreamAccessToken()`; requests to the OAuth routes are answered with
570
+ OAuth errors or error pages instead. No error message contains a token.
571
+
572
+ | Class | Thrown when |
573
+ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
574
+ | `McpAuthConfigError` | `createMcpAuth` options are invalid, or `revokeGrantsForSubject` is called on a store without `listGrantsBySubject`. |
575
+ | `GrantInactiveError` | `getUpstreamAccessToken()` or `renewUpstream()` runs for a grant that was revoked or has expired. |
576
+ | `UpstreamTokenError` | No upstream access token could be obtained for a live grant. |
577
+ | `IdentityProviderError` | A call to the identity provider failed (discovery, code exchange, ID token checks, renewal). `code` is the provider's OAuth error, when it sent one. |
578
+ | `SealerError` | A sealed value is malformed, was altered, belongs to another owner, or uses a key id that is not configured. |
579
+
558
580
  ### Registered metadata is enforced
559
581
 
560
582
  - **`grant_types`**: a client that omits it gets `authorization_code` only
@@ -661,13 +683,36 @@ off, and concurrent requests for one URL share a download.
661
683
  ## Security
662
684
 
663
685
  Report vulnerabilities privately, as described in [SECURITY.md](SECURITY.md).
664
- Releases are built and published by GitHub Actions with npm provenance;
665
- `npm audit signatures` verifies them.
686
+ Please do not open a public issue for a vulnerability.
687
+
688
+ Every release is built and published by GitHub Actions with
689
+ [npm provenance](https://docs.npmjs.com/generating-provenance-statements),
690
+ and a maintainer approves each one with a hardware security key. Verify what
691
+ you installed with:
692
+
693
+ ```bash
694
+ npm audit signatures
695
+ ```
666
696
 
667
697
  ## Contributing
668
698
 
669
- See [CONTRIBUTING.md](CONTRIBUTING.md).
699
+ Issues and pull requests are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md)
700
+ for the development setup and the checks a change must pass.
701
+
702
+ ## About Gydr
703
+
704
+ `@gydr-ai/mcp-oauth` is built and maintained by [Gydr](https://gydr.ai), an
705
+ AI chatbot platform that answers customers on websites, WhatsApp, Messenger,
706
+ Instagram and Telegram. Businesses on Gydr manage their chatbots from Claude,
707
+ Codex and other MCP clients, and this package grew out of the authorization
708
+ server that makes those connections safe. See also
709
+ [`@gydr-ai/safe-fetch`](https://github.com/gydr-ai/safe-fetch), SSRF-safe
710
+ `fetch` for Node.js.
670
711
 
671
712
  ## License
672
713
 
673
- [Apache-2.0](LICENSE) © Gydr.ai
714
+ [Apache-2.0](LICENSE) © [Gydr.ai](https://gydr.ai)
715
+
716
+ <p align="center">
717
+ <a href="https://gydr.ai"><img alt="Gydr" src="https://img.shields.io/badge/made_by-Gydr-0f172a?style=for-the-badge" /></a>
718
+ </p>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gydr-ai/mcp-oauth",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "OAuth 2.1 authorization server and resource-server guard for remote MCP servers, in front of any OIDC identity provider. No token passthrough, consent on every authorization, DCR and Client ID Metadata Documents.",
5
5
  "keywords": [
6
6
  "mcp",
@@ -56,11 +56,11 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@gydr-ai/safe-fetch": "^0.1.1",
59
- "jose": "^6.2.13"
59
+ "jose": "^6.2.14"
60
60
  },
61
61
  "devDependencies": {
62
62
  "@types/node": "26.6.6",
63
- "@vitest/coverage-v8": "4.1.12",
63
+ "@vitest/coverage-v8": "5.0.5",
64
64
  "@vitest/eslint-plugin": "1.6.28",
65
65
  "esbuild": "0.28.2",
66
66
  "eslint": "10.13.0",
@@ -68,6 +68,6 @@
68
68
  "prettier": "3.9.10",
69
69
  "typescript": "6.0.3",
70
70
  "typescript-eslint": "8.72.1",
71
- "vitest": "4.1.12"
71
+ "vitest": "5.0.5"
72
72
  }
73
73
  }