@technomoron/api-server-base 2.0.0-beta.1 → 2.0.0-beta.11

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 (52) hide show
  1. package/README.txt +25 -2
  2. package/dist/cjs/api-server-base.cjs +277 -41
  3. package/dist/cjs/api-server-base.d.ts +27 -7
  4. package/dist/cjs/auth-api/auth-module.d.ts +11 -2
  5. package/dist/cjs/auth-api/auth-module.js +215 -46
  6. package/dist/cjs/auth-api/compat-auth-storage.d.ts +7 -5
  7. package/dist/cjs/auth-api/compat-auth-storage.js +15 -3
  8. package/dist/cjs/auth-api/mem-auth-store.d.ts +5 -3
  9. package/dist/cjs/auth-api/mem-auth-store.js +7 -1
  10. package/dist/cjs/auth-api/sql-auth-store.d.ts +5 -3
  11. package/dist/cjs/auth-api/sql-auth-store.js +7 -1
  12. package/dist/cjs/auth-api/storage.d.ts +6 -4
  13. package/dist/cjs/auth-api/storage.js +15 -5
  14. package/dist/cjs/auth-api/types.d.ts +7 -2
  15. package/dist/cjs/index.cjs +4 -4
  16. package/dist/cjs/index.d.ts +4 -4
  17. package/dist/cjs/oauth/sequelize.js +1 -1
  18. package/dist/cjs/passkey/base.d.ts +1 -0
  19. package/dist/cjs/passkey/memory.d.ts +1 -0
  20. package/dist/cjs/passkey/memory.js +4 -0
  21. package/dist/cjs/passkey/sequelize.d.ts +1 -0
  22. package/dist/cjs/passkey/sequelize.js +11 -2
  23. package/dist/cjs/passkey/service.d.ts +5 -2
  24. package/dist/cjs/passkey/service.js +145 -10
  25. package/dist/cjs/passkey/types.d.ts +3 -0
  26. package/dist/cjs/user/base.js +2 -1
  27. package/dist/esm/api-server-base.d.ts +27 -7
  28. package/dist/esm/api-server-base.js +278 -42
  29. package/dist/esm/auth-api/auth-module.d.ts +11 -2
  30. package/dist/esm/auth-api/auth-module.js +216 -47
  31. package/dist/esm/auth-api/compat-auth-storage.d.ts +7 -5
  32. package/dist/esm/auth-api/compat-auth-storage.js +13 -1
  33. package/dist/esm/auth-api/mem-auth-store.d.ts +5 -3
  34. package/dist/esm/auth-api/mem-auth-store.js +8 -2
  35. package/dist/esm/auth-api/sql-auth-store.d.ts +5 -3
  36. package/dist/esm/auth-api/sql-auth-store.js +8 -2
  37. package/dist/esm/auth-api/storage.d.ts +6 -4
  38. package/dist/esm/auth-api/storage.js +13 -3
  39. package/dist/esm/auth-api/types.d.ts +7 -2
  40. package/dist/esm/index.d.ts +4 -4
  41. package/dist/esm/index.js +2 -2
  42. package/dist/esm/oauth/sequelize.js +1 -1
  43. package/dist/esm/passkey/base.d.ts +1 -0
  44. package/dist/esm/passkey/memory.d.ts +1 -0
  45. package/dist/esm/passkey/memory.js +4 -0
  46. package/dist/esm/passkey/sequelize.d.ts +1 -0
  47. package/dist/esm/passkey/sequelize.js +11 -2
  48. package/dist/esm/passkey/service.d.ts +5 -2
  49. package/dist/esm/passkey/service.js +113 -11
  50. package/dist/esm/passkey/types.d.ts +3 -0
  51. package/dist/esm/user/base.js +2 -1
  52. package/package.json +13 -11
@@ -1,15 +1,15 @@
1
1
  export { default as ApiServer } from './api-server-base.js';
2
2
  export { ApiError } from './api-server-base.js';
3
3
  export { ApiModule } from './api-module.js';
