@codelitdev/oauth-server-kit 0.1.0-alpha.1 → 0.1.0-alpha.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.
package/README.md CHANGED
@@ -65,10 +65,10 @@ product requirements and public contract.
65
65
  ## Development gates
66
66
 
67
67
  ```bash
68
- pnpm check-types
69
- pnpm test
70
- pnpm test:coverage
71
- pnpm build
68
+ bun run check-types
69
+ bun test
70
+ bun run test:coverage
71
+ bun run build
72
72
  ```
73
73
 
74
74
  The coverage release gate is 90% statements, lines, and functions and 80%
@@ -57,9 +57,7 @@ async function resolveBetterAuthSession(options, headers) {
57
57
  }
58
58
  }
59
59
  function uniqueRequired(values, field) {
60
- const result = [
61
- ...new Set(values.map((value) => value.trim()).filter(Boolean))
62
- ];
60
+ const result = [...new Set(values.map((value) => value.trim()).filter(Boolean))];
63
61
  if (result.length === 0) {
64
62
  throw new Error(`${field} must contain at least one value`);
65
63
  }
@@ -68,9 +66,7 @@ function uniqueRequired(values, field) {
68
66
  function assertPageLocation(value, field) {
69
67
  if (value.startsWith("/") && !value.startsWith("//")) {
70
68
  if (/\s/.test(value)) {
71
- throw new Error(
72
- `${field} must be an absolute URL or absolute path`
73
- );
69
+ throw new Error(`${field} must be an absolute URL or absolute path`);
74
70
  }
75
71
  return;
76
72
  }
@@ -89,14 +85,10 @@ function assertPageLocation(value, field) {
89
85
  }
90
86
  function assertScopeSubset(values, scopes, field) {
91
87
  if (!values) return void 0;
92
- const normalized = [
93
- ...new Set(values.map((value) => value.trim()).filter(Boolean))
94
- ];
88
+ const normalized = [...new Set(values.map((value) => value.trim()).filter(Boolean))];
95
89
  const invalid = normalized.filter((scope) => !scopes.includes(scope));
96
90
  if (invalid.length > 0) {
97
- throw new Error(
98
- `${field} contains unsupported scopes: ${invalid.join(", ")}`
99
- );
91
+ throw new Error(`${field} contains unsupported scopes: ${invalid.join(", ")}`);
100
92
  }
101
93
  return normalized;
102
94
  }
@@ -105,10 +97,7 @@ function createOAuthProviderOptions(input) {
105
97
  assertPageLocation(input.loginPage, "loginPage");
106
98
  assertPageLocation(input.consentPage, "consentPage");
107
99
  const scopes = uniqueRequired(input.scopes, "scopes");
108
- const validAudiences = uniqueRequired(
109
- input.validAudiences,
110
- "validAudiences"
111
- );
100
+ const validAudiences = uniqueRequired(input.validAudiences, "validAudiences");
112
101
  if (input.allowUnauthenticatedDynamicClientRegistration && !input.allowDynamicClientRegistration) {
113
102
  throw new Error(
114
103
  "unauthenticated dynamic client registration requires dynamic client registration"
@@ -128,7 +117,9 @@ function createOAuthProviderOptions(input) {
128
117
  loginPage: input.loginPage,
129
118
  consentPage: input.consentPage,
130
119
  scopes,
131
- validAudiences,
120
+ resources: validAudiences,
121
+ clientRegistrationDefaultResources: validAudiences,
122
+ clientRegistrationAllowedResources: validAudiences,
132
123
  allowDynamicClientRegistration: (_a = input.allowDynamicClientRegistration) != null ? _a : false,
133
124
  allowUnauthenticatedClientRegistration: (_b = input.allowUnauthenticatedDynamicClientRegistration) != null ? _b : false
134
125
  }, clientRegistrationDefaultScopes ? { clientRegistrationDefaultScopes } : {}), clientRegistrationAllowedScopes ? { clientRegistrationAllowedScopes } : {});
@@ -1,4 +1,4 @@
1
- import { __spreadValues } from './chunk-I4E63NIC.mjs';
1
+ import { __spreadValues } from './chunk-FWCSY2DS.mjs';
2
2
 
3
3
  // src/better-auth.ts
4
4
  function normalizeIssuer(value) {
@@ -40,9 +40,7 @@ async function resolveBetterAuthSession(options, headers) {
40
40
  }
41
41
  }
42
42
  function uniqueRequired(values, field) {
43
- const result = [
44
- ...new Set(values.map((value) => value.trim()).filter(Boolean))
45
- ];
43
+ const result = [...new Set(values.map((value) => value.trim()).filter(Boolean))];
46
44
  if (result.length === 0) {
47
45
  throw new Error(`${field} must contain at least one value`);
48
46
  }
@@ -51,9 +49,7 @@ function uniqueRequired(values, field) {
51
49
  function assertPageLocation(value, field) {
52
50
  if (value.startsWith("/") && !value.startsWith("//")) {
53
51
  if (/\s/.test(value)) {
54
- throw new Error(
55
- `${field} must be an absolute URL or absolute path`
56
- );
52
+ throw new Error(`${field} must be an absolute URL or absolute path`);
57
53
  }
58
54
  return;
59
55
  }
@@ -72,14 +68,10 @@ function assertPageLocation(value, field) {
72
68
  }
73
69
  function assertScopeSubset(values, scopes, field) {
74
70
  if (!values) return void 0;
75
- const normalized = [
76
- ...new Set(values.map((value) => value.trim()).filter(Boolean))
77
- ];
71
+ const normalized = [...new Set(values.map((value) => value.trim()).filter(Boolean))];
78
72
  const invalid = normalized.filter((scope) => !scopes.includes(scope));
79
73
  if (invalid.length > 0) {
80
- throw new Error(
81
- `${field} contains unsupported scopes: ${invalid.join(", ")}`
82
- );
74
+ throw new Error(`${field} contains unsupported scopes: ${invalid.join(", ")}`);
83
75
  }
84
76
  return normalized;
85
77
  }
@@ -88,10 +80,7 @@ function createOAuthProviderOptions(input) {
88
80
  assertPageLocation(input.loginPage, "loginPage");
89
81
  assertPageLocation(input.consentPage, "consentPage");
90
82
  const scopes = uniqueRequired(input.scopes, "scopes");
91
- const validAudiences = uniqueRequired(
92
- input.validAudiences,
93
- "validAudiences"
94
- );
83
+ const validAudiences = uniqueRequired(input.validAudiences, "validAudiences");
95
84
  if (input.allowUnauthenticatedDynamicClientRegistration && !input.allowDynamicClientRegistration) {
96
85
  throw new Error(
97
86
  "unauthenticated dynamic client registration requires dynamic client registration"
@@ -111,7 +100,9 @@ function createOAuthProviderOptions(input) {
111
100
  loginPage: input.loginPage,
112
101
  consentPage: input.consentPage,
113
102
  scopes,
114
- validAudiences,
103
+ resources: validAudiences,
104
+ clientRegistrationDefaultResources: validAudiences,
105
+ clientRegistrationAllowedResources: validAudiences,
115
106
  allowDynamicClientRegistration: (_a = input.allowDynamicClientRegistration) != null ? _a : false,
116
107
  allowUnauthenticatedClientRegistration: (_b = input.allowUnauthenticatedDynamicClientRegistration) != null ? _b : false
117
108
  }, clientRegistrationDefaultScopes ? { clientRegistrationDefaultScopes } : {}), clientRegistrationAllowedScopes ? { clientRegistrationAllowedScopes } : {});
@@ -17,5 +17,17 @@ var __spreadValues = (a, b) => {
17
17
  return a;
18
18
  };
19
19
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+ var __objRest = (source, exclude) => {
21
+ var target = {};
22
+ for (var prop in source)
23
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
24
+ target[prop] = source[prop];
25
+ if (source != null && __getOwnPropSymbols)
26
+ for (var prop of __getOwnPropSymbols(source)) {
27
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
28
+ target[prop] = source[prop];
29
+ }
30
+ return target;
31
+ };
20
32
 
21
- export { __spreadProps, __spreadValues };
33
+ export { __objRest, __spreadProps, __spreadValues };
@@ -1,4 +1,4 @@
1
- import { __spreadProps, __spreadValues } from './chunk-I4E63NIC.mjs';
1
+ import { __spreadProps, __spreadValues } from './chunk-FWCSY2DS.mjs';
2
2
 
3
3
  // src/verify-access-token.ts
4
4
  function requireAbsoluteUrl(value, field) {
@@ -44,16 +44,14 @@ async function verifyOAuthAccessToken(options, token) {
44
44
  const audiences = normalizedUniqueStrings(options.audiences);
45
45
  if (!token.trim()) return { status: "invalid_token" };
46
46
  try {
47
- const claims = await options.oauthResourceClient.getActions().verifyAccessToken(token, {
47
+ const claims = await options.oauthResourceClient.getActions().verifyBearerToken(token, {
48
48
  verifyOptions: { issuer, audience: audiences },
49
49
  resourceMetadataMappings: (_a = options.resourceMetadataMappings) != null ? _a : {}
50
50
  });
51
51
  const subject = optionalString(claims.sub);
52
52
  const claimIssuer = optionalString(claims.iss);
53
53
  const clientId = (_b = optionalString(claims.azp)) != null ? _b : optionalString(claims.client_id);
54
- const tokenAudiences = normalizedUniqueStrings(
55
- claimStrings(claims.aud)
56
- );
54
+ const tokenAudiences = normalizedUniqueStrings(claimStrings(claims.aud));
57
55
  const validatedAudiences = tokenAudiences.filter(
58
56
  (audience) => audiences.includes(audience)
59
57
  );
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler, Router } from 'express';
2
- import { a as AuthenticatedIdentity } from './types-DJxCmhYu.mjs';
2
+ import { a as AuthenticatedIdentity, A as AuthenticationResult } from './types-DJxCmhYu.mjs';
3
3
  import { VerifyOAuthAccessTokenOptions } from './index.mjs';
4
4
  import '@better-auth/oauth-provider/resource-client';
5
5
 
@@ -12,6 +12,7 @@ declare global {
12
12
  }
13
13
  interface CreateOAuthBearerMiddlewareOptions extends VerifyOAuthAccessTokenOptions {
14
14
  resourceMetadataUrl?: string;
15
+ verifyAccessToken?: (options: VerifyOAuthAccessTokenOptions, token: string) => Promise<AuthenticationResult>;
15
16
  }
16
17
  declare function createOAuthBearerMiddleware(options: CreateOAuthBearerMiddlewareOptions): RequestHandler;
17
18
 
package/dist/express.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { RequestHandler, Router } from 'express';
2
- import { a as AuthenticatedIdentity } from './types-DJxCmhYu.js';
2
+ import { a as AuthenticatedIdentity, A as AuthenticationResult } from './types-DJxCmhYu.js';
3
3
  import { VerifyOAuthAccessTokenOptions } from './index.js';
4
4
  import '@better-auth/oauth-provider/resource-client';
5
5
 
@@ -12,6 +12,7 @@ declare global {
12
12
  }
13
13
  interface CreateOAuthBearerMiddlewareOptions extends VerifyOAuthAccessTokenOptions {
14
14
  resourceMetadataUrl?: string;
15
+ verifyAccessToken?: (options: VerifyOAuthAccessTokenOptions, token: string) => Promise<AuthenticationResult>;
15
16
  }
16
17
  declare function createOAuthBearerMiddleware(options: CreateOAuthBearerMiddlewareOptions): RequestHandler;
17
18
 
package/dist/express.js CHANGED
@@ -21,6 +21,18 @@ var __spreadValues = (a, b) => {
21
21
  return a;
22
22
  };
23
23
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
24
+ var __objRest = (source, exclude) => {
25
+ var target = {};
26
+ for (var prop in source)
27
+ if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0)
28
+ target[prop] = source[prop];
29
+ if (source != null && __getOwnPropSymbols)
30
+ for (var prop of __getOwnPropSymbols(source)) {
31
+ if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop))
32
+ target[prop] = source[prop];
33
+ }
34
+ return target;
35
+ };
24
36
 
25
37
  // src/verify-access-token.ts
26
38
  function requireAbsoluteUrl(value, field) {
@@ -66,16 +78,14 @@ async function verifyOAuthAccessToken(options, token) {
66
78
  const audiences = normalizedUniqueStrings(options.audiences);
67
79
  if (!token.trim()) return { status: "invalid_token" };
68
80
  try {
69
- const claims = await options.oauthResourceClient.getActions().verifyAccessToken(token, {
81
+ const claims = await options.oauthResourceClient.getActions().verifyBearerToken(token, {
70
82
  verifyOptions: { issuer, audience: audiences },
71
83
  resourceMetadataMappings: (_a = options.resourceMetadataMappings) != null ? _a : {}
72
84
  });
73
85
  const subject = optionalString(claims.sub);
74
86
  const claimIssuer = optionalString(claims.iss);
75
87
  const clientId = (_b = optionalString(claims.azp)) != null ? _b : optionalString(claims.client_id);
76
- const tokenAudiences = normalizedUniqueStrings(
77
- claimStrings(claims.aud)
78
- );
88
+ const tokenAudiences = normalizedUniqueStrings(claimStrings(claims.aud));
79
89
  const validatedAudiences = tokenAudiences.filter(
80
90
  (audience) => audiences.includes(audience)
81
91
  );
@@ -142,7 +152,8 @@ function bearerToken(request) {
142
152
  return ((_a = match == null ? void 0 : match[1]) == null ? void 0 : _a.trim()) || null;
143
153
  }
144
154
  function createOAuthBearerMiddleware(options) {
145
- validateOAuthVerificationOptions(options);
155
+ const _a = options, { verifyAccessToken = verifyOAuthAccessToken } = _a, verificationOptions = __objRest(_a, ["verifyAccessToken"]);
156
+ validateOAuthVerificationOptions(verificationOptions);
146
157
  if (options.resourceMetadataUrl) {
147
158
  let metadataUrl;
148
159
  try {
@@ -167,13 +178,9 @@ function createOAuthBearerMiddleware(options) {
167
178
  );
168
179
  return;
169
180
  }
170
- const result = await verifyOAuthAccessToken(options, token);
181
+ const result = await verifyAccessToken(verificationOptions, token);
171
182
  if (result.status !== "authenticated") {
172
- sendAuthenticationError(
173
- response,
174
- result,
175
- options.resourceMetadataUrl
176
- );
183
+ sendAuthenticationError(response, result, options.resourceMetadataUrl);
177
184
  return;
178
185
  }
179
186
  request.auth = result.identity;
@@ -283,9 +290,7 @@ function normalizeOptions(options) {
283
290
  for (const method of options.loginMethods) {
284
291
  if (method.type === "social") {
285
292
  if (!method.providerId.trim() || !method.label.trim()) {
286
- throw new Error(
287
- "social login methods require providerId and label"
288
- );
293
+ throw new Error("social login methods require providerId and label");
289
294
  }
290
295
  }
291
296
  }
package/dist/express.mjs CHANGED
@@ -1,5 +1,5 @@
1
- import { validateOAuthVerificationOptions, verifyOAuthAccessToken } from './chunk-RJ4ABQXG.mjs';
2
- import { __spreadProps, __spreadValues } from './chunk-I4E63NIC.mjs';
1
+ import { verifyOAuthAccessToken, validateOAuthVerificationOptions } from './chunk-JENFPLCB.mjs';
2
+ import { __objRest, __spreadProps, __spreadValues } from './chunk-FWCSY2DS.mjs';
3
3
  import { Router } from 'express';
4
4
 
5
5
  // src/express.ts
@@ -39,7 +39,8 @@ function bearerToken(request) {
39
39
  return ((_a = match == null ? void 0 : match[1]) == null ? void 0 : _a.trim()) || null;
40
40
  }
41
41
  function createOAuthBearerMiddleware(options) {
42
- validateOAuthVerificationOptions(options);
42
+ const _a = options, { verifyAccessToken = verifyOAuthAccessToken } = _a, verificationOptions = __objRest(_a, ["verifyAccessToken"]);
43
+ validateOAuthVerificationOptions(verificationOptions);
43
44
  if (options.resourceMetadataUrl) {
44
45
  let metadataUrl;
45
46
  try {
@@ -64,13 +65,9 @@ function createOAuthBearerMiddleware(options) {
64
65
  );
65
66
  return;
66
67
  }
67
- const result = await verifyOAuthAccessToken(options, token);
68
+ const result = await verifyAccessToken(verificationOptions, token);
68
69
  if (result.status !== "authenticated") {
69
- sendAuthenticationError(
70
- response,
71
- result,
72
- options.resourceMetadataUrl
73
- );
70
+ sendAuthenticationError(response, result, options.resourceMetadataUrl);
74
71
  return;
75
72
  }
76
73
  request.auth = result.identity;
@@ -180,9 +177,7 @@ function normalizeOptions(options) {
180
177
  for (const method of options.loginMethods) {
181
178
  if (method.type === "social") {
182
179
  if (!method.providerId.trim() || !method.label.trim()) {
183
- throw new Error(
184
- "social login methods require providerId and label"
185
- );
180
+ throw new Error("social login methods require providerId and label");
186
181
  }
187
182
  }
188
183
  }
package/dist/index.js CHANGED
@@ -64,16 +64,14 @@ async function verifyOAuthAccessToken(options, token) {
64
64
  const audiences = normalizedUniqueStrings(options.audiences);
65
65
  if (!token.trim()) return { status: "invalid_token" };
66
66
  try {
67
- const claims = await options.oauthResourceClient.getActions().verifyAccessToken(token, {
67
+ const claims = await options.oauthResourceClient.getActions().verifyBearerToken(token, {
68
68
  verifyOptions: { issuer, audience: audiences },
69
69
  resourceMetadataMappings: (_a = options.resourceMetadataMappings) != null ? _a : {}
70
70
  });
71
71
  const subject = optionalString(claims.sub);
72
72
  const claimIssuer = optionalString(claims.iss);
73
73
  const clientId = (_b = optionalString(claims.azp)) != null ? _b : optionalString(claims.client_id);
74
- const tokenAudiences = normalizedUniqueStrings(
75
- claimStrings(claims.aud)
76
- );
74
+ const tokenAudiences = normalizedUniqueStrings(claimStrings(claims.aud));
77
75
  const validatedAudiences = tokenAudiences.filter(
78
76
  (audience) => audiences.includes(audience)
79
77
  );
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- export { verifyOAuthAccessToken } from './chunk-RJ4ABQXG.mjs';
2
- import './chunk-I4E63NIC.mjs';
1
+ export { verifyOAuthAccessToken } from './chunk-JENFPLCB.mjs';
2
+ import './chunk-FWCSY2DS.mjs';
package/dist/mcp.d.mts CHANGED
@@ -18,6 +18,10 @@ interface CreateMcpOAuthDiscoveryRoutesOptions {
18
18
  resourceUrl: string;
19
19
  scopesSupported: readonly string[];
20
20
  allowedOrigins: readonly string[] | "*";
21
+ metadataHandlers?: {
22
+ authorizationServer: (auth: BetterAuthMetadataApi) => (request: Request) => Promise<Response>;
23
+ openId: (auth: BetterAuthMetadataApi) => (request: Request) => Promise<Response>;
24
+ };
21
25
  }
22
26
  declare function createMcpOAuthDiscoveryRoutes(rawOptions: CreateMcpOAuthDiscoveryRoutesOptions): Router;
23
27
 
package/dist/mcp.d.ts CHANGED
@@ -18,6 +18,10 @@ interface CreateMcpOAuthDiscoveryRoutesOptions {
18
18
  resourceUrl: string;
19
19
  scopesSupported: readonly string[];
20
20
  allowedOrigins: readonly string[] | "*";
21
+ metadataHandlers?: {
22
+ authorizationServer: (auth: BetterAuthMetadataApi) => (request: Request) => Promise<Response>;
23
+ openId: (auth: BetterAuthMetadataApi) => (request: Request) => Promise<Response>;
24
+ };
21
25
  }
22
26
  declare function createMcpOAuthDiscoveryRoutes(rawOptions: CreateMcpOAuthDiscoveryRoutesOptions): Router;
23
27
 
package/dist/mcp.js CHANGED
@@ -33,9 +33,7 @@ function normalizeOptions(options) {
33
33
  throw new Error("resourceUrl must use http or https");
34
34
  }
35
35
  if (resource.username || resource.password || resource.search || resource.hash) {
36
- throw new Error(
37
- "resourceUrl must not include credentials, query, or fragment"
38
- );
36
+ throw new Error("resourceUrl must not include credentials, query, or fragment");
39
37
  }
40
38
  if (process.env.NODE_ENV === "production" && resource.protocol !== "https:") {
41
39
  throw new Error("resourceUrl must use https in production");
@@ -65,9 +63,7 @@ function normalizeOptions(options) {
65
63
  const authorizationServerPath = rawAuthorizationServerPath === "/" ? "" : rawAuthorizationServerPath.replace(/\/+$/, "");
66
64
  const authorizationServerUrl = `${authorizationServerBase.toString().replace(/\/$/, "")}${authorizationServerPath}`;
67
65
  const scopesSupported = [
68
- ...new Set(
69
- options.scopesSupported.map((scope) => scope.trim()).filter(Boolean)
70
- )
66
+ ...new Set(options.scopesSupported.map((scope) => scope.trim()).filter(Boolean))
71
67
  ];
72
68
  const allowedOrigins = options.allowedOrigins === "*" ? "*" : new Set(
73
69
  options.allowedOrigins.map((origin) => {
@@ -75,24 +71,16 @@ function normalizeOptions(options) {
75
71
  try {
76
72
  url = new URL(origin);
77
73
  } catch (e) {
78
- throw new Error(
79
- "allowedOrigins must contain absolute origins"
80
- );
74
+ throw new Error("allowedOrigins must contain absolute origins");
81
75
  }
82
76
  if (!["http:", "https:"].includes(url.protocol)) {
83
- throw new Error(
84
- "allowedOrigins must use http or https"
85
- );
77
+ throw new Error("allowedOrigins must use http or https");
86
78
  }
87
79
  if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
88
- throw new Error(
89
- "allowedOrigins must contain origins without paths"
90
- );
80
+ throw new Error("allowedOrigins must contain origins without paths");
91
81
  }
92
82
  if (process.env.NODE_ENV === "production" && url.protocol !== "https:") {
93
- throw new Error(
94
- "allowedOrigins must use https in production"
95
- );
83
+ throw new Error("allowedOrigins must use https in production");
96
84
  }
97
85
  return url.origin;
98
86
  })
@@ -128,9 +116,9 @@ function applyCors(request, response, allowedOrigins) {
128
116
  }
129
117
  async function sendFetchResponse(response, fetchResponse) {
130
118
  response.status(fetchResponse.status);
131
- fetchResponse.headers.forEach(
132
- (value, key) => response.setHeader(key, value)
133
- );
119
+ fetchResponse.headers.forEach((value, key) => {
120
+ response.setHeader(key, value);
121
+ });
134
122
  response.send(await fetchResponse.text());
135
123
  }
136
124
  function asyncHandler(handler) {
@@ -149,10 +137,7 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
149
137
  "/.well-known/openid-configuration",
150
138
  `${options.authorizationServerPath}/.well-known/openid-configuration`
151
139
  ]);
152
- const resourcePath = new URL(options.resourceUrl).pathname.replace(
153
- /\/$/,
154
- ""
155
- );
140
+ const resourcePath = new URL(options.resourceUrl).pathname.replace(/\/$/, "");
156
141
  const protectedResourcePaths = /* @__PURE__ */ new Set([
157
142
  "/.well-known/oauth-protected-resource",
158
143
  `/.well-known/oauth-protected-resource${resourcePath}`
@@ -178,7 +163,8 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
178
163
  next();
179
164
  });
180
165
  async function authorizationServerMetadata(request, response) {
181
- const handler = oauthProvider.oauthProviderAuthServerMetadata(options.auth);
166
+ var _a, _b;
167
+ const handler = ((_b = (_a = options.metadataHandlers) == null ? void 0 : _a.authorizationServer) != null ? _b : oauthProvider.oauthProviderAuthServerMetadata)(options.auth);
182
168
  await sendFetchResponse(
183
169
  response,
184
170
  await handler(
@@ -190,7 +176,8 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
190
176
  );
191
177
  }
192
178
  async function openIdMetadata(request, response) {
193
- const handler = oauthProvider.oauthProviderOpenIdConfigMetadata(options.auth);
179
+ var _a, _b;
180
+ const handler = ((_b = (_a = options.metadataHandlers) == null ? void 0 : _a.openId) != null ? _b : oauthProvider.oauthProviderOpenIdConfigMetadata)(options.auth);
194
181
  await sendFetchResponse(
195
182
  response,
196
183
  await handler(
@@ -208,15 +195,12 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
208
195
  router.get(path, asyncHandler(openIdMetadata));
209
196
  }
210
197
  async function protectedResourceMetadata(_request, response) {
211
- const metadata = await options.oauthResourceClient.getActions().getProtectedResourceMetadata(
212
- {
213
- resource: options.resourceUrl,
214
- authorization_servers: [options.authorizationServerUrl],
215
- scopes_supported: options.scopesSupported,
216
- bearer_methods_supported: ["header"]
217
- },
218
- { silenceWarnings: { oidcScopes: true } }
219
- );
198
+ const metadata = await options.oauthResourceClient.getActions().getProtectedResourceMetadata({
199
+ resource: options.resourceUrl,
200
+ authorization_servers: [options.authorizationServerUrl],
201
+ scopes_supported: options.scopesSupported,
202
+ bearer_methods_supported: ["header"]
203
+ });
220
204
  response.json(metadata);
221
205
  }
222
206
  for (const path of protectedResourcePaths) {
package/dist/mcp.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { __spreadProps, __spreadValues } from './chunk-I4E63NIC.mjs';
1
+ import { __spreadProps, __spreadValues } from './chunk-FWCSY2DS.mjs';
2
2
  import { oauthProviderAuthServerMetadata, oauthProviderOpenIdConfigMetadata } from '@better-auth/oauth-provider';
3
3
  import { Router } from 'express';
4
4
 
@@ -13,9 +13,7 @@ function normalizeOptions(options) {
13
13
  throw new Error("resourceUrl must use http or https");
14
14
  }
15
15
  if (resource.username || resource.password || resource.search || resource.hash) {
16
- throw new Error(
17
- "resourceUrl must not include credentials, query, or fragment"
18
- );
16
+ throw new Error("resourceUrl must not include credentials, query, or fragment");
19
17
  }
20
18
  if (process.env.NODE_ENV === "production" && resource.protocol !== "https:") {
21
19
  throw new Error("resourceUrl must use https in production");
@@ -45,9 +43,7 @@ function normalizeOptions(options) {
45
43
  const authorizationServerPath = rawAuthorizationServerPath === "/" ? "" : rawAuthorizationServerPath.replace(/\/+$/, "");
46
44
  const authorizationServerUrl = `${authorizationServerBase.toString().replace(/\/$/, "")}${authorizationServerPath}`;
47
45
  const scopesSupported = [
48
- ...new Set(
49
- options.scopesSupported.map((scope) => scope.trim()).filter(Boolean)
50
- )
46
+ ...new Set(options.scopesSupported.map((scope) => scope.trim()).filter(Boolean))
51
47
  ];
52
48
  const allowedOrigins = options.allowedOrigins === "*" ? "*" : new Set(
53
49
  options.allowedOrigins.map((origin) => {
@@ -55,24 +51,16 @@ function normalizeOptions(options) {
55
51
  try {
56
52
  url = new URL(origin);
57
53
  } catch (e) {
58
- throw new Error(
59
- "allowedOrigins must contain absolute origins"
60
- );
54
+ throw new Error("allowedOrigins must contain absolute origins");
61
55
  }
62
56
  if (!["http:", "https:"].includes(url.protocol)) {
63
- throw new Error(
64
- "allowedOrigins must use http or https"
65
- );
57
+ throw new Error("allowedOrigins must use http or https");
66
58
  }
67
59
  if (url.username || url.password || url.pathname !== "/" || url.search || url.hash) {
68
- throw new Error(
69
- "allowedOrigins must contain origins without paths"
70
- );
60
+ throw new Error("allowedOrigins must contain origins without paths");
71
61
  }
72
62
  if (process.env.NODE_ENV === "production" && url.protocol !== "https:") {
73
- throw new Error(
74
- "allowedOrigins must use https in production"
75
- );
63
+ throw new Error("allowedOrigins must use https in production");
76
64
  }
77
65
  return url.origin;
78
66
  })
@@ -108,9 +96,9 @@ function applyCors(request, response, allowedOrigins) {
108
96
  }
109
97
  async function sendFetchResponse(response, fetchResponse) {
110
98
  response.status(fetchResponse.status);
111
- fetchResponse.headers.forEach(
112
- (value, key) => response.setHeader(key, value)
113
- );
99
+ fetchResponse.headers.forEach((value, key) => {
100
+ response.setHeader(key, value);
101
+ });
114
102
  response.send(await fetchResponse.text());
115
103
  }
116
104
  function asyncHandler(handler) {
@@ -129,10 +117,7 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
129
117
  "/.well-known/openid-configuration",
130
118
  `${options.authorizationServerPath}/.well-known/openid-configuration`
131
119
  ]);
132
- const resourcePath = new URL(options.resourceUrl).pathname.replace(
133
- /\/$/,
134
- ""
135
- );
120
+ const resourcePath = new URL(options.resourceUrl).pathname.replace(/\/$/, "");
136
121
  const protectedResourcePaths = /* @__PURE__ */ new Set([
137
122
  "/.well-known/oauth-protected-resource",
138
123
  `/.well-known/oauth-protected-resource${resourcePath}`
@@ -158,7 +143,8 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
158
143
  next();
159
144
  });
160
145
  async function authorizationServerMetadata(request, response) {
161
- const handler = oauthProviderAuthServerMetadata(options.auth);
146
+ var _a, _b;
147
+ const handler = ((_b = (_a = options.metadataHandlers) == null ? void 0 : _a.authorizationServer) != null ? _b : oauthProviderAuthServerMetadata)(options.auth);
162
148
  await sendFetchResponse(
163
149
  response,
164
150
  await handler(
@@ -170,7 +156,8 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
170
156
  );
171
157
  }
172
158
  async function openIdMetadata(request, response) {
173
- const handler = oauthProviderOpenIdConfigMetadata(options.auth);
159
+ var _a, _b;
160
+ const handler = ((_b = (_a = options.metadataHandlers) == null ? void 0 : _a.openId) != null ? _b : oauthProviderOpenIdConfigMetadata)(options.auth);
174
161
  await sendFetchResponse(
175
162
  response,
176
163
  await handler(
@@ -188,15 +175,12 @@ function createMcpOAuthDiscoveryRoutes(rawOptions) {
188
175
  router.get(path, asyncHandler(openIdMetadata));
189
176
  }
190
177
  async function protectedResourceMetadata(_request, response) {
191
- const metadata = await options.oauthResourceClient.getActions().getProtectedResourceMetadata(
192
- {
193
- resource: options.resourceUrl,
194
- authorization_servers: [options.authorizationServerUrl],
195
- scopes_supported: options.scopesSupported,
196
- bearer_methods_supported: ["header"]
197
- },
198
- { silenceWarnings: { oidcScopes: true } }
199
- );
178
+ const metadata = await options.oauthResourceClient.getActions().getProtectedResourceMetadata({
179
+ resource: options.resourceUrl,
180
+ authorization_servers: [options.authorizationServerUrl],
181
+ scopes_supported: options.scopesSupported,
182
+ bearer_methods_supported: ["header"]
183
+ });
200
184
  response.json(metadata);
201
185
  }
202
186
  for (const path of protectedResourcePaths) {
package/package.json CHANGED
@@ -1,101 +1,101 @@
1
1
  {
2
- "name": "@codelitdev/oauth-server-kit",
3
- "version": "0.1.0-alpha.1",
4
- "description": "Lean Better Auth OAuth authentication framework for web, mobile, REST, and MCP surfaces.",
5
- "author": "CodeLit",
6
- "license": "MIT",
7
- "main": "dist/index.js",
8
- "types": "dist/index.d.ts",
9
- "files": [
10
- "dist"
11
- ],
12
- "exports": {
13
- ".": {
14
- "import": {
15
- "types": "./dist/index.d.mts",
16
- "default": "./dist/index.mjs"
17
- },
18
- "require": {
19
- "types": "./dist/index.d.ts",
20
- "default": "./dist/index.js"
21
- }
22
- },
23
- "./better-auth": {
24
- "import": {
25
- "types": "./dist/better-auth.d.mts",
26
- "default": "./dist/better-auth.mjs"
27
- },
28
- "require": {
29
- "types": "./dist/better-auth.d.ts",
30
- "default": "./dist/better-auth.js"
31
- }
32
- },
33
- "./express": {
34
- "import": {
35
- "types": "./dist/express.d.mts",
36
- "default": "./dist/express.mjs"
37
- },
38
- "require": {
39
- "types": "./dist/express.d.ts",
40
- "default": "./dist/express.js"
41
- }
42
- },
43
- "./mcp": {
44
- "import": {
45
- "types": "./dist/mcp.d.mts",
46
- "default": "./dist/mcp.mjs"
47
- },
48
- "require": {
49
- "types": "./dist/mcp.d.ts",
50
- "default": "./dist/mcp.js"
51
- }
52
- }
2
+ "name": "@codelitdev/oauth-server-kit",
3
+ "version": "0.1.0-alpha.2",
4
+ "description": "Lean Better Auth OAuth authentication framework for web, mobile, REST, and MCP surfaces.",
5
+ "author": "CodeLit",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/codelitdev/platform.git",
10
+ "directory": "packages/oauth-server-kit"
11
+ },
12
+ "homepage": "https://github.com/codelitdev/platform/tree/main/packages/oauth-server-kit#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/codelitdev/platform/issues"
15
+ },
16
+ "main": "dist/index.js",
17
+ "types": "dist/index.d.ts",
18
+ "files": [
19
+ "dist"
20
+ ],
21
+ "exports": {
22
+ ".": {
23
+ "import": {
24
+ "types": "./dist/index.d.mts",
25
+ "default": "./dist/index.mjs"
26
+ },
27
+ "require": {
28
+ "types": "./dist/index.d.ts",
29
+ "default": "./dist/index.js"
30
+ }
53
31
  },
54
- "scripts": {
55
- "clean": "rimraf dist/",
56
- "build": "tsup",
57
- "dev": "tsup --watch",
58
- "check-types": "tsc --noEmit",
59
- "test": "vitest run",
60
- "test:watch": "vitest",
61
- "test:coverage": "vitest run --coverage",
62
- "lint": "eslint src test --quiet",
63
- "lint:fix": "pnpm lint --fix",
64
- "prettier": "prettier --write src test docs *.md *.json",
65
- "format": "pnpm prettier",
66
- "format:check": "prettier --check src test docs *.md *.json",
67
- "quality": "pnpm format:check && pnpm lint && pnpm check-types",
68
- "prepare": "husky",
69
- "release:alpha": "pnpm quality && pnpm test:coverage && pnpm build && pnpm publish --tag alpha --access public --no-git-checks"
32
+ "./better-auth": {
33
+ "import": {
34
+ "types": "./dist/better-auth.d.mts",
35
+ "default": "./dist/better-auth.mjs"
36
+ },
37
+ "require": {
38
+ "types": "./dist/better-auth.d.ts",
39
+ "default": "./dist/better-auth.js"
40
+ }
70
41
  },
71
- "publishConfig": {
72
- "access": "public",
73
- "tag": "alpha"
42
+ "./express": {
43
+ "import": {
44
+ "types": "./dist/express.d.mts",
45
+ "default": "./dist/express.mjs"
46
+ },
47
+ "require": {
48
+ "types": "./dist/express.d.ts",
49
+ "default": "./dist/express.js"
50
+ }
74
51
  },
75
- "peerDependencies": {
76
- "@better-auth/oauth-provider": "^1.6.23",
77
- "better-auth": "^1.6.23",
78
- "express": "^4.21.2"
79
- },
80
- "devDependencies": {
81
- "@better-auth/oauth-provider": "^1.6.23",
82
- "@types/express": "^4.17.20",
83
- "@types/node": "^22.14.1",
84
- "@vitest/coverage-v8": "3.2.7",
85
- "better-auth": "^1.6.23",
86
- "eslint": "^10.8.0",
87
- "eslint-config-prettier": "^10.1.8",
88
- "eslint-plugin-unused-imports": "^4.3.0",
89
- "express": "^4.21.2",
90
- "globals": "^15.15.0",
91
- "husky": "^9.1.7",
92
- "lint-staged": "^15.2.2",
93
- "prettier": "^3.9.6",
94
- "rimraf": "^5.0.0",
95
- "tsup": "^8.3.0",
96
- "typescript": "^5.9.3",
97
- "typescript-eslint": "^8.46.0",
98
- "vitest": "^3.2.7"
99
- },
100
- "packageManager": "pnpm@11.10.0"
52
+ "./mcp": {
53
+ "import": {
54
+ "types": "./dist/mcp.d.mts",
55
+ "default": "./dist/mcp.mjs"
56
+ },
57
+ "require": {
58
+ "types": "./dist/mcp.d.ts",
59
+ "default": "./dist/mcp.js"
60
+ }
61
+ }
62
+ },
63
+ "scripts": {
64
+ "clean": "rimraf dist/",
65
+ "build": "tsup",
66
+ "dev": "tsup --watch",
67
+ "check-types": "tsc -p tsconfig.test.json --noEmit",
68
+ "test": "bun test --timeout 60000 src",
69
+ "test:watch": "bun test --watch --timeout 60000 src",
70
+ "test:coverage": "bun test --coverage --timeout 60000 src",
71
+ "lint": "biome lint .",
72
+ "lint:fix": "biome lint --write .",
73
+ "format": "biome format --write .",
74
+ "format:check": "biome ci --linter-enabled=false .",
75
+ "quality": "bun run format:check && bun run lint && bun run check-types"
76
+ },
77
+ "publishConfig": {
78
+ "access": "public",
79
+ "tag": "latest"
80
+ },
81
+ "peerDependencies": {
82
+ "@better-auth/oauth-provider": "^1.7.2",
83
+ "better-auth": "^1.7.2",
84
+ "express": "^4.21.2"
85
+ },
86
+ "devDependencies": {
87
+ "@better-auth/core": "1.7.2",
88
+ "@better-auth/oauth-provider": "1.7.2",
89
+ "@better-auth/utils": "0.4.2",
90
+ "@better-fetch/fetch": "1.3.1",
91
+ "@types/express": "^4.17.20",
92
+ "@types/node": "^22.14.1",
93
+ "@types/bun": "^1.4.1",
94
+ "better-auth": "1.7.2",
95
+ "better-call": "1.4.0",
96
+ "express": "^4.21.2",
97
+ "rimraf": "^5.0.0",
98
+ "tsup": "^8.3.0",
99
+ "typescript": "^5.9.3"
100
+ }
101
101
  }