@ttoss/http-server-auth 0.6.3 → 0.7.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
@@ -173,3 +173,9 @@ path when the app versions its API; individual paths are overridable through
173
173
  ## OAuth authorization server
174
174
 
175
175
  The package also ships `oauthServer()` — a Koa `Router` that issues tokens (`/authorize`, `/token`, `/register`, discovery), a thin adapter over `createOAuthHandlers` from [`@ttoss/auth-core`](https://ttoss.dev/docs/modules/packages/auth-core). Pair it with the `oauth` verification strategy above when one deployment both issues and verifies. See the [OAuth Authorization Server](https://ttoss.dev/docs/engineering/guidelines/oauth-authorization-server) guideline.
176
+
177
+ ### Protected resource metadata (RFC 9728)
178
+
179
+ Passing `resource` to `oauthServer()` serves the protected-resource metadata document; `createProtectedResourceMetadataMiddleware` serves the same document when you bring your own auth middleware. Both answer at **every** location RFC 9728 defines for that resource — the root, plus the path-derived `/.well-known/oauth-protected-resource<path>` when the resource identifier carries a path, since §3.1 inserts the well-known segment between host and path. The locations and the document body come from `protectedResourceMetadataPaths` / `protectedResourceMetadataDocument` in `@ttoss/auth-core` (re-exported here), which is also what `getWwwAuthenticateHeader` derives its URL from — so the header and the routes cannot disagree.
180
+
181
+ Mount either **before** `authMiddleware`: clients fetch discovery before they have a token.
package/dist/index.cjs CHANGED
@@ -295,7 +295,9 @@ var oauthServer = options => {
295
295
  applyResponse(ctx, engine.authorizationServerMetadata());
296
296
  });
297
297
  const prm = engine.protectedResourceMetadata();