4
- export type { ApiErrorParams, ApiHandler, ApiKey, ApiServerConf, ApiRequest, ApiRoute, ApiAuthType, ApiAuthClass, ApiTokenData, ExtendedReq } from './api-server-base.js';
5
- export type { AuthIdentifier, AuthStorage } from './auth-api/types.js';
4
+ export type { ApiErrorParams, ApiHandler, ApiKey, ApiServerConf, ApiRequest, ApiRoute, ApiAuthType, ApiAuthClass, ApiTokenData, ExtendedReq, ExpressApiRequest, ExpressApiLocals } from './api-server-base.js';
5
+ export type { AuthIdentifier } from './auth-api/types.js';
6
6
  export type { Token, TokenPair, TokenStatus } from './token/types.js';
7
7
  export type { JwtSignResult, JwtVerifyResult, JwtDecodeResult } from './token/base.js';
8
8
  export type { OAuthClient, AuthCodeData, AuthCodeRequest } from './oauth/types.js';
9
9
  export type { AuthProviderModule } from './auth-api/module.js';
10
- export { nullAuthStorage, BaseAuthStorage } from './auth-api/storage.js';
10
+ export { nullAuthAdapter, BaseAuthAdapter } from './auth-api/storage.js';
11
11
  export { nullAuthModule, BaseAuthModule } from './auth-api/module.js';
12
- export { AuthStorageAdapter } from './auth-api/compat-auth-storage.js';
12
+ export { CompositeAuthAdapter } from './auth-api/compat-auth-storage.js';
13
13
  export { MemAuthStore } from './auth-api/mem-auth-store.js';
14
14
  export { SqlAuthStore } from './auth-api/sql-auth-store.js';
15
15
  export { default as AuthModule } from './auth-api/auth-module.js';
@@ -126,7 +126,7 @@ class SequelizeOAuthStore extends base_js_1.OAuthStore {
126
126
  const existing = await this.clients.findByPk(input.clientId);
127
127
  const hashedSecret = input.clientSecret !== undefined && input.clientSecret !== null
128
128
  ? await bcryptjs_1.default.hash(input.clientSecret, this.bcryptRounds)
129
- : existing?.client_secret ?? '';
129
+ : (existing?.client_secret ?? '');
130
130
  const redirectUris = input.redirectUris ?? (existing ? decodeStringArray(existing.redirect_uris) : undefined);
131
131
  const scope = input.scope ?? (existing ? decodeStringArray(existing.scope) : undefined);
132
132
  const metadata = input.metadata ?? (existing ? parseMetadata(existing.metadata) : undefined);
@@ -6,6 +6,7 @@ export declare abstract class PasskeyStore implements PasskeyStorageAdapter {
6
6
  login?: string;
7
7
  }): Promise<PasskeyUserDescriptor | null>;
8
8
  abstract listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
9
+ abstract deleteCredential(credentialId: Buffer | string): Promise<boolean>;
9
10
  abstract findCredentialById(credentialId: Buffer): Promise<StoredPasskeyCredential | null>;
10
11
  abstract saveCredential(record: StoredPasskeyCredential): Promise<void>;
11
12
  abstract updateCredentialCounter(credentialId: Buffer, counter: number): Promise<void>;
@@ -17,6 +17,7 @@ export declare class MemoryPasskeyStore extends PasskeyStore {
17
17
  login?: string;
18
18
  }): Promise<PasskeyUserDescriptor | null>;
19
19
  listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
20
+ deleteCredential(credentialId: Buffer | string): Promise<boolean>;
20
21
  findCredentialById(credentialId: Buffer): Promise<StoredPasskeyCredential | null>;
21
22
  saveCredential(record: StoredPasskeyCredential): Promise<void>;
22
23
  updateCredentialCounter(credentialId: Buffer, counter: number): Promise<void>;
@@ -37,6 +37,10 @@ class MemoryPasskeyStore extends base_js_1.PasskeyStore {
37
37
  .filter((record) => normalizeUserId(record.userId) === normalizedUserId)
38
38
  .map((record) => cloneCredential(record));
39
39
  }
