@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
@@ -10,7 +10,7 @@ import cors from 'cors';
10
10
  import express from 'express';
11
11
  import multer from 'multer';
12
12
  import { nullAuthModule } from './auth-api/module.js';
13
- import { nullAuthStorage } from './auth-api/storage.js';
13
+ import { nullAuthAdapter } from './auth-api/storage.js';
14
14
  import { TokenStore } from './token/base.js';
15
15
  class JwtHelperStore extends TokenStore {
16
16
  async save() {
@@ -344,6 +344,7 @@ function fillConfig(config) {
344
344
  devMode: config.devMode ?? false,
345
345
  hydrateGetBody: config.hydrateGetBody ?? true,
346
346
  validateTokens: config.validateTokens ?? false,
347
+ refreshMaybe: config.refreshMaybe ?? false,
347
348
  apiVersion: config.apiVersion ?? '',
348
349
  minClientVersion: config.minClientVersion ?? '',
349
350
  tokenStore: config.tokenStore,
@@ -362,7 +363,7 @@ export class ApiServer {
362
363
  this.config = fillConfig(config);
363
364
  this.apiBasePath = this.normalizeApiBasePath(this.config.apiBasePath);
364
365
  this.startedAt = Date.now();
365
- this.storageAdapter = nullAuthStorage;
366
+ this.storageAdapter = nullAuthAdapter;
366
367
  this.moduleAdapter = nullAuthModule;
367
368
  this.jwtHelper = new JwtHelperStore();
368
369
  this.tokenStoreAdapter = this.config.tokenStore ?? null;
@@ -440,13 +441,19 @@ export class ApiServer {
440
441
  }
441
442
  return this.passkeyServiceAdapter;
442
443
  }
444
+ async listUserCredentials(userId) {
445
+ return this.ensurePasskeyService().listUserCredentials(userId);
446
+ }
447
+ async deletePasskeyCredential(credentialId) {
448
+ return this.ensurePasskeyService().deleteCredential(credentialId);
449
+ }
443
450
  ensureOAuthStore() {
444
451
  if (!this.oauthStoreAdapter) {
445
452
  throw new Error('OAuth store is not configured');
446
453
  }
447
454
  return this.oauthStoreAdapter;
448
455
  }
449
- // AuthStorage-compatible helpers (used by AuthModule)
456
+ // AuthAdapter-compatible helpers (used by AuthModule)
450
457
  async getUser(identifier) {
451
458
  return this.userStoreAdapter ? this.userStoreAdapter.findUser(identifier) : null;
452
459
  }
@@ -604,6 +611,7 @@ export class ApiServer {
604
611
  const path = `${this.apiBasePath}/v1/ping`;
605
612
  this.app.get(path, (_req, res) => {
606
613
  const payload = {
614
+ success: true,
607
615
  status: 'ok',
608
616
  apiVersion: this.config.apiVersion ?? '',
609
617
  minClientVersion: this.config.minClientVersion ?? '',
@@ -611,7 +619,7 @@ export class ApiServer {
611
619
  startedAt: this.startedAt,
612
620
  timestamp: new Date().toISOString()
613
621
  };
614
- res.status(200).json({ code: 200, message: 'Success', data: payload });
622
+ res.status(200).json({ success: true, code: 200, message: 'Success', data: payload, errors: {} });
615
623
  });
616
624
  }
617
625
  normalizeApiBasePath(path) {
@@ -634,6 +642,7 @@ export class ApiServer {
634
642
  }
635
643
  this.apiNotFoundHandler = (req, res) => {
636
644
  const payload = {
645
+ success: false,
637
646
  code: 404,
638
647
  message: this.describeMissingEndpoint(req),
639
648
  data: null,
@@ -692,16 +701,117 @@ export class ApiServer {
692
701
  }
693
702
  async verifyJWT(token) {
694
703
  if (!this.config.accessSecret) {
695
- return { tokenData: undefined, error: 'JWT authentication disabled; no jwtSecret set' };
704
+ return { tokenData: undefined, error: 'JWT authentication disabled; no jwtSecret set', expired: false };
696
705
  }
697
706
  const result = this.jwtVerify(token, this.config.accessSecret);
698
707
  if (!result.success) {
699
- return { tokenData: undefined, error: result.error };
708
+ return { tokenData: undefined, error: result.error, expired: result.expired };
700
709
  }
701
710
  if (!result.data.uid) {
702
- return { tokenData: undefined, error: 'Missing/bad userid in token' };
711
+ return { tokenData: undefined, error: 'Missing/bad userid in token', expired: false };
712
+ }
713
+ return { tokenData: result.data, error: undefined, expired: false };
714
+ }
715
+ jwtCookieOptions(apiReq) {
716
+ const conf = this.config;
717
+ const forwarded = apiReq.req.headers['x-forwarded-proto'];
718
+ const referer = apiReq.req.headers['origin'] ?? apiReq.req.headers['referer'];
719
+ const origin = typeof referer === 'string' ? referer : '';
720
+ const isHttps = forwarded === 'https' || apiReq.req.protocol === 'https';
721
+ const isLocalhost = origin.includes('localhost');
722
+ const options = {
723
+ httpOnly: true,
724
+ secure: true,
725
+ sameSite: 'strict',
726
+ domain: conf.cookieDomain || undefined,
727
+ path: '/',
728
+ maxAge: undefined
729
+ };
730
+ if (conf.devMode) {
731
+ options.secure = isHttps;
732
+ options.httpOnly = false;
733
+ options.sameSite = 'lax';
734
+ if (isLocalhost) {
735
+ options.domain = undefined;
736
+ }
703
737
  }
704
- return { tokenData: result.data, error: undefined };
738
+ return options;
739
+ }
740
+ setAccessCookie(apiReq, accessToken, sessionCookie) {
741
+ const conf = this.config;
742
+ const options = this.jwtCookieOptions(apiReq);
743
+ const accessMaxAge = Math.max(1, conf.accessExpiry) * 1000;
744
+ const accessOptions = sessionCookie ? options : { ...options, maxAge: accessMaxAge };
745
+ apiReq.res.cookie(conf.accessCookie, accessToken, accessOptions);
746
+ }
747
+ async tryRefreshAccessToken(apiReq) {
748
+ const conf = this.config;
749
+ if (!conf.refreshSecret || !conf.accessSecret) {
750
+ return null;
751
+ }
752
+ const rawRefresh = apiReq.req.cookies?.[conf.refreshCookie];
753
+ if (typeof rawRefresh !== 'string') {
754
+ return null;
755
+ }
756
+ const refreshToken = rawRefresh.trim();
757
+ if (!refreshToken) {
758
+ return null;
759
+ }
760
+ const verify = this.jwtVerify(refreshToken, conf.refreshSecret);
761
+ if (!verify.success || !verify.data) {
762
+ return null;
763
+ }
764
+ let stored = null;
765
+ try {
766
+ stored = await this.storageAdapter.getToken({ refreshToken });
767
+ }
768
+ catch {
769
+ return null;
770
+ }
771
+ if (!stored) {
772
+ return null;
773
+ }
774
+ const storedUid = String(stored.userId);
775
+ const verifyUid = verify.data.uid === undefined || verify.data.uid === null ? null : String(verify.data.uid);
776
+ if (verifyUid && verifyUid !== storedUid) {
777
+ return null;
778
+ }
779
+ const claims = verify.data;
780
+ const { exp: _exp, iat: _iat, nbf: _nbf, ...payload } = claims;
781
+ void _exp;
782
+ void _iat;
783
+ void _nbf;
784
+ // Ensure we never embed token secrets into refreshed access tokens.
785
+ delete payload.accessToken;
786
+ delete payload.refreshToken;
787
+ delete payload.userId;
788
+ delete payload.expires;
789
+ delete payload.issuedAt;
790
+ delete payload.lastSeenAt;
791
+ delete payload.status;
792
+ const access = this.jwtSign(payload, conf.accessSecret, conf.accessExpiry);
793
+ if (!access.success || !access.token) {
794
+ return null;
795
+ }
796
+ const updated = await this.updateToken({
797
+ refreshToken,
798
+ accessToken: access.token,
799
+ lastSeenAt: new Date()
800
+ });
801
+ if (!updated) {
802
+ return null;
803
+ }
804
+ this.setAccessCookie(apiReq, access.token, stored.sessionCookie ?? false);
805
+ if (apiReq.req.cookies) {
806
+ apiReq.req.cookies[conf.accessCookie] = access.token;
807
+ }
808
+ const verifiedAccess = await this.verifyJWT(access.token);
809
+ if (!verifiedAccess.tokenData) {
810
+ return null;
811
+ }
812
+ const refreshedStored = { ...stored, accessToken: access.token };
813
+ apiReq.authToken = refreshedStored;
814
+ return { token: access.token, tokenData: verifiedAccess.tokenData, stored: refreshedStored };
705
815
  }
706
816
  async authenticate(apiReq, authType) {
707
817
  if (authType === 'none') {
@@ -711,6 +821,7 @@ export class ApiServer {
711
821
  let token = null;
712
822
  const authHeader = apiReq.req.headers.authorization;
713
823
  const requiresAuthToken = this.requiresAuthToken(authType);
824
+ const allowRefresh = requiresAuthToken || (authType === 'maybe' && this.config.refreshMaybe);
714
825
  const apiKeyAuth = await this.tryAuthenticateApiKey(apiReq, authType, authHeader);
715
826
  if (apiKeyAuth) {
716
827
  return apiKeyAuth;
@@ -719,32 +830,84 @@ export class ApiServer {
719
830
  token = authHeader.slice(7).trim();
720
831
  }
721
832
  if (!token) {
722
- const access = apiReq.req.cookies?.dat;
833
+ const access = apiReq.req.cookies?.[this.config.accessCookie];
723
834
  if (access) {
724
835
  token = access;
725
836
  }
726
837
  }
838
+ let tokenData;
839
+ let error;
840
+ let expired = false;
727
841
  if (!token || token === null) {
728
- if (requiresAuthToken) {
729
- throw new ApiError({ code: 401, message: 'Authorization token is required (Bearer/cookie)' });
842
+ if (authType === 'maybe') {
843
+ if (!this.config.refreshMaybe) {
844
+ return null;
845
+ }
846
+ const refreshed = await this.tryRefreshAccessToken(apiReq);
847
+ if (!refreshed) {
848
+ return null;
849
+ }
850
+ token = refreshed.token;
851
+ tokenData = refreshed.tokenData;
852
+ error = undefined;
853
+ expired = false;
854
+ }
855
+ else if (requiresAuthToken) {
856
+ const refreshed = await this.tryRefreshAccessToken(apiReq);
857
+ if (!refreshed) {
858
+ throw new ApiError({ code: 401, message: 'Authorization token is required (Bearer/cookie)' });
859
+ }
860
+ token = refreshed.token;
861
+ tokenData = refreshed.tokenData;
862
+ error = undefined;
863
+ expired = false;
730
864
  }
731
865
  }
732
866
  if (!token) {
733
- if (authType === 'maybe') {
734
- return null;
735
- }
736
- else {
737
- throw new ApiError({ code: 401, message: 'Unauthorized Access - requires authentication' });
867
+ throw new ApiError({ code: 401, message: 'Unauthorized Access - requires authentication' });
868
+ }
869
+ if (!tokenData) {
870
+ const verified = await this.verifyJWT(token);
871
+ tokenData = verified.tokenData;
872
+ error = verified.error;
873
+ expired = verified.expired ?? false;
874
+ }
875
+ if (!tokenData && allowRefresh && expired) {
876
+ const refreshed = await this.tryRefreshAccessToken(apiReq);
877
+ if (refreshed) {
878
+ token = refreshed.token;
879
+ tokenData = refreshed.tokenData;
880
+ error = undefined;
738
881
  }
739
882
  }
740
- const { tokenData, error } = await this.verifyJWT(token);
741
883
  if (!tokenData) {
742
884
  throw new ApiError({ code: 401, message: 'Unathorized Access - ' + error });
743
885
  }
744
886
  const effectiveUserId = this.extractTokenUserId(tokenData);
745
887
  apiReq.realUid = this.resolveRealUserId(tokenData, effectiveUserId);
746
888
  if (this.shouldValidateStoredToken(authType)) {
747
- await this.assertStoredAccessToken(apiReq, token, tokenData);
889
+ try {
890
+ await this.assertStoredAccessToken(apiReq, token, tokenData);
891
+ }
892
+ catch (error) {
893
+ if (allowRefresh &&
894
+ error instanceof ApiError &&
895
+ error.code === 401 &&
896
+ error.message === 'Authorization token is no longer valid') {
897
+ const refreshed = await this.tryRefreshAccessToken(apiReq);
898
+ if (!refreshed) {
899
+ throw error;
900
+ }
901
+ token = refreshed.token;
902
+ tokenData = refreshed.tokenData;
903
+ const refreshedUserId = this.extractTokenUserId(tokenData);
904
+ apiReq.realUid = this.resolveRealUserId(tokenData, refreshedUserId);
905
+ await this.assertStoredAccessToken(apiReq, token, tokenData);
906
+ }
907
+ else {
908
+ throw error;
909
+ }
910
+ }
748
911
  }
749
912
  apiReq.token = token;
750
913
  return tokenData;
@@ -786,6 +949,9 @@ export class ApiServer {
786
949
  }
787
950
  async assertStoredAccessToken(apiReq, token, tokenData) {
788
951
  const userId = String(this.extractTokenUserId(tokenData));
952
+ if (apiReq.authToken && apiReq.authToken.accessToken === token && String(apiReq.authToken.userId) === userId) {
953
+ return;
954
+ }
789
955
  const stored = await this.storageAdapter.getToken({
790
956
  accessToken: token,
791
957
  userId
@@ -825,32 +991,100 @@ export class ApiServer {
825
991
  }
826
992
  return rawReal;
827
993
  }
828
- handle_request(handler, auth) {
994
+ useExpress(pathOrHandler, ...handlers) {
995
+ if (typeof pathOrHandler === 'string') {
996
+ this.app.use(pathOrHandler, ...handlers);
997
+ }
998
+ else {
999
+ this.app.use(pathOrHandler, ...handlers);
1000
+ }
1001
+ this.ensureApiNotFoundOrdering();
1002
+ return this;
1003
+ }
1004
+ createApiRequest(req, res) {
1005
+ const apiReq = {
1006
+ server: this,
1007
+ req,
1008
+ res,
1009
+ token: '',
1010
+ tokenData: null,
1011
+ realUid: null,
1012
+ getClientInfo: () => ensureClientInfo(apiReq),
1013
+ getClientIp: () => ensureClientInfo(apiReq).ip,
1014
+ getClientIpChain: () => ensureClientInfo(apiReq).ipchain,
1015
+ getRealUid: () => apiReq.realUid ?? null,
1016
+ isImpersonating: () => {
1017
+ const realUid = apiReq.realUid;
1018
+ const tokenUid = apiReq.tokenData?.uid;
1019
+ if (realUid === null || realUid === undefined) {
1020
+ return false;
1021
+ }
1022
+ if (tokenUid === null || tokenUid === undefined) {
1023
+ return false;
1024
+ }
1025
+ return realUid !== tokenUid;
1026
+ }
1027
+ };
1028
+ return apiReq;
1029
+ }
1030
+ expressAuth(auth) {
829
1031
  return async (req, res, next) => {
830
- void next;
831
- const apiReq = {
832
- server: this,
833
- req,
834
- res,
835
- token: '',
836
- tokenData: null,
837
- realUid: null,
838
- getClientInfo: () => ensureClientInfo(apiReq),
839
- getClientIp: () => ensureClientInfo(apiReq).ip,
840
- getClientIpChain: () => ensureClientInfo(apiReq).ipchain,
841
- getRealUid: () => apiReq.realUid ?? null,
842
- isImpersonating: () => {
843
- const realUid = apiReq.realUid;
844
- const tokenUid = apiReq.tokenData?.uid;
845
- if (realUid === null || realUid === undefined) {
846
- return false;
847
- }
848
- if (tokenUid === null || tokenUid === undefined) {
849
- return false;
850
- }
851
- return realUid !== tokenUid;
1032
+ const apiReq = this.createApiRequest(req, res);
1033
+ req.apiReq = apiReq;
1034
+ res.locals.apiReq = apiReq;
1035
+ this.currReq = apiReq;
1036
+ try {
1037
+ if (this.config.hydrateGetBody) {
1038
+ hydrateGetBody(req);
1039
+ }
1040
+ if (this.config.debug) {
1041
+ this.dumpRequest(apiReq);
852
1042
  }
1043
+ apiReq.tokenData = await this.authenticate(apiReq, auth.type);
1044
+ await this.authorize(apiReq, auth.req);
1045
+ next();
1046
+ }
1047
+ catch (error) {
1048
+ next(error);
1049
+ }
1050
+ };
1051
+ }
1052
+ expressErrorHandler() {
1053
+ return (error, _req, res, next) => {
1054
+ void _req;
1055
+ if (res.headersSent) {
1056
+ next(error);
1057
+ return;
1058
+ }
1059
+ if (error instanceof ApiError || isApiErrorLike(error)) {
1060
+ const apiError = error;
1061
+ const normalizedErrors = apiError.errors && typeof apiError.errors === 'object' && !Array.isArray(apiError.errors)
1062
+ ? apiError.errors
1063
+ : {};
1064
+ const errorPayload = {
1065
+ success: false,
1066
+ code: apiError.code,
1067
+ message: apiError.message,
1068
+ data: apiError.data ?? null,
1069
+ errors: normalizedErrors
1070
+ };
1071
+ res.status(apiError.code).json(errorPayload);
1072
+ return;
1073
+ }
1074
+ const errorPayload = {
1075
+ success: false,
1076
+ code: 500,
1077
+ message: this.guessExceptionText(error),
1078
+ data: null,
1079
+ errors: {}
853
1080
  };
1081
+ res.status(500).json(errorPayload);
1082
+ };
1083
+ }
1084
+ handle_request(handler, auth) {
1085
+ return async (req, res, next) => {
1086
+ void next;
1087
+ const apiReq = this.createApiRequest(req, res);
854
1088
  this.currReq = apiReq;
855
1089
  try {
856
1090
  if (this.config.hydrateGetBody) {
@@ -873,7 +1107,7 @@ export class ApiServer {
873
1107
  throw new ApiError({ code: 500, message: 'Handler result must start with a numeric status code' });
874
1108
  }
875
1109
  const message = typeof rawMessage === 'string' ? rawMessage : 'Success';
876
- const responsePayload = { code, message, data };
1110
+ const responsePayload = { success: true, code, message, data, errors: {} };
877
1111
  if (this.config.debug) {
878
1112
  this.dumpResponse(apiReq, responsePayload, code);
879
1113
  }
@@ -886,6 +1120,7 @@ export class ApiServer {
886
1120
  ? apiError.errors
887
1121
  : {};
888
1122
  const errorPayload = {
1123
+ success: false,
889
1124
  code: apiError.code,
890
1125
  message: apiError.message,
891
1126
  data: apiError.data ?? null,
@@ -898,6 +1133,7 @@ export class ApiServer {
898
1133
  }
899
1134
  else {
900
1135
  const errorPayload = {
1136
+ success: false,
901
1137
  code: 500,
902
1138
  message: this.guessExceptionText(error),
903
1139
  data: null,
@@ -1,6 +1,6 @@
1
1
  import { type ApiRequest, type ApiRoute, type ApiServer } from '../api-server-base.js';
2
2
  import { BaseAuthModule, type AuthProviderModule } from './module.js';
3
- import type { AuthIdentifier, AuthStorage } from './types.js';
3
+ import type { AuthAdapter, AuthIdentifier } from './types.js';
4
4
  import type { OAuthCallbackParams, OAuthCallbackResult, OAuthStartParams, OAuthStartResult } from '../oauth/types.js';
5
5
  import type { TokenPair, Token } from '../token/types.js';
6
6
  interface CanImpersonateContext<UserEntity> {
@@ -46,7 +46,7 @@ export default class AuthModule<UserEntity, PublicUser> extends BaseAuthModule<U
46
46
  private readonly defaultDomain?;
47
47
  private readonly canImpersonateHook?;
48
48
  constructor(options?: AuthModuleOptions<UserEntity>);
49
- protected get storage(): AuthStorage<UserEntity, PublicUser>;
49
+ protected get storage(): AuthAdapter<UserEntity, PublicUser>;
50
50
  protected canImpersonate(apiReq: ApiRequest, realUser: UserEntity, targetUser: UserEntity): Promise<boolean>;
51
51
  protected ensureImpersonationAllowed(apiReq: ApiRequest, realUser: UserEntity, targetUser: UserEntity): Promise<void>;
52
52
  protected buildTokenPayload(user: UserEntity, metadata?: TokenMetadata): TokenClaims;
@@ -57,6 +57,9 @@ export default class AuthModule<UserEntity, PublicUser> extends BaseAuthModule<U
57
57
  private resolveSessionPreferences;
58
58
  private mergeSessionPreferences;
59
59
  private sessionPrefsFromRecord;
60
+ private validateCredentialId;
61
+ private normalizeCredentialId;
62
+ private toIsoDate;
60
63
  private cookieOptions;
61
64
  private setJwtCookies;
62
65
  issueTokens(apiReq: ApiRequest, user: UserEntity, metadata?: TokenIssueOptions): Promise<TokenPair>;
@@ -76,6 +79,8 @@ export default class AuthModule<UserEntity, PublicUser> extends BaseAuthModule<U
76
79
  private postWhoAmI;
77
80
  private postPasskeyChallenge;
78
81
  private postPasskeyVerify;
82
+ private getPasskeys;
83
+ private deletePasskey;
79
84
  private postImpersonation;
80
85
  private deleteImpersonation;
81
86
  private getUserFromPasskey;
@@ -91,6 +96,10 @@ export default class AuthModule<UserEntity, PublicUser> extends BaseAuthModule<U
91
96
  private resolveClientAuthentication;
92
97
  private assertRedirectUriAllowed;
93
98
  private resolveUserForOAuth;
99
+ private hasPasskeyService;
100
+ private hasOAuthStore;
101
+ private storageImplements;
102
+ private storageImplementsAll;
94
103
  defineRoutes(): ApiRoute[];
95
104
  }
96
105
  export {};