@soapjs/soap-auth 0.1.0 → 0.2.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.
Files changed (41) hide show
  1. package/README.md +475 -8
  2. package/build/factories/http-auth-strategy.factory.js +1 -2
  3. package/build/factories/index.d.ts +3 -0
  4. package/build/factories/index.js +19 -0
  5. package/build/index.d.ts +4 -25
  6. package/build/index.js +4 -25
  7. package/build/session/index.d.ts +3 -0
  8. package/build/session/index.js +19 -0
  9. package/build/soap-auth.d.ts +9 -9
  10. package/build/soap-auth.js +64 -34
  11. package/build/strategies/api-key/api-key.strategy.d.ts +4 -3
  12. package/build/strategies/api-key/api-key.strategy.js +9 -6
  13. package/build/strategies/api-key/api-key.types.d.ts +2 -4
  14. package/build/strategies/base-auth.strategy.d.ts +4 -3
  15. package/build/strategies/base-auth.strategy.js +22 -6
  16. package/build/strategies/basic/basic.strategy.d.ts +5 -11
  17. package/build/strategies/basic/basic.strategy.js +14 -19
  18. package/build/strategies/basic/basic.types.d.ts +2 -2
  19. package/build/strategies/{credential-based-auth.strategy.d.ts → credential-auth.strategy.d.ts} +15 -12
  20. package/build/strategies/{credential-based-auth.strategy.js → credential-auth.strategy.js} +95 -46
  21. package/build/strategies/index.d.ts +16 -0
  22. package/build/strategies/index.js +32 -0
  23. package/build/strategies/jwt/jwt.strategy.d.ts +17 -2
  24. package/build/strategies/jwt/jwt.strategy.js +118 -45
  25. package/build/strategies/jwt/jwt.tools.d.ts +7 -3
  26. package/build/strategies/jwt/jwt.tools.js +80 -41
  27. package/build/strategies/jwt/jwt.types.d.ts +4 -14
  28. package/build/strategies/local/local.strategy.d.ts +3 -9
  29. package/build/strategies/local/local.strategy.js +7 -58
  30. package/build/strategies/local/local.types.d.ts +2 -2
  31. package/build/strategies/oauth2/oauth2.strategy.d.ts +21 -7
  32. package/build/strategies/oauth2/oauth2.strategy.js +161 -52
  33. package/build/strategies/oauth2/oauth2.types.d.ts +9 -17
  34. package/build/strategies/token-auth.strategy.d.ts +25 -0
  35. package/build/strategies/token-auth.strategy.js +78 -0
  36. package/build/tools/index.d.ts +3 -0
  37. package/build/tools/index.js +19 -0
  38. package/build/types.d.ts +94 -68
  39. package/package.json +3 -3
  40. package/build/strategies/token-based-auth.strategy.d.ts +0 -25
  41. package/build/strategies/token-based-auth.strategy.js +0 -124
@@ -0,0 +1,3 @@
1
+ export * from "./session.tools";
2
+ export * from "./token.tools";
3
+ export * from "./tools";
@@ -0,0 +1,19 @@
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 __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./session.tools"), exports);
18
+ __exportStar(require("./token.tools"), exports);
19
+ __exportStar(require("./tools"), exports);
package/build/types.d.ts CHANGED
@@ -36,19 +36,22 @@ export type Credentials = {
36
36
  [key: string]: unknown;
37
37
  };
38
38
  export interface AuthResultConfig<TContext = unknown, TUser = unknown> {
39
- onSuccess?: (context: AuthSuccessContext<TUser, TContext>) => Promise<void> | void;
40
- onFailure?: (context: AuthFailureContext<TContext>) => Promise<void> | void;
39
+ onSuccess?: (action: string, context: AuthSuccessContext<TUser, TContext>) => Promise<void> | void;
40
+ onFailure?: (action: string, context: AuthFailureContext<TContext>) => Promise<void> | void;
41
41
  }
42
42
  export interface SecurityConfig {
43
- security?: {
44
- maxFailedLoginAttempts?: number;
45
- lockoutDuration?: number;
46
- notifyOnLockout?: (account: any) => Promise<void>;
47
- };
43
+ maxFailedLoginAttempts?: number;
44
+ lockoutDuration?: number;
45
+ notifyOnLockout?: (account: any) => Promise<void>;
48
46
  }