40
+ async deleteCredential(credentialId) {
41
+ const key = encodeCredentialId(credentialId);
42
+ return this.credentials.delete(key);
43
+ }
40
44
  async findCredentialById(credentialId) {
41
45
  const record = this.credentials.get(encodeCredentialId(credentialId));
42
46
  return record ? cloneCredential(record) : null;
@@ -44,6 +44,7 @@ export declare class SequelizePasskeyStore extends PasskeyStore {
44
44
  login?: string;
45
45
  }): Promise<PasskeyUserDescriptor | null>;
46
46
  listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
47
+ deleteCredential(credentialId: Buffer | string): Promise<boolean>;
47
48
  findCredentialById(credentialId: Buffer): Promise<StoredPasskeyCredential | null>;
48
49
  saveCredential(record: StoredPasskeyCredential): Promise<void>;
49
50
  updateCredentialCounter(credentialId: Buffer, counter: number): Promise<void>;
@@ -147,9 +147,16 @@ class SequelizePasskeyStore extends base_js_1.PasskeyStore {
147
147
  counter: model.counter,
148
148
  transports: (model.transports ?? undefined),
149
149
  backedUp: model.backedUp,
150
- deviceType: model.deviceType
150
+ deviceType: model.deviceType,
151
+ createdAt: model.createdAt ?? undefined,
152
+ updatedAt: model.updatedAt ?? undefined
151
153
  }));
152
154
  }
155
+ async deleteCredential(credentialId) {
156
+ const encoded = Buffer.isBuffer(credentialId) ? credentialId.toString('base64') : credentialId;
157
+ const deleted = await this.credentials.destroy({ where: { credentialId: encoded } });
158
+ return deleted > 0;
159
+ }
153
160
  async findCredentialById(credentialId) {
154
161
  const model = await this.credentials.findByPk(encodeCredentialId(credentialId));
155
162
  if (!model) {
@@ -162,7 +169,9 @@ class SequelizePasskeyStore extends base_js_1.PasskeyStore {
162
169
  counter: model.counter,
163
170
  transports: (model.transports ?? undefined),
164
171
  backedUp: model.backedUp,
165
- deviceType: model.deviceType
172
+ deviceType: model.deviceType,
173
+ createdAt: model.createdAt ?? undefined,
174
+ updatedAt: model.updatedAt ?? undefined
166
175
  };
167
176
  }
168
177
  async saveCredential(record) {
@@ -1,11 +1,14 @@
1
- import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyStorageAdapter, PasskeyVerificationParams, PasskeyVerificationResult, PasskeyServiceConfig } from './types.js';
2
- export type { CredentialDeviceType, PasskeyChallenge, PasskeyChallengeParams, PasskeyChallengeRecord, PasskeyChallengeMetadata, PasskeyUserDescriptor, PasskeyVerificationParams, PasskeyVerificationResult, PasskeyServiceConfig, PasskeyStorageAdapter } from './types.js';
1
+ import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyStorageAdapter, PasskeyVerificationParams, PasskeyVerificationResult, PasskeyServiceConfig, StoredPasskeyCredential } from './types.js';
2
+ import type { AuthIdentifier } from '../auth-api/types.js';
3
+ export type { CredentialDeviceType, PasskeyChallenge, PasskeyChallengeParams, PasskeyChallengeRecord, PasskeyChallengeMetadata, PasskeyUserDescriptor, PasskeyVerificationParams, PasskeyVerificationResult, PasskeyServiceConfig, PasskeyStorageAdapter, StoredPasskeyCredential } from './types.js';
3
4
  type Logger = Pick<typeof console, 'error' | 'warn'>;