298
- if (prm) router.get("/.well-known/oauth-protected-resource", ctx => {
298
+ if (prm && options.resource) for (const metadataPath of (0, _ttoss_auth_core.protectedResourceMetadataPaths)({
299
+ resource: options.resource
300
+ })) router.get(metadataPath, ctx => {
299
301
  applyResponse(ctx, prm);
300
302
  });
301
303
  router.get(engine.paths.authorize, async ctx => {
@@ -310,17 +312,25 @@ var oauthServer = options => {
310
312
  return router;
311
313
  };
312
314
  /**
313
- * Koa middleware that serves `GET /.well-known/oauth-protected-resource`
314
- * (RFC 9728). Mount it **before** `authMiddleware` so the discovery endpoint
315
+ * Koa middleware that serves the RFC 9728 Protected Resource Metadata
316
+ * document. Mount it **before** `authMiddleware` so the discovery endpoint
315
317
  * stays unauthenticated (clients fetch it before they have a token).
318
+ *
319
+ * It answers at every location `protectedResourceMetadataPaths` derives for
320
+ * the resource: the root, plus the path-derived location of RFC 9728 §3.1 when
321
+ * the resource identifier carries a path.
316
322
  */
317
323
  var createProtectedResourceMetadataMiddleware = args => {
324
+ const metadataPaths = new Set((0, _ttoss_auth_core.protectedResourceMetadataPaths)({
325
+ resource: args.resource
326
+ }));
327
+ const body = (0, _ttoss_auth_core.protectedResourceMetadataDocument)({
328
+ resource: args.resource,
329
+ authorizationServers: args.authorizationServers
330
+ });
318
331
  return async (ctx, next) => {
319
- if (ctx.method === "GET" && ctx.path === "/.well-known/oauth-protected-resource") {
320
- ctx.body = {
321
- resource: args.resource,
322
- authorization_servers: args.authorizationServers
323
- };
332
+ if (ctx.method === "GET" && metadataPaths.has(ctx.path)) {
333
+ ctx.body = body;
324
334
  return;
325
335
  }
326
336
  await next();
@@ -379,4 +389,22 @@ Object.defineProperty(exports, 'normalizeEmail', {
379
389
  }
380
390
  });
381
391
  exports.oauthServer = oauthServer;
392
+ Object.defineProperty(exports, 'protectedResourceMetadataDocument', {
393
+ enumerable: true,
394
+ get: function () {
395
+ return _ttoss_auth_core.protectedResourceMetadataDocument;
396
+ }
397
+ });
398
+ Object.defineProperty(exports, 'protectedResourceMetadataPaths', {
399
+ enumerable: true,
400
+ get: function () {
401
+ return _ttoss_auth_core.protectedResourceMetadataPaths;
402
+ }
403
+ });
404
+ Object.defineProperty(exports, 'protectedResourceMetadataUrl', {
405
+ enumerable: true,
406
+ get: function () {
407
+ return _ttoss_auth_core.protectedResourceMetadataUrl;
408
+ }
409
+ });
382
410
  exports.requireAuth = requireAuth;
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
 
2
2
  import { Context, Middleware, Next, Router } from "@ttoss/http-server";
3
- import { AuthCodeStore, AuthorizeRequest, ClientStore, EmailAuthDelivery, EmailAuthErrorCode, EmailAuthHandler, EmailAuthHandlers, EmailAuthHooks, EmailAuthMode, EmailAuthOptions, EmailAuthOptions as EmailAuthOptions$1, EmailAuthPaths, EmailAuthSession, EmailAuthTtl, EmailAuthUser, EmailAuthUserStore, EmailCodeOptions, IssueTokensArgs, IssuedTokens, OAuthClient, OAuthClientMetadata, OAuthHandlers, OAuthServerOptions, OAuthServerOptions as OAuthServerOptions$1, OnAuthorizeArgs, OnAuthorizeResult, OnRefreshTokenArgs, OnRefreshTokenResult, OneTimeTokenPurpose, OneTimeTokenStore, PasswordOptions, RequestRateLimit, RequestRateLimitStore, StoredAuthorizationCode, StoredOneTimeToken, createEmailAuthHandlers, createOAuthHandlers, emailAuthErrorCodes, getWwwAuthenticateHeader, normalizeEmail } from "@ttoss/auth-core";
3
+ import { AuthCodeStore, AuthorizeRequest, ClientStore, EmailAuthDelivery, EmailAuthErrorCode, EmailAuthHandler, EmailAuthHandlers, EmailAuthHooks, EmailAuthMode, EmailAuthOptions, EmailAuthOptions as EmailAuthOptions$1, EmailAuthPaths, EmailAuthSession, EmailAuthTtl, EmailAuthUser, EmailAuthUserStore, EmailCodeOptions, IssueTokensArgs, IssuedTokens, OAuthClient, OAuthClientMetadata, OAuthHandlers, OAuthServerOptions, OAuthServerOptions as OAuthServerOptions$1, OnAuthorizeArgs, OnAuthorizeResult, OnRefreshTokenArgs, OnRefreshTokenResult, OneTimeTokenPurpose, OneTimeTokenStore, PasswordOptions, ProtectedResourceMetadata, RequestRateLimit, RequestRateLimitStore, StoredAuthorizationCode, StoredOneTimeToken, createEmailAuthHandlers, createOAuthHandlers, emailAuthErrorCodes, getWwwAuthenticateHeader, normalizeEmail, protectedResourceMetadataDocument, protectedResourceMetadataPaths, protectedResourceMetadataUrl } from "@ttoss/auth-core";
4
4
 
5
5
  //#region src/types.d.ts
6
6
  type AuthenticatedUser = {
@@ -158,9 +158,13 @@ declare const emailAuth: (options: EmailAuthOptions$1 & {
158
158
  */
159
159
  declare const oauthServer: (options: OAuthServerOptions$1) => Router;
160
160
  /**
161
- * Koa middleware that serves `GET /.well-known/oauth-protected-resource`
162
- * (RFC 9728). Mount it **before** `authMiddleware` so the discovery endpoint
161
+ * Koa middleware that serves the RFC 9728 Protected Resource Metadata
162
+ * document. Mount it **before** `authMiddleware` so the discovery endpoint
163
163
  * stays unauthenticated (clients fetch it before they have a token).
164
+ *
165
+ * It answers at every location `protectedResourceMetadataPaths` derives for
166
+ * the resource: the root, plus the path-derived location of RFC 9728 §3.1 when
167
+ * the resource identifier carries a path.
164
168
  */
165
169
  declare const createProtectedResourceMetadataMiddleware: (args: {
166
170
  /** The protected resource's identifier URI. */resource: string; /** Authorization server issuer URIs that issue tokens for this resource. */
@@ -184,4 +188,4 @@ declare const isOriginAllowed: (origin: string, allowedOrigins: Array<string | R
184
188
  */
185
189
  declare const requireAuth: (options: AuthMiddlewareOptions) => ((ctx: Context, next: Next) => Promise<void>);
186
190
  //#endregion
187
- export { type ApiTokenOptions, type AuthCodeStore, type AuthMiddlewareOptions, type AuthStrategy, type AuthenticatedUser, type AuthorizeRequest, type ClientStore, type EmailAuthDelivery, type EmailAuthErrorCode, type EmailAuthHandler, type EmailAuthHandlers, type EmailAuthHooks, type EmailAuthMode, type EmailAuthOptions, type EmailAuthPaths, type EmailAuthSession, type EmailAuthTtl, type EmailAuthUser, type EmailAuthUserStore, type EmailCodeOptions, type IssueTokensArgs, type IssuedTokens, type JwtOptions, type OAuthClient, type OAuthClientMetadata, type OAuthHandlers, type OAuthOptions, type OAuthServerOptions, type OnAuthorizeArgs, type OnAuthorizeResult, type OnRefreshTokenArgs, type OnRefreshTokenResult, type OneTimeTokenPurpose, type OneTimeTokenStore, type PasswordOptions, type RequestRateLimit, type RequestRateLimitStore, type StoredAuthorizationCode, type StoredOneTimeToken, type SystemOptions, authMiddleware, createEmailAuthHandlers, createOAuthHandlers, createProtectedResourceMetadataMiddleware, emailAuth, emailAuthErrorCodes, getWwwAuthenticateHeader, isOriginAllowed, normalizeEmail, oauthServer, requireAuth };
191
+ export { type ApiTokenOptions, type AuthCodeStore, type AuthMiddlewareOptions, type AuthStrategy, type AuthenticatedUser, type AuthorizeRequest, type ClientStore, type EmailAuthDelivery, type EmailAuthErrorCode, type EmailAuthHandler, type EmailAuthHandlers, type EmailAuthHooks, type EmailAuthMode, type EmailAuthOptions, type EmailAuthPaths, type EmailAuthSession, type EmailAuthTtl, type EmailAuthUser, type EmailAuthUserStore, type EmailCodeOptions, type IssueTokensArgs, type IssuedTokens, type JwtOptions, type OAuthClient, type OAuthClientMetadata, type OAuthHandlers, type OAuthOptions, type OAuthServerOptions, type OnAuthorizeArgs, type OnAuthorizeResult, type OnRefreshTokenArgs, type OnRefreshTokenResult, type OneTimeTokenPurpose, type OneTimeTokenStore, type PasswordOptions, type ProtectedResourceMetadata, type RequestRateLimit, type RequestRateLimitStore, type StoredAuthorizationCode, type StoredOneTimeToken, type SystemOptions, authMiddleware, createEmailAuthHandlers, createOAuthHandlers, createProtectedResourceMetadataMiddleware, emailAuth, emailAuthErrorCodes, getWwwAuthenticateHeader, isOriginAllowed, normalizeEmail, oauthServer, protectedResourceMetadataDocument, protectedResourceMetadataPaths, protectedResourceMetadataUrl, requireAuth };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
 
2
- import { AuthCodeStore, AuthorizeRequest, ClientStore, EmailAuthDelivery, EmailAuthErrorCode, EmailAuthHandler, EmailAuthHandlers, EmailAuthHooks, EmailAuthMode, EmailAuthOptions, EmailAuthOptions as EmailAuthOptions$1, EmailAuthPaths, EmailAuthSession, EmailAuthTtl, EmailAuthUser, EmailAuthUserStore, EmailCodeOptions, IssueTokensArgs, IssuedTokens, OAuthClient, OAuthClientMetadata, OAuthHandlers, OAuthServerOptions, OAuthServerOptions as OAuthServerOptions$1, OnAuthorizeArgs, OnAuthorizeResult, OnRefreshTokenArgs, OnRefreshTokenResult, OneTimeTokenPurpose, OneTimeTokenStore, PasswordOptions, RequestRateLimit, RequestRateLimitStore, StoredAuthorizationCode, StoredOneTimeToken, createEmailAuthHandlers, createOAuthHandlers, emailAuthErrorCodes, getWwwAuthenticateHeader, normalizeEmail } from "@ttoss/auth-core";
2
+ import { AuthCodeStore, AuthorizeRequest, ClientStore, EmailAuthDelivery, EmailAuthErrorCode, EmailAuthHandler, EmailAuthHandlers, EmailAuthHooks, EmailAuthMode, EmailAuthOptions, EmailAuthOptions as EmailAuthOptions$1, EmailAuthPaths, EmailAuthSession, EmailAuthTtl, EmailAuthUser, EmailAuthUserStore, EmailCodeOptions, IssueTokensArgs, IssuedTokens, OAuthClient, OAuthClientMetadata, OAuthHandlers, OAuthServerOptions, OAuthServerOptions as OAuthServerOptions$1, OnAuthorizeArgs, OnAuthorizeResult, OnRefreshTokenArgs, OnRefreshTokenResult, OneTimeTokenPurpose, OneTimeTokenStore, PasswordOptions, ProtectedResourceMetadata, RequestRateLimit, RequestRateLimitStore, StoredAuthorizationCode, StoredOneTimeToken, createEmailAuthHandlers, createOAuthHandlers, emailAuthErrorCodes, getWwwAuthenticateHeader, normalizeEmail, protectedResourceMetadataDocument, protectedResourceMetadataPaths, protectedResourceMetadataUrl } from "@ttoss/auth-core";
3
3
  import { Context, Middleware, Next, Router } from "@ttoss/http-server";
4
4
 
5
5
  //#region src/types.d.ts
@@ -158,9 +158,13 @@ declare const emailAuth: (options: EmailAuthOptions$1 & {
158
158
  */
159
159
  declare const oauthServer: (options: OAuthServerOptions$1) => Router;
160
160
  /**
161
- * Koa middleware that serves `GET /.well-known/oauth-protected-resource`
162
- * (RFC 9728). Mount it **before** `authMiddleware` so the discovery endpoint
161
+ * Koa middleware that serves the RFC 9728 Protected Resource Metadata
162
+ * document. Mount it **before** `authMiddleware` so the discovery endpoint
163
163
  * stays unauthenticated (clients fetch it before they have a token).
164
+ *
165
+ * It answers at every location `protectedResourceMetadataPaths` derives for
166
+ * the resource: the root, plus the path-derived location of RFC 9728 §3.1 when
167
+ * the resource identifier carries a path.
164
168
  */
165
169
  declare const createProtectedResourceMetadataMiddleware: (args: {
166
170
  /** The protected resource's identifier URI. */resource: string; /** Authorization server issuer URIs that issue tokens for this resource. */
@@ -184,4 +188,4 @@ declare const isOriginAllowed: (origin: string, allowedOrigins: Array<string | R
184
188
  */
185
189
  declare const requireAuth: (options: AuthMiddlewareOptions) => ((ctx: Context, next: Next) => Promise<void>);
186
190
  //#endregion
187
- export { type ApiTokenOptions, type AuthCodeStore, type AuthMiddlewareOptions, type AuthStrategy, type AuthenticatedUser, type AuthorizeRequest, type ClientStore, type EmailAuthDelivery, type EmailAuthErrorCode, type EmailAuthHandler, type EmailAuthHandlers, type EmailAuthHooks, type EmailAuthMode, type EmailAuthOptions, type EmailAuthPaths, type EmailAuthSession, type EmailAuthTtl, type EmailAuthUser, type EmailAuthUserStore, type EmailCodeOptions, type IssueTokensArgs, type IssuedTokens, type JwtOptions, type OAuthClient, type OAuthClientMetadata, type OAuthHandlers, type OAuthOptions, type OAuthServerOptions, type OnAuthorizeArgs, type OnAuthorizeResult, type OnRefreshTokenArgs, type OnRefreshTokenResult, type OneTimeTokenPurpose, type OneTimeTokenStore, type PasswordOptions, type RequestRateLimit, type RequestRateLimitStore, type StoredAuthorizationCode, type StoredOneTimeToken, type SystemOptions, authMiddleware, createEmailAuthHandlers, createOAuthHandlers, createProtectedResourceMetadataMiddleware, emailAuth, emailAuthErrorCodes, getWwwAuthenticateHeader, isOriginAllowed, normalizeEmail, oauthServer, requireAuth };
191
+ export { type ApiTokenOptions, type AuthCodeStore, type AuthMiddlewareOptions, type AuthStrategy, type AuthenticatedUser, type AuthorizeRequest, type ClientStore, type EmailAuthDelivery, type EmailAuthErrorCode, type EmailAuthHandler, type EmailAuthHandlers, type EmailAuthHooks, type EmailAuthMode, type EmailAuthOptions, type EmailAuthPaths, type EmailAuthSession, type EmailAuthTtl, type EmailAuthUser, type EmailAuthUserStore, type EmailCodeOptions, type IssueTokensArgs, type IssuedTokens, type JwtOptions, type OAuthClient, type OAuthClientMetadata, type OAuthHandlers, type OAuthOptions, type OAuthServerOptions, type OnAuthorizeArgs, type OnAuthorizeResult, type OnRefreshTokenArgs, type OnRefreshTokenResult, type OneTimeTokenPurpose, type OneTimeTokenStore, type PasswordOptions, type ProtectedResourceMetadata, type RequestRateLimit, type RequestRateLimitStore, type StoredAuthorizationCode, type StoredOneTimeToken, type SystemOptions, authMiddleware, createEmailAuthHandlers, createOAuthHandlers, createProtectedResourceMetadataMiddleware, emailAuth, emailAuthErrorCodes, getWwwAuthenticateHeader, isOriginAllowed, normalizeEmail, oauthServer, protectedResourceMetadataDocument, protectedResourceMetadataPaths, protectedResourceMetadataUrl, requireAuth };
package/dist/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  /** Powered by @ttoss/config. https://ttoss.dev/docs/modules/packages/config/ */
2
2
  import crypto from "node:crypto";
3
- import { createEmailAuthHandlers, createEmailAuthHandlers as createEmailAuthHandlers$1, createOAuthHandlers, createOAuthHandlers as createOAuthHandlers$1, emailAuthErrorCodes, getWwwAuthenticateHeader, hashApiToken, normalizeEmail, verifyJwt } from "@ttoss/auth-core";
3
+ import { createEmailAuthHandlers, createEmailAuthHandlers as createEmailAuthHandlers$1, createOAuthHandlers, createOAuthHandlers as createOAuthHandlers$1, emailAuthErrorCodes, getWwwAuthenticateHeader, hashApiToken, normalizeEmail, protectedResourceMetadataDocument, protectedResourceMetadataDocument as protectedResourceMetadataDocument$1, protectedResourceMetadataPaths, protectedResourceMetadataPaths as protectedResourceMetadataPaths$1, protectedResourceMetadataUrl, verifyJwt } from "@ttoss/auth-core";
4
4
  import { Router } from "@ttoss/http-server";
5
5
 
6
6
  //#region src/origin.ts
@@ -264,7 +264,9 @@ var oauthServer = options => {
264
264
  applyResponse(ctx, engine.authorizationServerMetadata());
265
265
  });
266
266
  const prm = engine.protectedResourceMetadata();
267
- if (prm) router.get("/.well-known/oauth-protected-resource", ctx => {
267
+ if (prm && options.resource) for (const metadataPath of protectedResourceMetadataPaths$1({
268
+ resource: options.resource
269
+ })) router.get(metadataPath, ctx => {
268
270
  applyResponse(ctx, prm);
269
271
  });
270
272
  router.get(engine.paths.authorize, async ctx => {
@@ -279,17 +281,25 @@ var oauthServer = options => {
279
281
  return router;
280
282
  };
281
283
  /**
282
- * Koa middleware that serves `GET /.well-known/oauth-protected-resource`
283
- * (RFC 9728). Mount it **before** `authMiddleware` so the discovery endpoint
284
+ * Koa middleware that serves the RFC 9728 Protected Resource Metadata
285
+ * document. Mount it **before** `authMiddleware` so the discovery endpoint
284
286
  * stays unauthenticated (clients fetch it before they have a token).
287
+ *
288
+ * It answers at every location `protectedResourceMetadataPaths` derives for
289
+ * the resource: the root, plus the path-derived location of RFC 9728 §3.1 when
290
+ * the resource identifier carries a path.
285
291
  */
286
292
  var createProtectedResourceMetadataMiddleware = args => {
293
+ const metadataPaths = new Set(protectedResourceMetadataPaths$1({
294
+ resource: args.resource
295
+ }));
296
+ const body = protectedResourceMetadataDocument$1({
297
+ resource: args.resource,
298
+ authorizationServers: args.authorizationServers
299
+ });
287
300
  return async (ctx, next) => {
288
- if (ctx.method === "GET" && ctx.path === "/.well-known/oauth-protected-resource") {
289
- ctx.body = {
290
- resource: args.resource,
291
- authorization_servers: args.authorizationServers
292
- };
301
+ if (ctx.method === "GET" && metadataPaths.has(ctx.path)) {
302
+ ctx.body = body;
293
303
  return;
294
304
  }
295
305
  await next();
@@ -313,4 +323,4 @@ var requireAuth = options => {
313
323
  };
314
324
 
315
325
  //#endregion
316
- export { authMiddleware, createEmailAuthHandlers, createOAuthHandlers, createProtectedResourceMetadataMiddleware, emailAuth, emailAuthErrorCodes, getWwwAuthenticateHeader, isOriginAllowed, normalizeEmail, oauthServer, requireAuth };
326
+ export { authMiddleware, createEmailAuthHandlers, createOAuthHandlers, createProtectedResourceMetadataMiddleware, emailAuth, emailAuthErrorCodes, getWwwAuthenticateHeader, isOriginAllowed, normalizeEmail, oauthServer, protectedResourceMetadataDocument, protectedResourceMetadataPaths, protectedResourceMetadataUrl, requireAuth };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-auth",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "Authentication middleware for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "auth",
@@ -32,18 +32,18 @@
32
32
  "dist"
33
33
  ],
34
34
  "dependencies": {
35
- "@ttoss/auth-core": "^0.14.0"
35
+ "@ttoss/auth-core": "^0.15.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/koa": "^3.0.3",
39
39
  "jest": "^30.4.2",
40
40
  "supertest": "^7.2.2",
41
41
  "tsdown": "^0.22.2",
42
- "@ttoss/config": "^1.38.0",
43
- "@ttoss/http-server": "^0.8.1"
42
+ "@ttoss/http-server": "^0.9.0",
43
+ "@ttoss/config": "^1.39.0"
44
44
  },
45
45
  "peerDependencies": {
46
- "@ttoss/http-server": "^0.8.1"
46
+ "@ttoss/http-server": "^0.9.0"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public",