@silkweave/auth 2.6.1 → 3.0.0

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.
package/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # @silkweave/auth
2
2
 
3
- OAuth 2.1 authentication for [Silkweave](https://github.com/silkweave/silkweave) MCP servers. Acts as an OAuth proxy between MCP clients and upstream identity providers (Google, etc.), handling PKCE, refresh tokens, dynamic client registration (CIMD), and protected resource metadata (RFC 9728).
3
+ Auth for [Silkweave](https://github.com/silkweave/silkweave) MCP servers, in two layers:
4
+
5
+ - **Resource-server core** (the package root, `@silkweave/auth`) - the spec-required surface for an MCP server: bearer-token validation + protected resource metadata (RFC 9728). `jose`-only. Most servers need only this and delegate token issuance to an external IdP (Auth0/WorkOS/Stytch/Keycloak/Google).
6
+ - **OAuth authorization server** (the opt-in subpath, `@silkweave/auth/oauth`) - a full OAuth 2.1 proxy between MCP clients and an upstream IdP: PKCE, refresh tokens, dynamic client registration (CIMD), and persistence stores. Import this only when you want Silkweave itself to *be* the authorization server, so a pure resource server never pulls the issuer machinery into its dependency graph.
4
7
 
5
8
  ## Install
6
9
 
@@ -8,12 +11,14 @@ OAuth 2.1 authentication for [Silkweave](https://github.com/silkweave/silkweave)
8
11
  pnpm add @silkweave/auth
9
12
  ```
10
13
 
14
+ > The OAuth-proxy helpers (`google`, `createOAuthProxy`, `createJsonStore`/`createRedisStore`/`createMemoryStore`, `OAuthStore`) are imported from `@silkweave/auth/oauth`. Bearer validation (`validateToken`) and `generateProtectedResourceMetadata` - plus the `AuthConfig`/`AuthInfo`/`OAuthRequest`/`OAuthResponse`/`OAuthProvider` types - live at the package root.
15
+
11
16
  ## Quick Start with Google OAuth
12
17
 
13
18
  The `google()` helper returns a complete `AuthConfig` ready to pass to the `http()` adapter:
14
19
 
15
20
  ```typescript
16
- import { google, createJsonStore } from '@silkweave/auth'
21
+ import { google, createJsonStore } from '@silkweave/auth/oauth'
17
22
  import { silkweave } from '@silkweave/core'
18
23
  import { http } from '@silkweave/mcp'
19
24
 
@@ -52,7 +57,7 @@ await silkweave({ name: 'my-server', description: 'My MCP Server', version: '1.0
52
57
  For providers other than Google, use `createOAuthProxy()` directly. It returns an `OAuthProvider` that implements the full OAuth 2.1 proxy flow:
53
58
 
54
59
  ```typescript
55
- import { createOAuthProxy } from '@silkweave/auth'
60
+ import { createOAuthProxy } from '@silkweave/auth/oauth'
56
61
 
57
62
  const provider = createOAuthProxy({
58
63
  authorizeUrl: 'https://provider.example.com/authorize',
@@ -139,6 +144,36 @@ if (result.error) {
139
144
  console.log(result.auth?.clientId)
140
145
  ```
141
146
 
147
+ ### Recommended: front with an external IdP (resource-server only)
148
+
149
+ The MCP 2026 spec direction is for servers to be **pure OAuth resource servers**
150
+ that delegate token issuance to a dedicated authorization server. For most
151
+ deployments, point `authorizationServers` at an external IdP (Auth0, WorkOS,
152
+ Stytch, Keycloak, Google, ...), have `verifyToken` validate that IdP's JWTs (e.g.
153
+ with `jose`'s `jwtVerify` against the IdP JWKS), and skip the `@silkweave/auth/oauth`
154
+ proxy entirely:
155
+
156
+ ```typescript
157
+ import { validateToken } from '@silkweave/auth'
158
+
159
+ const auth = {
160
+ resourceUrl: 'https://mcp.example.com',
161
+ authorizationServers: ['https://idp.example.com'],
162
+ issuer: 'https://idp.example.com', // RFC 9207 - bind the token to this issuer
163
+ audience: 'https://mcp.example.com', // RFC 8707 - reject tokens minted for another resource
164
+ requiredScopes: ['mcp:tools'], // advertised in the 403 step-up challenge (SEP-2350)
165
+ verifyToken: async (token) => {
166
+ const { payload } = await jwtVerify(token, JWKS, { issuer: 'https://idp.example.com', audience: 'https://mcp.example.com' })
167
+ return { token, clientId: payload.sub, scopes: String(payload.scope ?? '').split(' '), iss: payload.iss, aud: payload.aud, expiresAt: payload.exp }
168
+ }
169
+ }
170
+ ```
171
+
172
+ `validateToken` then enforces, in order: expiry, **issuer** binding (`issuer`),
173
+ **audience** binding (`audience`, defaults to `resourceUrl`; set `false` to skip),
174
+ and **required scopes** - emitting a `WWW-Authenticate` challenge with `scope="..."`
175
+ on insufficient scope so the client knows what to step up to.
176
+
142
177
  ## Protected Resource Metadata (RFC 9728)
143
178
 
144
179
  Generate the `/.well-known/oauth-protected-resource` document for your server:
@@ -148,11 +183,13 @@ import { generateProtectedResourceMetadata } from '@silkweave/auth'
148
183
 
149
184
  const metadata = generateProtectedResourceMetadata(
150
185
  'https://my-server.example.com',
151
- ['https://my-server.example.com']
186
+ ['https://idp.example.com'],
187
+ ['mcp:tools'] // optional scopes_supported - the adapters pass auth.requiredScopes here
152
188
  )
153
189
  // {
154
190
  // resource: 'https://my-server.example.com',
155
- // authorization_servers: ['https://my-server.example.com'],
191
+ // authorization_servers: ['https://idp.example.com'],
192
+ // scopes_supported: ['mcp:tools'],
156
193
  // bearer_methods_supported: ['header']
157
194
  // }
158
195
  ```
@@ -166,7 +203,7 @@ The OAuth proxy needs persistent storage for auth codes, client registrations, P
166
203
  In-memory storage -- data is lost on restart. Good for development:
167
204
 
168
205
  ```typescript
169
- import { createMemoryStore } from '@silkweave/auth'
206
+ import { createMemoryStore } from '@silkweave/auth/oauth'
170
207
 
171
208
  const store = createMemoryStore()
172
209
  ```
@@ -176,7 +213,7 @@ const store = createMemoryStore()
176
213
  Persists to a JSON file on disk. Suitable for single-process deployments:
177
214
 
178
215
  ```typescript
179
- import { createJsonStore } from '@silkweave/auth'
216
+ import { createJsonStore } from '@silkweave/auth/oauth'
180
217
 
181
218
  const store = createJsonStore('oauth-store.json')
182
219
  ```
@@ -186,7 +223,7 @@ const store = createJsonStore('oauth-store.json')
186
223
  For production multi-process deployments. Accepts any Redis client with `get`/`set`/`del` methods (compatible with `ioredis` and `redis`):
187
224
 
188
225
  ```typescript
189
- import { createRedisStore } from '@silkweave/auth'
226
+ import { createRedisStore } from '@silkweave/auth/oauth'
190
227
  import Redis from 'ioredis'
191
228
 
192
229
  const store = createRedisStore({
@@ -200,7 +237,7 @@ const store = createRedisStore({
200
237
  Implement the `OAuthStore` interface for your own backend:
201
238
 
202
239
  ```typescript
203
- import type { OAuthStore } from '@silkweave/auth'
240
+ import type { OAuthStore } from '@silkweave/auth/oauth'
204
241
 
205
242
  const store: OAuthStore = {
206
243
  saveAuthCode(code, data) { /* ... */ },
package/build/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import { a as OAuthRequest, i as OAuthProvider, n as VerifyToken, o as OAuthResponse, r as AuthInfo, t as AuthConfig } from "./types-BFhAEzlP.mjs";
1
2
  import { SilkweaveContext } from "@silkweave/core";
2
3
 
3
4
  //#region src/errors.d.ts
@@ -11,7 +12,7 @@ declare function insufficientScope(message?: string): AuthError;
11
12
  //#endregion
12
13
  //#region src/extract.d.ts
13
14
  declare function extractBearerToken(header: string | null | undefined): string | null;
14
- declare function buildWWWAuthenticate(error?: string, description?: string, resourceMetadataUrl?: string): string;
15
+ declare function buildWWWAuthenticate(error?: string, description?: string, resourceMetadataUrl?: string, scope?: string): string;
15
16
  //#endregion
16
17
  //#region src/metadata.d.ts
17
18
  interface ProtectedResourceMetadata {
@@ -20,155 +21,7 @@ interface ProtectedResourceMetadata {
20
21
  scopes_supported?: string[];
21
22
  bearer_methods_supported?: string[];
22
23
  }
23
- declare function generateProtectedResourceMetadata(resourceUrl: string, authorizationServers: string[]): ProtectedResourceMetadata;
24
- //#endregion
25
- //#region src/provider/types.d.ts
26
- interface AuthInfo {
27
- token: string;
28
- clientId?: string;
29
- scopes?: string[];
30
- expiresAt?: number;
31
- [key: string]: unknown;
32
- }
33
- interface OAuthRequest {
34
- method: string;
35
- url: URL;
36
- headers: Record<string, string | undefined>;
37
- body?: Record<string, string>;
38
- }
39
- interface OAuthResponse {
40
- status: number;
41
- headers: Record<string, string>;
42
- body?: string | Record<string, unknown>;
43
- }
44
- interface OAuthProvider {
45
- authorize(req: OAuthRequest): Promise<OAuthResponse>;
46
- callback(req: OAuthRequest): Promise<OAuthResponse>;
47
- token(req: OAuthRequest): Promise<OAuthResponse>;
48
- register(req: OAuthRequest): Promise<OAuthResponse>;
49
- metadata(): OAuthResponse;
50
- verifyToken(token: string): Promise<AuthInfo | undefined>;
51
- }
52
- //#endregion
53
- //#region src/types.d.ts
54
- type VerifyToken = (token: string, context: SilkweaveContext) => Promise<AuthInfo | undefined>;
55
- interface AuthConfig {
56
- verifyToken: VerifyToken;
57
- required?: boolean;
58
- resourceUrl?: string;
59
- authorizationServers?: string[];
60
- requiredScopes?: string[];
61
- provider?: OAuthProvider;
62
- callbackPath?: string;
63
- }
64
- //#endregion
65
- //#region src/provider/store.d.ts
66
- interface AuthCodeData {
67
- clientId: string;
68
- redirectUri: string;
69
- codeChallenge: string;
70
- codeChallengeMethod: string;
71
- scopes: string[];
72
- upstreamAccessToken: string;
73
- upstreamIdToken?: string;
74
- email?: string;
75
- sub?: string;
76
- expiresAt: number;
77
- }
78
- interface PendingAuthData {
79
- clientId: string;
80
- redirectUri: string;
81
- codeChallenge: string;
82
- codeChallengeMethod: string;
83
- scope: string;
84
- clientState: string;
85
- resource?: string;
86
- expiresAt: number;
87
- }
88
- interface ClientRegistration {
89
- clientId: string;
90
- clientSecret: string;
91
- redirectUris: string[];
92
- clientName?: string;
93
- createdAt: number;
94
- }
95
- interface RefreshTokenData {
96
- clientId: string;
97
- scopes: string[];
98
- email?: string;
99
- sub?: string;
100
- expiresAt: number;
101
- }
102
- interface OAuthStore {
103
- saveAuthCode(code: string, data: AuthCodeData): Promise<void>;
104
- getAuthCode(code: string): Promise<AuthCodeData | undefined>;
105
- deleteAuthCode(code: string): Promise<void>;
106
- savePendingAuth(state: string, data: PendingAuthData): Promise<void>;
107
- getPendingAuth(state: string): Promise<PendingAuthData | undefined>;
108
- deletePendingAuth(state: string): Promise<void>;
109
- savePkceVerifier(state: string, verifier: string): Promise<void>;
110
- getPkceVerifier(state: string): Promise<string | undefined>;
111
- deletePkceVerifier(state: string): Promise<void>;
112
- saveClient(clientId: string, data: ClientRegistration): Promise<void>;
113
- getClient(clientId: string): Promise<ClientRegistration | undefined>;
114
- saveRefreshToken(token: string, data: RefreshTokenData): Promise<void>;
115
- getRefreshToken(token: string): Promise<RefreshTokenData | undefined>;
116
- deleteRefreshToken(token: string): Promise<void>;
117
- }
118
- //#endregion
119
- //#region src/provider/google.d.ts
120
- interface GoogleOAuthOptions {
121
- clientId: string;
122
- clientSecret: string;
123
- resourceUrl: string;
124
- redirectUris: string[];
125
- requiredScopes?: string[];
126
- callbackPath?: string;
127
- signingKey?: string;
128
- tokenTtl?: number;
129
- store?: OAuthStore;
130
- }
131
- declare function google(options: GoogleOAuthOptions): AuthConfig;
132
- //#endregion
133
- //#region src/provider/proxy.d.ts
134
- interface OAuthProxyConfig {
135
- authorizeUrl: string;
136
- tokenUrl: string;
137
- userinfoUrl?: string;
138
- clientId: string;
139
- clientSecret: string;
140
- resourceUrl: string;
141
- redirectUris: string[];
142
- requiredScopes?: string[];
143
- callbackPath?: string;
144
- signingKey?: string;
145
- tokenTtl?: number;
146
- store?: OAuthStore;
147
- }
148
- declare function createOAuthProxy(config: OAuthProxyConfig): OAuthProvider;
149
- //#endregion
150
- //#region src/provider/uri.d.ts
151
- declare function matchRedirectUri(uri: string, patterns: string[]): boolean;
152
- //#endregion
153
- //#region src/store/json-store.d.ts
154
- declare function createJsonStore(path: string): OAuthStore;
155
- //#endregion
156
- //#region src/store/memory-store.d.ts
157
- declare function createMemoryStore(): OAuthStore;
158
- //#endregion
159
- //#region src/store/redis-store.d.ts
160
- interface RedisClient {
161
- get(key: string): Promise<unknown>;
162
- set(key: string, value: string, options?: {
163
- ex?: number;
164
- }): Promise<unknown>;
165
- del(key: string): Promise<unknown>;
166
- }
167
- interface RedisStoreOptions {
168
- client: RedisClient;
169
- prefix?: string;
170
- }
171
- declare function createRedisStore(options: RedisStoreOptions): OAuthStore;
24
+ declare function generateProtectedResourceMetadata(resourceUrl: string, authorizationServers: string[], scopesSupported?: string[]): ProtectedResourceMetadata;
172
25
  //#endregion
173
26
  //#region src/validate.d.ts
174
27
  interface ValidateResult {
@@ -184,5 +37,5 @@ interface ValidateResult {
184
37
  }
185
38
  declare function validateToken(authorizationHeader: string | null | undefined, config: AuthConfig, context: SilkweaveContext): Promise<ValidateResult>;
186
39
  //#endregion
187
- export { AuthCodeData, AuthConfig, AuthError, type AuthInfo, ClientRegistration, GoogleOAuthOptions, OAuthProvider, OAuthProxyConfig, OAuthRequest, OAuthResponse, OAuthStore, PendingAuthData, ProtectedResourceMetadata, RedisClient, RedisStoreOptions, RefreshTokenData, ValidateResult, VerifyToken, buildWWWAuthenticate, createJsonStore, createMemoryStore, createOAuthProxy, createRedisStore, extractBearerToken, generateProtectedResourceMetadata, google, insufficientScope, invalidToken, matchRedirectUri, validateToken };
40
+ export { AuthConfig, AuthError, AuthInfo, type OAuthProvider, type OAuthRequest, type OAuthResponse, ProtectedResourceMetadata, ValidateResult, VerifyToken, buildWWWAuthenticate, extractBearerToken, generateProtectedResourceMetadata, insufficientScope, invalidToken, validateToken };
188
41
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/extract.ts","../src/metadata.ts","../src/provider/types.ts","../src/types.ts","../src/provider/store.ts","../src/provider/google.ts","../src/provider/proxy.ts","../src/provider/uri.ts","../src/store/json-store.ts","../src/store/memory-store.ts","../src/store/redis-store.ts","../src/validate.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/extract.ts","../src/metadata.ts","../src/validate.ts"],"mappings":";;;;cAAa,SAAA,SAAkB,KAAA;EAAA,SAGX,IAAA;EAAA,SACA,UAAA;cAFhB,OAAA,UACgB,IAAA,UACA,UAAA;AAAA;AAAA,iBAOJ,YAAA,CAAa,OAAA,YAAyB,SAAA;AAAA,iBAItC,iBAAA,CAAkB,OAAA,YAA8B,SAAA;;;iBCfhD,kBAAA,CAAmB,MAAA;AAAA,iBAMnB,oBAAA,CACd,KAAA,WACA,WAAA,WACA,mBAAA,WACA,KAAA;;;UCVe,yBAAA;EACf,QAAA;EACA,qBAAA;EACA,gBAAA;EACA,wBAAA;AAAA;AAAA,iBAGc,iCAAA,CACd,WAAA,UACA,oBAAA,YACA,eAAA,cACC,yBAAA;;;UCNc,cAAA;EACf,IAAA,GAAO,QAAA;EACP,KAAA;IACE,UAAA;IACA,OAAA,EAAS,MAAA;IACT,IAAA;MAAQ,KAAA;MAAe,iBAAA;IAAA;EAAA;AAAA;AAAA,iBAIL,aAAA,CACpB,mBAAA,6BACA,MAAA,EAAQ,UAAA,EACR,OAAA,EAAS,gBAAA,GACR,OAAA,CAAQ,cAAA"}