4
5
  export declare class PasskeyService {
5
6
  private readonly config;
6
7
  private readonly adapter;
7
8
  private readonly logger;
8
9
  constructor(config: PasskeyServiceConfig, adapter: PasskeyStorageAdapter, logger?: Logger);
10
+ listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
11
+ deleteCredential(credentialId: Buffer | string): Promise<boolean>;
9
12
  createChallenge(params: PasskeyChallengeParams): Promise<PasskeyChallenge>;
10
13
  verifyResponse(params: PasskeyVerificationParams): Promise<PasskeyVerificationResult>;
11
14
  private createRegistrationChallenge;
@@ -1,4 +1,37 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
3
36
  exports.PasskeyService = void 0;
4
37
  const server_1 = require("@simplewebauthn/server");
@@ -34,12 +67,64 @@ function toBuffer(value) {
34
67
  const view = value instanceof Uint8Array ? value : new Uint8Array(value);
35
68
  return Buffer.from(view);
36
69
  }
70
+ function toBufferOrNull(value) {
71
+ if (!value) {
72
+ return null;
73
+ }
74
+ if (Buffer.isBuffer(value)) {
75
+ return value;
76
+ }
77
+ if (value instanceof ArrayBuffer || value instanceof Uint8Array) {
78
+ return toBuffer(value);
79
+ }
80
+ if (typeof value === 'string') {
81
+ try {
82
+ return fromBase64Url(value);
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ return null;
89
+ }
90
+ async function spkiToCosePublicKey(spki) {
91
+ try {
92
+ const subtle = globalThis.crypto?.subtle ?? (await Promise.resolve().then(() => __importStar(require('crypto')))).webcrypto?.subtle;
93
+ if (!subtle) {
94
+ return null;
95
+ }
96
+ const key = await subtle.importKey('spki', spki, { name: 'ECDSA', namedCurve: 'P-256' }, true, ['verify']);
97
+ const raw = Buffer.from(await subtle.exportKey('raw', key));
98
+ if (raw.length !== 65 || raw[0] !== 0x04) {
99
+ return null;
100
+ }
101
+ const x = raw.slice(1, 33);
102
+ const y = raw.slice(33, 65);
103
+ const coseMap = new Map([
104
+ [1, 2], // kty: EC2
105
+ [3, -7], // alg: ES256
106
+ [-1, 1], // crv: P-256
107
+ [-2, x],
108
+ [-3, y]
109
+ ]);
110
+ return Buffer.from(helpers_1.isoCBOR.encode(coseMap));
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ }
37
116
  class PasskeyService {
38
117
  constructor(config, adapter, logger = console) {
39
118
  this.config = config;
40
119
  this.adapter = adapter;
41
120
  this.logger = logger;
42
121
  }
122
+ async listUserCredentials(userId) {
123
+ return this.adapter.listUserCredentials(userId);
124
+ }
125
+ async deleteCredential(credentialId) {
126
+ return this.adapter.deleteCredential(credentialId);
127
+ }
43
128
  async createChallenge(params) {
44
129
  await this.adapter.cleanupChallenges?.(new Date());
45
130
  const metadata = {
@@ -107,7 +192,8 @@ class PasskeyService {
107
192
  return {
108
193
  challenge: options.challenge,
109
194
  expiresAt: expiresAt.toISOString(),
110
- userId: user.id
195
+ userId: user.id,
196
+ publicKey: options
111
197
  };
112
198
  }
113
199
  async createAuthenticationChallenge(params, metadata) {
@@ -136,7 +222,8 @@ class PasskeyService {
136
222
  return {
137
223
  challenge: options.challenge,
138
224
  expiresAt: expiresAt.toISOString(),
139
- userId: user.id
225
+ userId: user.id,
226
+ publicKey: options
140
227
  };
141
228
  }
142
229
  async verifyRegistration(params, record) {
@@ -155,14 +242,57 @@ class PasskeyService {
155
242
  requireUserVerification: true
156
243
  });
157
244
  if (!result.verified || !result.registrationInfo) {
245
+ if (!result.verified) {
246
+ const err = result.error ?? result;
247
+ this.logger.error?.('Passkey registration verification failed', err);
248
+ }
158
249
  return { verified: false };
159
250
  }
160
251
  const registrationInfo = result.registrationInfo;
252
+ const attestationResponse = params.response?.response;
253
+ const credentialIdPrimary = toBufferOrNull(registrationInfo.credentialID);
254
+ const credentialIdFallback = toBufferOrNull(params.response?.id);
255
+ const credentialId = credentialIdPrimary && credentialIdPrimary.length > 0 ? credentialIdPrimary : credentialIdFallback;
256
+ const publicKeyPrimary = toBufferOrNull(registrationInfo.credentialPublicKey);
257
+ let publicKeyFallback = toBufferOrNull(attestationResponse?.publicKey);
258
+ if ((!publicKeyPrimary || publicKeyPrimary.length === 0) && attestationResponse?.attestationObject) {
259
+ try {
260
+ const attObj = (0, helpers_1.decodeAttestationObject)(helpers_1.isoBase64URL.toBuffer(attestationResponse.attestationObject));
261
+ const parsedAuth = (0, helpers_1.parseAuthenticatorData)(attObj.get('authData'));
262
+ publicKeyFallback = toBufferOrNull(parsedAuth.credentialPublicKey) ?? publicKeyFallback;
263
+ }
264
+ catch (error) {
265
+ this.logger.warn?.('Passkey registration: failed to parse attestationObject', error);
266
+ }
267
+ }
268
+ const publicKey = publicKeyPrimary && publicKeyPrimary.length > 0 ? publicKeyPrimary : publicKeyFallback;
269
+ if (this.logger?.warn) {
270
+ const pkPrimaryHex = publicKeyPrimary ? publicKeyPrimary.slice(0, 4).toString('hex') : 'null';
271
+ const pkFallbackHex = publicKeyFallback ? publicKeyFallback.slice(0, 4).toString('hex') : 'null';
272
+ this.logger.warn(`Passkey registration: pkPrimary len=${publicKeyPrimary?.length ?? 0} head=${pkPrimaryHex}, pkFallback len=${publicKeyFallback?.length ?? 0} head=${pkFallbackHex}`);
273
+ }
274
+ if (!credentialId || credentialId.length === 0) {
275
+ return { verified: false, message: 'Missing credential id in registration response' };
276
+ }
277
+ if (!publicKey || publicKey.length === 0) {
278
+ return { verified: false, message: 'Missing public key in registration response' };
279
+ }
280
+ let storedPublicKey = Buffer.isBuffer(publicKey) ? publicKey : toBuffer(publicKey);
281
+ // If fallback is an SPKI key (DER, starts with 0x30) convert to COSE so verification succeeds.
282
+ if (storedPublicKey[0] === 0x30) {
283
+ const converted = await spkiToCosePublicKey(storedPublicKey);
284
+ if (converted) {
285
+ storedPublicKey = converted;
286
+ }
287
+ else {
288
+ this.logger.warn?.('Passkey registration: failed to convert SPKI public key to COSE');
289
+ }
290
+ }
161
291
  await this.adapter.saveCredential({
162
292
  userId: user.id,
163
- credentialId: toBuffer(registrationInfo.credentialID),
164
- publicKey: toBuffer(registrationInfo.credentialPublicKey),
165
- counter: registrationInfo.counter,
293
+ credentialId,
294
+ publicKey: storedPublicKey,
295
+ counter: registrationInfo.counter ?? 0,
166
296
  transports: sanitizeTransports(params.response.transports),
167
297
  backedUp: registrationInfo.credentialDeviceType === 'multiDevice',
168
298
  deviceType: registrationInfo.credentialDeviceType
@@ -182,22 +312,27 @@ class PasskeyService {
182
312
  }
183
313
  const user = await this.requireUser({ userId: credential.userId, login: record.login });
184
314
  const storedAuthData = {
185
- credentialID: credential.credentialId,
315
+ id: credential.credentialId,
316
+ publicKey: toBuffer(credential.publicKey),
317
+ credentialPublicKey: toBuffer(credential.publicKey),
186
318
  counter: credential.counter,
319
+ transports: credential.transports ?? undefined,
187
320
  credentialBackedUp: credential.backedUp,
188
- credentialDeviceType: credential.deviceType,
189
- credentialPublicKey: credential.publicKey,
190
- transports: credential.transports ?? undefined
321
+ credentialDeviceType: credential.deviceType
322
+ // simplewebauthn accepts either Uint8Array or Buffer; ensure Buffer
323
+ // see https://github.com/MasterKale/SimpleWebAuthn/blob/master/packages/server/src/authentication/verifyAuthenticationResponse.ts
191
324
  };
192
325
  const result = await (0, server_1.verifyAuthenticationResponse)({
193
326
  response,
194
327
  expectedChallenge: record.challenge,
195
328
  expectedOrigin: this.config.origins,
196
329
  expectedRPID: this.config.rpId,
197
- authenticator: storedAuthData,
330
+ credential: storedAuthData,
198
331
  requireUserVerification: true
199
332
  });
200
333
  if (!result.verified) {
334
+ const err = result.error ?? result;
335
+ this.logger.error?.('Passkey authentication verification failed', err);
201
336
  return { verified: false };
202
337
  }
203
338
  await this.adapter.updateCredentialCounter(credential.credentialId, result.authenticationInfo.newCounter);
@@ -36,6 +36,8 @@ export interface StoredPasskeyCredential {
36
36
  transports?: AuthenticatorTransportFuture[];
37
37
  backedUp: boolean;
38
38
  deviceType: CredentialDeviceType;
39
+ createdAt?: Date;
40
+ updatedAt?: Date;
39
41
  }
40
42
  export interface PasskeyStorageAdapter {
41
43
  resolveUser(params: {
@@ -43,6 +45,7 @@ export interface PasskeyStorageAdapter {
43
45
  login?: string;
44
46
  }): Promise<PasskeyUserDescriptor | null>;
45
47
  listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
48
+ deleteCredential(credentialId: Buffer | string): Promise<boolean>;
46
49
  findCredentialById(credentialId: Buffer): Promise<StoredPasskeyCredential | null>;
47
50
  saveCredential(record: StoredPasskeyCredential): Promise<void>;
48
51
  updateCredentialCounter(credentialId: Buffer, counter: number): Promise<void>;
@@ -35,7 +35,8 @@ class UserStore {
35
35
  toPublic(user) {
36
36
  const mapped = this.toPublicUser(user);
37
37
  if (mapped && typeof mapped === 'object') {
38
- const { password, ...rest } = mapped;
38
+ const { password: _password, ...rest } = mapped;
39
+ void _password;
39
40
  return rest;
40
41
  }
41
42
  return mapped;
@@ -4,16 +4,16 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
- import { Application, Request, Response } from 'express';
7
+ import { Application, Request, Response, type ErrorRequestHandler, type RequestHandler } from 'express';
8
8
  import { ApiModule } from './api-module.js';
9
9
  import { TokenStore, type JwtDecodeResult, type JwtSignResult, type JwtVerifyResult } from './token/base.js';
10
- import type { ApiAuthClass, ApiKey } from './api-module.js';
10
+ import type { ApiAuthClass, ApiAuthType, ApiKey } from './api-module.js';
11
11
  import type { AuthProviderModule } from './auth-api/module.js';
12
- import type { AuthStorage, AuthIdentifier } from './auth-api/types.js';
12
+ import type { AuthAdapter, AuthIdentifier } from './auth-api/types.js';
13
13
  import type { OAuthStore } from './oauth/base.js';
14
14
  import type { AuthCodeData, AuthCodeRequest, OAuthClient } from './oauth/types.js';
15
15
  import type { PasskeyService } from './passkey/service.js';
16
- import type { PasskeyChallenge, PasskeyChallengeParams, PasskeyVerificationParams, PasskeyVerificationResult } from './passkey/types.js';
16
+ import type { PasskeyChallenge, PasskeyChallengeParams, StoredPasskeyCredential, PasskeyVerificationParams, PasskeyVerificationResult } from './passkey/types.js';
17
17
  import type { Token } from './token/types.js';
18
18
  import type { UserStore } from './user/base.js';
19
19
  import type { JwtPayload, SignOptions, VerifyOptions } from 'jsonwebtoken';
@@ -47,6 +47,12 @@ export interface ApiRequest {
47
47
  getRealUid: () => AuthIdentifier | null;
48
48
  isImpersonating: () => boolean;
49
49
  }
50
+ export interface ExpressApiRequest extends ExtendedReq {
51
+ apiReq?: ApiRequest;
52
+ }
53
+ export interface ExpressApiLocals {
54
+ apiReq?: ApiRequest;
55
+ }
50
56
  export interface ClientAgentProfile {
51
57
  ua: string;
52
58
  browser: string;
@@ -101,6 +107,7 @@ export interface ApiServerConf {
101
107
  devMode: boolean;
102
108
  hydrateGetBody: boolean;
103
109
  validateTokens: boolean;
110
+ refreshMaybe: boolean;
104
111
  apiVersion: string;
105
112
  minClientVersion: string;
106
113
  tokenStore?: TokenStore;
@@ -122,23 +129,25 @@ export declare class ApiServer {
122
129
  private canImpersonateAdapter;
123
130
  private readonly jwtHelper;
124
131
  constructor(config?: Partial<ApiServerConf>);
125
- authStorage<UserRow, SafeUser>(storage: AuthStorage<UserRow, SafeUser>): this;
132
+ authStorage<UserRow, SafeUser>(storage: AuthAdapter<UserRow, SafeUser>): this;
126
133
  /**
127
134
  * @deprecated Use {@link ApiServer.authStorage} instead.
128
135
  */
129
- useAuthStorage<UserRow, SafeUser>(storage: AuthStorage<UserRow, SafeUser>): this;
136
+ useAuthStorage<UserRow, SafeUser>(storage: AuthAdapter<UserRow, SafeUser>): this;
130
137
  authModule<UserRow>(module: AuthProviderModule<UserRow>): this;
131
138
  /**
132
139
  * @deprecated Use {@link ApiServer.authModule} instead.
133
140
  */
134
141
  useAuthModule<UserRow>(module: AuthProviderModule<UserRow>): this;
135
- getAuthStorage(): AuthStorage<any, any>;
142
+ getAuthStorage(): AuthAdapter<any, any>;
136
143
  getAuthModule(): AuthProviderModule<any>;
137
144
  setTokenStore(store: TokenStore): this;
138
145
  getTokenStore(): TokenStore | null;
139
146
  private ensureUserStore;
140
147
  private ensureTokenStore;
141
148
  private ensurePasskeyService;
149
+ listUserCredentials(userId: AuthIdentifier): Promise<StoredPasskeyCredential[]>;
150
+ deletePasskeyCredential(credentialId: Buffer | string): Promise<boolean>;
142
151
  private ensureOAuthStore;
143
152
  getUser(identifier: AuthIdentifier): Promise<any | null>;
144
153
  getUserPasswordHash(user: any): string;
@@ -187,6 +196,9 @@ export declare class ApiServer {
187
196
  private describeMissingEndpoint;
188
197
  start(): this;
189
198
  private verifyJWT;
199
+ private jwtCookieOptions;
200
+ private setAccessCookie;
201
+ private tryRefreshAccessToken;
190
202
  private authenticate;
191
203
  private tryAuthenticateApiKey;
192
204
  private requiresAuthToken;
@@ -195,6 +207,14 @@ export declare class ApiServer {
195
207
  private normalizeAuthIdentifier;
196
208
  private extractTokenUserId;
197
209
  private resolveRealUserId;
210
+ useExpress(path: string, ...handlers: Array<RequestHandler | ErrorRequestHandler>): this;
211
+ useExpress(...handlers: Array<RequestHandler | ErrorRequestHandler>): this;
212
+ private createApiRequest;
213
+ expressAuth(auth: {
214
+ type: ApiAuthType;
215
+ req: ApiAuthClass;
216
+ }): RequestHandler;
217
+ expressErrorHandler(): ErrorRequestHandler;
198
218
  private handle_request;
199
219
  api<T extends ApiModule<any>>(module: T): this;
200
220
  dumpRequest(apiReq: ApiRequest): void;