@ttoss/http-server-auth 0.2.1 → 0.3.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.
package/README.md CHANGED
@@ -27,8 +27,10 @@ app.use(
27
27
  },
28
28
 
29
29
  apiToken: {
30
- lookup: async (tokenHash) => {
31
- const record = await ApiTokenModel.findOne({
30
+ // The second argument is the Koa `ctx`, so the lookup can do
31
+ // request-scoped work (read `ctx.db`, bump `lastUsedAt`, etc.).
32
+ lookup: async (tokenHash, ctx) => {
33
+ const record = await ctx.db.ApiToken.findOne({
32
34
  where: { tokenHash, revoked: false },
33
35
  });
34
36
  if (!record) return null;
@@ -115,7 +117,9 @@ type AuthenticatedUser = {
115
117
  1. Reads `Authorization: Bearer <token>`; missing header → 401 if `required`.
116
118
  2. If `allowedOrigins` is configured and the `Origin` header doesn't match → 403. Requests without an Origin header are never rejected.
117
119
  3. Tries each strategy in `strategies` order; first match wins.
118
- - `jwt` — verifies HS256 JWT via `@ttoss/auth-core verifyJwt`; maps `sub`/`email` to user (override with `jwt.mapPayload`).
119
- - `apiToken` — hashes the token (SHA-256) and calls `apiToken.lookup(hash)`.
120
+ - `jwt` — verifies HS256 JWT via `@ttoss/auth-core verifyJwt`; maps `sub`/`email` to user (override with `jwt.mapPayload(payload, ctx)`).
121
+ - `apiToken` — hashes the token (SHA-256) and calls `apiToken.lookup(hash, ctx)`.
120
122
  - `system` — constant-time comparison against `system.secret`.
121
123
  4. All strategies fail and `required` → 401. Failure reason is never leaked.
124
+
125
+ Both `apiToken.lookup` and `jwt.mapPayload` receive the Koa `ctx` as a second argument, enabling request-scoped work (e.g. reading a per-request connection off `ctx.db` or updating `lastUsedAt`). The single-argument signatures keep working — `ctx` is purely additive.
package/dist/index.cjs CHANGED
@@ -50,13 +50,13 @@ var isOriginAllowed = (origin, allowedOrigins) => {
50
50
 
51
51
  //#endregion
52
52
  //#region src/authMiddleware.ts
53
- var tryJwt = (token, opts) => {
53
+ var tryJwt = (token, opts, ctx) => {
54
54
  const payload = (0, _ttoss_auth_core.verifyJwt)({
55
55
  token,
56
56
  secret: opts.secret
57
57
  });
58
58
  if (!payload) return null;
59
- if (opts.mapPayload) return opts.mapPayload(payload);
59
+ if (opts.mapPayload) return opts.mapPayload(payload, ctx);
60
60
  return {
61
61
  id: String(payload.sub ?? ""),
62
62
  ...(payload.email !== void 0 && {
@@ -64,8 +64,8 @@ var tryJwt = (token, opts) => {
64
64
  })
65
65
  };
66
66
  };
67
- var tryApiToken = async (token, opts) => {
68
- return opts.lookup((0, _ttoss_auth_core.hashApiToken)(token));
67
+ var tryApiToken = async (token, opts, ctx) => {
68
+ return opts.lookup((0, _ttoss_auth_core.hashApiToken)(token), ctx);
69
69
  };
70
70
  var trySystem = (token, opts) => {
71
71
  const a = Buffer.from(token);
@@ -73,10 +73,10 @@ var trySystem = (token, opts) => {
73
73
  if (a.length !== b.length || !node_crypto.default.timingSafeEqual(a, b)) return null;
74
74
  return opts.user;
75
75
  };
76
- var resolveUser = async (token, options) => {
76
+ var resolveUser = async (token, options, ctx) => {
77
77
  for (const strategy of options.strategies) {
78
78
  let user = null;
79
- if (strategy === "jwt" && options.jwt) user = tryJwt(token, options.jwt);else if (strategy === "apiToken" && options.apiToken) user = await tryApiToken(token, options.apiToken);else if (strategy === "system" && options.system) user = trySystem(token, options.system);
79
+ if (strategy === "jwt" && options.jwt) user = tryJwt(token, options.jwt, ctx);else if (strategy === "apiToken" && options.apiToken) user = await tryApiToken(token, options.apiToken, ctx);else if (strategy === "system" && options.system) user = trySystem(token, options.system);
80
80
  if (user) return {
81
81
  user,
82
82
  strategy
@@ -102,7 +102,7 @@ var authMiddleware = options => {
102
102
  if (required) ctx.throw(401, "Unauthorized");
103
103
  return next();
104
104
  }
105
- const result = await resolveUser(token, options);
105
+ const result = await resolveUser(token, options, ctx);
106
106
  if (!result) {
107
107
  if (required) ctx.throw(401, "Unauthorized");
108
108
  return next();
package/dist/index.d.cts CHANGED
@@ -13,15 +13,21 @@ type JwtOptions = {
13
13
  /**
14
14
  * Override how the JWT payload maps to an AuthenticatedUser.
15
15
  * Defaults to `{ id: payload.sub, email: payload.email }`.
16
+ *
17
+ * Receives the Koa `ctx` as a second argument so the mapping can do
18
+ * request-scoped work (e.g. reading from `ctx.db`).
16
19
  */
17
- mapPayload?: (payload: Record<string, unknown>) => AuthenticatedUser | null;
20
+ mapPayload?: (payload: Record<string, unknown>, ctx: Context) => AuthenticatedUser | null;
18
21
  };
19
22
  type ApiTokenOptions = {
20
23
  /**
21
24
  * Receives the SHA-256 hash of the presented token and returns the
22
25
  * authenticated user, or null if not found / revoked.
26
+ *
27
+ * Receives the Koa `ctx` as a second argument so the lookup can do
28
+ * request-scoped work (e.g. bumping `lastUsedAt` or reading `ctx.db`).
23
29
  */
24
- lookup: (tokenHash: string) => Promise<AuthenticatedUser | null>;
30
+ lookup: (tokenHash: string, ctx: Context) => Promise<AuthenticatedUser | null>;
25
31
  };
26
32
  type SystemOptions = {
27
33
  secret: string; /** User attached to ctx.state.user for system calls. */
package/dist/index.d.mts CHANGED
@@ -13,15 +13,21 @@ type JwtOptions = {
13
13
  /**
14
14
  * Override how the JWT payload maps to an AuthenticatedUser.
15
15
  * Defaults to `{ id: payload.sub, email: payload.email }`.
16
+ *
17
+ * Receives the Koa `ctx` as a second argument so the mapping can do
18
+ * request-scoped work (e.g. reading from `ctx.db`).
16
19
  */
17
- mapPayload?: (payload: Record<string, unknown>) => AuthenticatedUser | null;
20
+ mapPayload?: (payload: Record<string, unknown>, ctx: Context) => AuthenticatedUser | null;
18
21
  };
19
22
  type ApiTokenOptions = {
20
23
  /**
21
24
  * Receives the SHA-256 hash of the presented token and returns the
22
25
  * authenticated user, or null if not found / revoked.
26
+ *
27
+ * Receives the Koa `ctx` as a second argument so the lookup can do
28
+ * request-scoped work (e.g. bumping `lastUsedAt` or reading `ctx.db`).
23
29
  */
24
- lookup: (tokenHash: string) => Promise<AuthenticatedUser | null>;
30
+ lookup: (tokenHash: string, ctx: Context) => Promise<AuthenticatedUser | null>;
25
31
  };
26
32
  type SystemOptions = {
27
33
  secret: string; /** User attached to ctx.state.user for system calls. */
package/dist/index.mjs CHANGED
@@ -19,13 +19,13 @@ var isOriginAllowed = (origin, allowedOrigins) => {
19
19
 
20
20
  //#endregion
21
21
  //#region src/authMiddleware.ts
22
- var tryJwt = (token, opts) => {
22
+ var tryJwt = (token, opts, ctx) => {
23
23
  const payload = verifyJwt({
24
24
  token,
25
25
  secret: opts.secret
26
26
  });
27
27
  if (!payload) return null;
28
- if (opts.mapPayload) return opts.mapPayload(payload);
28
+ if (opts.mapPayload) return opts.mapPayload(payload, ctx);
29
29
  return {
30
30
  id: String(payload.sub ?? ""),
31
31
  ...(payload.email !== void 0 && {
@@ -33,8 +33,8 @@ var tryJwt = (token, opts) => {
33
33
  })
34
34
  };
35
35
  };
36
- var tryApiToken = async (token, opts) => {
37
- return opts.lookup(hashApiToken(token));
36
+ var tryApiToken = async (token, opts, ctx) => {
37
+ return opts.lookup(hashApiToken(token), ctx);
38
38
  };
39
39
  var trySystem = (token, opts) => {
40
40
  const a = Buffer.from(token);
@@ -42,10 +42,10 @@ var trySystem = (token, opts) => {
42
42
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return null;
43
43
  return opts.user;
44
44
  };
45
- var resolveUser = async (token, options) => {
45
+ var resolveUser = async (token, options, ctx) => {
46
46
  for (const strategy of options.strategies) {
47
47
  let user = null;
48
- if (strategy === "jwt" && options.jwt) user = tryJwt(token, options.jwt);else if (strategy === "apiToken" && options.apiToken) user = await tryApiToken(token, options.apiToken);else if (strategy === "system" && options.system) user = trySystem(token, options.system);
48
+ if (strategy === "jwt" && options.jwt) user = tryJwt(token, options.jwt, ctx);else if (strategy === "apiToken" && options.apiToken) user = await tryApiToken(token, options.apiToken, ctx);else if (strategy === "system" && options.system) user = trySystem(token, options.system);
49
49
  if (user) return {
50
50
  user,
51
51
  strategy
@@ -71,7 +71,7 @@ var authMiddleware = options => {
71
71
  if (required) ctx.throw(401, "Unauthorized");
72
72
  return next();
73
73
  }
74
- const result = await resolveUser(token, options);
74
+ const result = await resolveUser(token, options, ctx);
75
75
  if (!result) {
76
76
  if (required) ctx.throw(401, "Unauthorized");
77
77
  return next();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ttoss/http-server-auth",
3
- "version": "0.2.1",
3
+ "version": "0.3.1",
4
4
  "description": "Authentication middleware for @ttoss/http-server",
5
5
  "keywords": [
6
6
  "auth",
@@ -32,7 +32,7 @@
32
32
  "dist"
33
33
  ],
34
34
  "dependencies": {
35
- "@ttoss/auth-core": "^0.6.0"
35
+ "@ttoss/auth-core": "^0.6.1"
36
36
  },
37
37
  "devDependencies": {
38
38
  "@types/koa": "^3.0.3",
@@ -40,10 +40,10 @@
40
40
  "supertest": "^7.2.2",
41
41
  "tsdown": "^0.22.2",
42
42
  "@ttoss/config": "^1.37.17",
43
- "@ttoss/http-server": "^0.6.1"
43
+ "@ttoss/http-server": "^0.7.0"
44
44
  },
45
45
  "peerDependencies": {
46
- "@ttoss/http-server": "^0.6.1"
46
+ "@ttoss/http-server": "^0.7.0"
47
47
  },
48
48
  "publishConfig": {
49
49
  "access": "public",