49
- export interface BaseAuthStrategyConfig<TContext = unknown, TUser = unknown> extends AccountLockConfig<TContext>, RateLimitConfig, RoleAuthorizationConfig<TUser>, SecurityConfig {
47
+ export interface BaseAuthStrategyConfig<TContext = unknown, TUser = unknown> extends AuthResultConfig<TContext, TUser> {
50
48
  mfa?: MfaConfig<TUser, TContext>;
51
49
  session?: SessionConfig;
50
+ role?: RoleAuthorizationConfig<TUser>;
51
+ rateLimit?: RateLimitConfig;
52
+ security?: SecurityConfig;
53
+ lock?: AccountLockConfig<TContext>;
54
+ failedAttempts?: FailedAttemptsConfig;
52
55
  }
53
56
  export interface AuditLoggingConfig<TContext = unknown> {
54
57
  logAttempt?: (userId: string, success: boolean, context?: TContext) => Promise<void>;
@@ -75,55 +78,58 @@ export interface PasswordPolicyConfig {
75
78
  getLastPasswordChange?: (identifier: string) => Date;
76
79
  forcePasswordChangeOnFirstLogin?: boolean;
77
80
  passwordExpirationDays?: number;
81
+ isPasswordChangeRequired?: (identifier: string) => Promise<boolean>;
82
+ generateResetToken?: (identifier: string) => Promise<string>;
83
+ sendResetEmail?: (identifier: string, token: string) => Promise<void>;
84
+ validateResetToken?: (token: string) => Promise<boolean>;
85
+ updatePassword?: (identifier: string, newPassword: string) => Promise<void>;
86
+ }
87
+ export interface UserConfig {
88
+ getUserData: (payload: any) => Promise<any>;
89
+ validateUser?: (payload: any) => Promise<any>;
90
+ }
91
+ export interface CredentailsConfig<TContext = any> {
92
+ extractCredentials: <TCredentials = {
93
+ identifier: string;
94
+ password: string;
95
+ }>(context: TContext) => TCredentials;
96
+ verifyCredentials: (identifier: string, password: string) => Promise<boolean>;
78
97
  }
79
- export interface CredentialBasedAuthStrategyConfig<TContext = unknown, TUser = unknown> extends BaseAuthStrategyConfig<TContext, TUser> {
98
+ export interface FailedAttemptsConfig {
99
+ incrementFailedAttempts?: (identifier: string, ...rest: unknown[]) => Promise<void>;
100
+ resetFailedAttempts?: (identifier: string, ...rest: unknown[]) => Promise<void>;
101
+ getFailedAttempts?: (identifier: string, ...rest: unknown[]) => Promise<number>;
102
+ }
103
+ export interface CredentialAuthStrategyConfig<TContext = unknown, TUser = unknown> extends BaseAuthStrategyConfig<TContext, TUser> {
80
104
  passwordPolicy?: PasswordPolicyConfig;
81
105
  audit?: AuditLoggingConfig<TContext>;
82
- logout: {} & AuthResultConfig<TContext, TUser>;
83
- login: {
84
- extractCredentials: (context: TContext) => Promise<{
85
- identifier: string;
86
- password: string;
87
- }>;
88
- retrieveUserData: (identifier: string) => Promise<TUser | null>;
89
- verifyUserCredentials: (identifier: string, password: string) => Promise<boolean>;
90
- incrementFailedAttempts?: (identifier: string) => Promise<void>;
91
- resetFailedAttempts?: (identifier: string) => Promise<void>;
92
- getFailedAttempts?: (identifier: string) => Promise<number>;
93
- } & AuthResultConfig<TContext, TUser>;
94
- passwordReset?: {
95
- generateResetToken?: (identifier: string) => Promise<string>;
96
- sendResetEmail?: (identifier: string, token: string) => Promise<void>;
97
- validateResetToken?: (token: string) => Promise<boolean>;
98
- updatePassword?: (identifier: string, newPassword: string) => Promise<void>;
99
- } & AuthResultConfig<TContext, TUser>;
100
- }
101
- export interface TokenBasedAuthStrategyConfig<TContext = unknown, TUser = unknown> extends BaseAuthStrategyConfig<TContext, TUser>, TokenRotationConfig<TUser> {
102
- tokens?: TokenHandlersConfig;
103
- login: {
104
- retrieveUserData: (identifier: string) => Promise<TUser | null>;
105
- } & AuthResultConfig<TContext, TUser>;
106
- logout: {} & AuthResultConfig<TContext, TUser>;
107
- }
108
- export interface TokenRotationConfig<TUser = unknown> {
109
- enableRotation?: boolean;
110
- maxRotations?: number;
111
- storeUsedTokens?: boolean;
112
- getRefreshToken?: (user: TUser) => Promise<string>;
113
- rotateToken?: (refreshToken: string) => Promise<{
114
- accessToken: string;
115
- refreshToken: string;
116
- }>;
117
- onTokenRotated?: (user: TUser, newTokens: {
118
- accessToken: string;
119
- refreshToken: string;
120
- }) => Promise<void>;
121
- onTokenRotationFailure?: (user: TUser, error: Error) => Promise<void>;
106
+ credentials?: CredentailsConfig<TContext>;
107
+ user?: UserConfig;
108
+ routes?: {
109
+ login?: AuthRouteConfig;
110
+ logout?: AuthRouteConfig;
111
+ resetPassword?: AuthRouteConfig;
112
+ };
113
+ }
114
+ export type AuthRouteConfig = {
115
+ path?: string;
116
+ method?: string;
117
+ };
118
+ export interface TokenAuthStrategyConfig<TContext = unknown, TUser = unknown> extends BaseAuthStrategyConfig<TContext, TUser> {
119
+ user?: UserConfig;
120
+ routes: {
121
+ login?: AuthRouteConfig;
122
+ logout?: AuthRouteConfig;
123
+ refresh?: AuthRouteConfig;
124
+ [key: string]: AuthRouteConfig;
125
+ };
126
+ accessToken?: TokenConfig<TContext>;
127
+ refreshToken?: TokenConfig<TContext>;
122
128
  }
123
129
  export interface AccountLockConfig<TContext = unknown> {
124
130
  logFailedAttempt?: (account: any, context?: TContext) => Promise<void>;
125
- lockAccount?: (account: any, ...args: unknown[]) => Promise<void>;
126
- isAccountLocked?: (account: any, ...args: unknown[]) => Promise<boolean>;
131
+ lockAccount?: (account: any) => Promise<void>;
132
+ isAccountLocked?: (account: any, context?: TContext) => Promise<boolean>;
127
133
  }
128
134
  export interface RateLimitConfig {
129
135
  checkRateLimit?: (...args: unknown[]) => Promise<boolean>;
@@ -158,7 +164,7 @@ export type AuthResult<TUser, TSessionData = unknown> = {
158
164
  };
159
165
  export interface AuthStrategy<TContext = unknown, TUser = unknown> {
160
166
  init?(...args: unknown[]): Promise<void>;
161
- authenticate(context?: TContext, ...args: unknown[]): Promise<AuthResult<TUser>>;
167
+ authenticate(context?: TContext, ...args: unknown[]): Promise<AuthResult<TUser> | null>;
162
168
  authorize?(user: any, action: string, resource?: string): Promise<boolean>;
163
169
  refresh?(refreshToken: string): Promise<string>;
164
170
  logout?(context?: TContext): Promise<void>;
@@ -184,7 +190,6 @@ export interface SoapSocketAuthConfig<TContext = unknown, TUser = unknown> {
184
190
  }
185
191
  export interface SoapAuthConfig<TContext = unknown, TUser = unknown> {
186
192
  session?: SessionConfig;
187
- tokens?: TokenHandlersConfig;
188
193
  http?: SoapHttpAuthConfig<TContext, TUser>;
189
194
  socket?: SoapSocketAuthConfig<TContext, TUser>;
190
195
  logger?: Soap.Logger;
@@ -230,22 +235,43 @@ export interface StorageContext {
230
235
  encrypt?: (data: string) => Promise<string> | string;
231
236
  decrypt?: (data: string) => Promise<string> | string;
232
237
  }
233
- export interface TokenHandlerConfig {
238
+ export interface TokenIssuerConfig {
234
239
  secretKey: string;
235
- expiresIn: string | number;
236
- audience?: string | string[];
237
- issuer?: string | string[];
238
- subject?: string;
239
- tokenType?: string;
240
+ options: {
241
+ expiresIn: string | number;
242
+ audience?: string | string[];
243
+ issuer?: string | string[];
244
+ subject?: string;
245
+ [option: string]: unknown;
246
+ };
240
247
  generate?: (payload: any) => string;
248
+ }
249
+ export interface TokenVerifierConfig {
250
+ options: {
251
+ [option: string]: unknown;
252
+ };
241
253
  verify?: (token: string) => Promise<any>;
242
- store?: (token: string, data: any, expiresIn: number) => Promise<void>;
243
- retrieve?: (context: any) => Promise<string | null>;
244
- remove?: (context: any) => Promise<void>;
245
- embed?: (context: any, token: string) => void;
246
- rotate?: (oldToken: string) => Promise<string>;
247
- }
248
- export interface TokenHandlersConfig {
249
- access: TokenHandlerConfig;
250
- refresh?: TokenHandlerConfig;
254
+ }
255
+ export interface TokenPersistenceConfig {
256
+ store?: (token: string, data: any, expiresIn: string | number) => Promise<void>;
257
+ read?: (...args: any[]) => Promise<string | null>;
258
+ remove?: (...args: any[]) => Promise<void>;
259
+ }
260
+ export interface TokenConfig<TContext = any> {
261
+ embed?: (context: TContext, token: string) => void;
262
+ retrieve?: (context: TContext) => Promise<string | null>;
263
+ rotation?: TokenRotationConfig;
264
+ issuer?: TokenIssuerConfig;
265
+ verifier?: TokenVerifierConfig;
266
+ persistence?: TokenPersistenceConfig;
267
+ additional?: Record<string, unknown>;
268
+ }
269
+ export interface TokenRotationConfig {
270
+ maxRotations?: number;
271
+ rotateToken?: (token: string) => Promise<string>;
272
+ }
273
+ export interface PKCEConfig<TContext> {
274
+ generateCodeVerifier?: () => string;
275
+ storeCodeVerifier?: (context: TContext, codeVerifier: string) => void;
276
+ retrieveCodeVerifier?: (context: TContext) => string | null;
251
277
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soapjs/soap-auth",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "",
5
5
  "homepage": "https://docs.soapjs.com",
6
6
  "repository": "https://github.com/soapjs/soap-auth",
@@ -15,14 +15,14 @@
15
15
  "prepublish": "npm run clean && tsc --project tsconfig.build.json"
16
16
  },
17
17
  "devDependencies": {
18
- "@soapjs/soap": "^0.5.2",
18
+ "@soapjs/soap": "^0.5.8",
19
19
  "@types/jest": "^27.0.3",
20
20
  "jest": "^27.4.5",
21
21
  "ts-jest": "^27.1.3",
22
22
  "typescript": "^4.8.2"
23
23
  },
24
24
  "peerDependencies": {
25
- "@soapjs/soap": ">=0.5.2"
25
+ "@soapjs/soap": ">=0.5.8"
26
26
  },
27
27
  "dependencies": {
28
28
  "axios": "^1.7.9",
@@ -1,25 +0,0 @@
1
- import * as Soap from "@soapjs/soap";
2
- import { AuthResult, TokenBasedAuthStrategyConfig } from "../types";
3
- import { BaseAuthStrategy } from "./base-auth.strategy";
4
- import { TokenHandlerConfig } from "../types";
5
- import { SessionHandler } from "../session/session-handler";
6
- export declare abstract class TokenBasedAuthStrategy<TContext = unknown, TUser = unknown> extends BaseAuthStrategy<TContext, TUser> {
7
- protected config: TokenBasedAuthStrategyConfig<TContext, TUser>;
8
- protected accessTokenHandler: TokenHandlerConfig;
9
- protected refreshTokenHandler?: TokenHandlerConfig;
10
- protected session?: SessionHandler;
11
- protected logger?: Soap.Logger;
12
- constructor(config: TokenBasedAuthStrategyConfig<TContext, TUser>, accessTokenHandler: TokenHandlerConfig, refreshTokenHandler?: TokenHandlerConfig, session?: SessionHandler, logger?: Soap.Logger);
13
- protected retrieveUser(decodedToken: any): Promise<TUser | null>;
14
- authenticate(context: TContext): Promise<AuthResult<TUser>>;
15
- logout(context: TContext): Promise<void>;
16
- generateTokens(user: TUser, context: TContext): Promise<{
17
- accessToken: string;
18
- refreshToken?: string;
19
- }>;
20
- rotateToken(context: TContext): Promise<{
21
- accessToken: string;
22
- refreshToken?: string;
23
- }>;
24
- isTokenExpired(token: string): Promise<boolean>;
25
- }
@@ -1,124 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TokenBasedAuthStrategy = void 0;
4
- const base_auth_strategy_1 = require("./base-auth.strategy");
5
- const errors_1 = require("../errors");
6
- class TokenBasedAuthStrategy extends base_auth_strategy_1.BaseAuthStrategy {
7
- config;
8
- accessTokenHandler;
9
- refreshTokenHandler;
10
- session;
11
- logger;
12
- constructor(config, accessTokenHandler, refreshTokenHandler, session, logger) {
13
- super(config, session, logger);
14
- this.config = config;
15
- this.accessTokenHandler = accessTokenHandler;
16
- this.refreshTokenHandler = refreshTokenHandler;
17
- this.session = session;
18
- this.logger = logger;
19
- }
20
- retrieveUser(decodedToken) {
21
- return this.config.login.retrieveUserData(decodedToken);
22
- }
23
- async authenticate(context) {
24
- try {
25
- let accessToken = await this.accessTokenHandler.retrieve?.(context);
26
- await this.checkRateLimit(context);
27
- if (accessToken) {
28
- try {
29
- const decoded = await this.accessTokenHandler.verify?.(accessToken);
30
- const user = await this.retrieveUser(decoded);
31
- if (!user) {
32
- throw new errors_1.UserNotFoundError();
33
- }
34
- await this.isAuthorized(user);
35
- return { user, tokens: { accessToken } };
36
- }
37
- catch (error) {
38
- this.logger?.warn("Access token is invalid or expired, trying refresh token...");
39
- }
40
- }
41
- const refreshToken = await this.refreshTokenHandler?.retrieve?.(context);
42
- if (!refreshToken) {
43
- throw new errors_1.MissingTokenError();
44
- }
45
- accessToken = await this.refreshTokenHandler?.rotate?.(refreshToken);
46
- this.accessTokenHandler.embed?.(context, accessToken);
47
- const decoded = await this.accessTokenHandler.verify?.(accessToken);
48
- const user = await this.retrieveUser(decoded);
49
- if (!user) {
50
- throw new errors_1.UserNotFoundError();
51
- }
52
- await this.isAuthorized(user);
53
- return { user, tokens: { accessToken, refreshToken } };
54
- }
55
- catch (error) {
56
- this.logger?.error("Authentication failed:", error);
57
- throw new errors_1.AuthError(error, "Authentication failed.");
58
- }
59
- }
60
- async logout(context) {
61
- try {
62
- await this.accessTokenHandler.remove?.(context);
63
- if (this.refreshTokenHandler) {
64
- await this.refreshTokenHandler.remove?.(context);
65
- }
66
- await this.config.logout.onSuccess?.(context);
67
- this.logger?.info("User logged out successfully.");
68
- }
69
- catch (error) {
70
- this.logger?.error("Error during logout:", error);
71
- await this.config.logout.onFailure?.({ context, error });
72
- throw new errors_1.AuthError(error, "Logout process failed.");
73
- }
74
- }
75
- async generateTokens(user, context) {
76
- const payload = { userId: user.id, roles: user.roles };
77
- const accessToken = this.accessTokenHandler.generate?.(payload);
78
- if (!accessToken)
79
- throw new Error("Failed to generate access token.");
80
- await this.accessTokenHandler.store?.(accessToken, user, +this.accessTokenHandler.expiresIn);
81
- this.accessTokenHandler.embed?.(context, accessToken);
82
- let refreshToken;
83
- if (this.refreshTokenHandler) {
84
- refreshToken = this.refreshTokenHandler.generate?.(payload);
85
- if (refreshToken) {
86
- await this.refreshTokenHandler.store?.(refreshToken, user, +this.refreshTokenHandler.expiresIn);
87
- this.refreshTokenHandler.embed?.(context, refreshToken);
88
- }
89
- }
90
- return { accessToken, refreshToken };
91
- }
92
- async rotateToken(context) {
93
- try {
94
- if (!this.refreshTokenHandler) {
95
- throw new Error("Refresh token handler is not configured.");
96
- }
97
- const refreshToken = await this.refreshTokenHandler.retrieve?.(context);
98
- if (!refreshToken) {
99
- throw new errors_1.MissingTokenError("Refresh");
100
- }
101
- const newAccessToken = await this.refreshTokenHandler.rotate?.(refreshToken);
102
- this.accessTokenHandler.embed?.(context, newAccessToken);
103
- return { accessToken: newAccessToken, refreshToken };
104
- }
105
- catch (error) {
106
- this.logger?.error("Token rotation failed:", error);
107
- throw new errors_1.InvalidTokenError("Refresh");
108
- }
109
- }
110
- async isTokenExpired(token) {
111
- try {
112
- const decoded = JSON.parse(Buffer.from(token.split(".")[1], "base64").toString());
113
- if (!decoded.exp)
114
- return false;
115
- const currentTime = Math.floor(Date.now() / 1000);
116
- return decoded.exp < currentTime;
117
- }
118
- catch (error) {
119
- this.logger?.warn("Failed to decode token:", error);
120
- return false;
121
- }
122
- }
123
- }
124
- exports.TokenBasedAuthStrategy = TokenBasedAuthStrategy;