@soapjs/soap-auth 0.1.1 → 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 -1
  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 +18 -2
  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 -57
  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 +3 -27
  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 +158 -49
  33. package/build/strategies/oauth2/oauth2.types.d.ts +8 -16
  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 +87 -57
  39. package/package.json +1 -1
  40. package/build/strategies/token-based-auth.strategy.d.ts +0 -25
  41. package/build/strategies/token-based-auth.strategy.js +0 -130
@@ -23,57 +23,96 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.prepareRefreshTokenConfig = exports.prepareAccessTokenConfig = void 0;
26
+ exports.clearDefaultJwtCookie = exports.clearDefaultJwtHeader = exports.setDefaultJwtHeader = exports.setDefaultJwtCookie = exports.prepareRefreshTokenConfig = exports.prepareAccessTokenConfig = void 0;
27
27
  const Soap = __importStar(require("@soapjs/soap"));
28
28
  const prepareAccessTokenConfig = (config) => {
29
29
  return Soap.removeUndefinedProperties({
30
- ...config.accessToken,
31
- tokenType: "Access",
32
- expiresIn: config.accessToken.expiresIn || "1h",
33
- signOptions: {
34
- ...config.accessToken.signOptions,
35
- algorithm: config.accessToken.signOptions.algorithm || "HS256",
36
- expiresIn: config.accessToken.expiresIn || "1h",
37
- audience: config.accessToken.audience,
38
- issuer: config.accessToken.issuer,
39
- subject: config.accessToken.subject,
30
+ ...config,
31
+ generation: {
32
+ ...config.issuer.options,
33
+ expiresIn: config.issuer.options.expiresIn || "1h",
34
+ algorithm: config.issuer.options.algorithm || "HS256",
35
+ },
36
+ verification: {
37
+ ...config.verifier.options,
38
+ algorithms: config.verifier.options.algorithms || ["HS256"],
39
+ expiresIn: config.verifier.options.expiresIn || "1h",
40
40
  },
41
- verifyOptions: config.accessToken.verifyOptions
42
- ? {
43
- ...config.accessToken.verifyOptions,
44
- algorithms: config.accessToken.verifyOptions.algorithms || ["HS256"],
45
- expiresIn: config.accessToken.expiresIn || "1h",
46
- audience: config.accessToken.audience,
47
- issuer: config.accessToken.issuer,
48
- subject: config.accessToken.subject,
49
- }
50
- : {},
51
41
  });
52
42
  };
53
43
  exports.prepareAccessTokenConfig = prepareAccessTokenConfig;
54
44
  const prepareRefreshTokenConfig = (config) => {
55
45
  return Soap.removeUndefinedProperties({
56
- ...config.refreshToken,
57
- secretKey: config.refreshToken.secretKey,
58
- tokenType: "Refresh",
59
- signOptions: {
60
- ...config.refreshToken.signOptions,
61
- algorithm: config.refreshToken.signOptions.algorithm || "HS256",
62
- expiresIn: config.refreshToken.expiresIn || "7d",
63
- audience: config.refreshToken.audience,
64
- issuer: config.refreshToken.issuer,
65
- subject: config.refreshToken.subject,
46
+ ...config,
47
+ generation: {
48
+ ...config.issuer,
49
+ expiresIn: config.issuer.options.expiresIn || "7d",
50
+ algorithm: config.issuer.options.algorithm || "HS256",
51
+ },
52
+ verification: {
53
+ ...config.verifier.options,
54
+ algorithms: config.verifier.options.algorithms || ["HS256"],
55
+ expiresIn: config.verifier.options.expiresIn || "7d",
66
56
  },
67
- verifyOptions: config.refreshToken.verifyOptions
68
- ? {
69
- ...config.refreshToken.verifyOptions,
70
- algorithm: config.refreshToken.verifyOptions.algorithms || ["HS256"],
71
- expiresIn: config.refreshToken.expiresIn || "7d",
72
- audience: config.refreshToken.audience,
73
- issuer: config.refreshToken.issuer,
74
- subject: config.refreshToken.subject,
75
- }
76
- : {},
77
57
  });
78
58
  };
79
59
  exports.prepareRefreshTokenConfig = prepareRefreshTokenConfig;
60
+ const setDefaultJwtCookie = (token, context) => {
61
+ const options = {
62
+ httpOnly: true,
63
+ secure: true,
64
+ sameSite: "Strict",
65
+ maxAge: 7 * 24 * 60 * 60 * 1000,
66
+ };
67
+ if (context?.res) {
68
+ context.res.cookie("refreshToken", token, options);
69
+ }
70
+ else if (context?.response) {
71
+ context.response.cookie("refreshToken", token, options);
72
+ }
73
+ else if (context?.cookie) {
74
+ context.cookie("refreshToken", token, options);
75
+ }
76
+ };
77
+ exports.setDefaultJwtCookie = setDefaultJwtCookie;
78
+ const setDefaultJwtHeader = (token, context) => {
79
+ if (typeof context?.res?.setHeader === "function") {
80
+ context.res.setHeader("Authorization", `Bearer ${token}`);
81
+ }
82
+ else if (typeof context?.response?.setHeader === "function") {
83
+ context.response.setHeader("Authorization", `Bearer ${token}`);
84
+ }
85
+ else if (typeof context?.setHeader === "function") {
86
+ context.setHeader("Authorization", `Bearer ${token}`);
87
+ }
88
+ };
89
+ exports.setDefaultJwtHeader = setDefaultJwtHeader;
90
+ const clearDefaultJwtHeader = (context) => {
91
+ if (typeof context?.res?.setHeader === "function") {
92
+ context.res.setHeader("Authorization", ``);
93
+ }
94
+ else if (typeof context?.response?.setHeader === "function") {
95
+ context.response.setHeader("Authorization", ``);
96
+ }
97
+ else if (typeof context?.setHeader === "function") {
98
+ context.setHeader("Authorization", ``);
99
+ }
100
+ };
101
+ exports.clearDefaultJwtHeader = clearDefaultJwtHeader;
102
+ const clearDefaultJwtCookie = (context) => {
103
+ const options = {
104
+ httpOnly: true,
105
+ secure: true,
106
+ sameSite: "Strict",
107
+ };
108
+ if (typeof context?.res?.clearCookie === "function") {
109
+ context.res.clearCookie("refreshToken", options);
110
+ }
111
+ else if (typeof context?.response?.clearCookie === "function") {
112
+ context.response.clearCookie("refreshToken", options);
113
+ }
114
+ else if (typeof context?.clearCookie === "function") {
115
+ context.clearCookie("refreshToken", options);
116
+ }
117
+ };
118
+ exports.clearDefaultJwtCookie = clearDefaultJwtCookie;
@@ -1,4 +1,4 @@
1
- import { TokenBasedAuthStrategyConfig, TokenConfig } from "../../types";
1
+ import { TokenAuthStrategyConfig } from "../../types";
2
2
  export interface JwtVerifyOptions {
3
3
  algorithms?: string[];
4
4
  notBefore?: string | number;
@@ -12,36 +12,12 @@ export interface JwtVerifyOptions {
12
12
  export interface JwtSignOptions {
13
13
  algorithm?: "HS256" | "HS384" | "HS512" | "RS256" | "RS384" | "RS512" | "ES256" | "ES384" | "ES512" | "PS256" | "PS384" | "PS512" | "none";
14
14
  notBefore?: string | number;
15
- jwtid?: string;
15
+ jti?: string;
16
16
  issuedAt?: number;
17
17
  mutatePayload?: (payload: Record<string, any>) => Record<string, any>;
18
18
  noTimestamp?: boolean;
19
19
  keyid?: string;
20
20
  allowUnsafe?: boolean;
21
21
  }
22
- export type JwtAccessTokenConfig = {
23
- verifyOptions?: JwtVerifyOptions;
24
- signOptions: JwtSignOptions;
25
- } & TokenConfig;
26
- export type JwtRefreshTokenConfig = {
27
- verifyOptions?: JwtVerifyOptions;
28
- signOptions: JwtSignOptions;
29
- } & TokenConfig;
30
- export interface JwtConfig<TContext = unknown, TUser = unknown> extends TokenBasedAuthStrategyConfig<TContext, TUser> {
31
- accessToken: JwtAccessTokenConfig;
32
- refreshToken?: JwtRefreshTokenConfig;
33
- routes?: {
34
- login?: {
35
- path: string;
36
- method?: "POST" | "GET";
37
- };
38
- logout?: {
39
- path: string;
40
- method?: "POST" | "GET";
41
- };
42
- refresh?: {
43
- path: string;
44
- method?: "POST" | "GET";
45
- };
46
- };
22
+ export interface JwtConfig<TContext = unknown, TUser = unknown> extends TokenAuthStrategyConfig<TContext, TUser> {
47
23
  }
@@ -1,8 +1,8 @@
1
1
  import * as Soap from "@soapjs/soap";
2
- import { CredentialBasedAuthStrategy } from "../credential-based-auth.strategy";
2
+ import { CredentialAuthStrategy } from "../credential-auth.strategy";
3
3
  import { LocalStrategyConfig } from "./local.types";
4
4
  import { SessionHandler } from "../../session/session-handler";
5
- export declare class LocalStrategy<TContext = unknown, TUser = unknown> extends CredentialBasedAuthStrategy<TContext, TUser> {
5
+ export declare class LocalStrategy<TContext = unknown, TUser = unknown> extends CredentialAuthStrategy<TContext, TUser> {
6
6
  protected config: LocalStrategyConfig<TContext, TUser>;
7
7
  protected session?: SessionHandler;
8
8
  protected logger?: Soap.Logger;
@@ -11,15 +11,9 @@ export declare class LocalStrategy<TContext = unknown, TUser = unknown> extends
11
11
  identifier: string;
12
12
  password: string;
13
13
  }>;
14
- protected verifyCredentials(credentials: {
15
- identifier: string;
16
- password: string;
17
- }): Promise<boolean>;
14
+ protected verifyCredentials(identifier: string, password: string): Promise<boolean>;
18
15
  protected retrieveUser(credentials: {
19
16
  identifier: string;
20
17
  password: string;
21
18
  }): Promise<TUser | null>;
22
- requestPasswordReset(email: string): Promise<void>;
23
- resetPassword(email: string, token: string, newPassword: string): Promise<void>;
24
- changePassword(email: string, oldPassword: string, newPassword: string): Promise<void>;
25
19
  }
@@ -1,9 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.LocalStrategy = void 0;
4
- const errors_1 = require("../../errors");
5
- const credential_based_auth_strategy_1 = require("../credential-based-auth.strategy");
6
- class LocalStrategy extends credential_based_auth_strategy_1.CredentialBasedAuthStrategy {
4
+ const credential_auth_strategy_1 = require("../credential-auth.strategy");
5
+ class LocalStrategy extends credential_auth_strategy_1.CredentialAuthStrategy {
7
6
  config;
8
7
  session;
9
8
  logger;
@@ -13,64 +12,14 @@ class LocalStrategy extends credential_based_auth_strategy_1.CredentialBasedAuth
13
12
  this.session = session;
14
13
  this.logger = logger;
15
14
  }
16
- async extractCredentials(context) {
17
- return this.config.login.extractCredentials(context);
15
+ extractCredentials(context) {
16
+ return this.config.credentials.extractCredentials(context);
18
17
  }
19
- async verifyCredentials(credentials) {
20
- return this.config.login.verifyUserCredentials(credentials.identifier, credentials.password);
18
+ async verifyCredentials(identifier, password) {
19
+ return this.config.credentials.verifyCredentials(identifier, password);
21
20
  }
22
21
  async retrieveUser(credentials) {
23
- return this.config.login.retrieveUserData(credentials.identifier);
24
- }
25
- async requestPasswordReset(email) {
26
- try {
27
- if (!this.config.passwordReset?.generateResetToken) {
28
- throw new Error("Password reset token generation is not configured.");
29
- }
30
- const token = await this.config.passwordReset.generateResetToken(email);
31
- await this.config.passwordReset.sendResetEmail?.(email, token);
32
- this.logger?.info(`Password reset requested for email: ${email}`);
33
- await this.config.passwordReset.onSuccess?.({ email });
34
- }
35
- catch (error) {
36
- this.logger?.error("Password reset request error:", error);
37
- await this.config.passwordReset.onFailure?.({ email, error });
38
- throw new errors_1.AuthError(error, "Password reset request failed.");
39
- }
40
- }
41
- async resetPassword(email, token, newPassword) {
42
- try {
43
- if (!this.config.passwordReset?.validateResetToken) {
44
- throw new Error("Password reset token validation is not configured.");
45
- }
46
- const isValid = await this.config.passwordReset.validateResetToken(token);
47
- if (!isValid)
48
- throw new Error("Invalid or expired reset token.");
49
- await this.config.passwordReset.updatePassword(email, newPassword);
50
- this.logger?.info(`Password reset successful for email: ${email}`);
51
- await this.config.passwordReset.onSuccess?.({ email });
52
- }
53
- catch (error) {
54
- this.logger?.error("Password reset error:", error);
55
- await this.config.passwordReset.onFailure?.({ email, error });
56
- throw new errors_1.AuthError(error, "Password reset failed.");
57
- }
58
- }
59
- async changePassword(email, oldPassword, newPassword) {
60
- try {
61
- const isAuthenticated = await this.config.login.verifyUserCredentials(email, oldPassword);
62
- if (!isAuthenticated) {
63
- throw new errors_1.InvalidCredentialsError();
64
- }
65
- await this.config.passwordReset?.updatePassword?.(email, newPassword);
66
- this.logger?.info(`Password changed successfully for email: ${email}`);
67
- await this.config.passwordReset?.onSuccess?.({ email });
68
- }
69
- catch (error) {
70
- this.logger?.error("Change password error:", error);
71
- await this.config.passwordReset?.onFailure?.({ email, error });
72
- throw new errors_1.AuthError(error, "Change password failed.");
73
- }
22
+ return this.config.user.getUserData(credentials.identifier);
74
23
  }
75
24
  }
76
25
  exports.LocalStrategy = LocalStrategy;
@@ -1,3 +1,3 @@
1
- import { CredentialBasedAuthStrategyConfig } from "../../types";
2
- export interface LocalStrategyConfig<TContext = unknown, TUser = unknown> extends CredentialBasedAuthStrategyConfig<TContext, TUser> {
1
+ import { CredentialAuthStrategyConfig } from "../../types";
2
+ export interface LocalStrategyConfig<TContext = unknown, TUser = unknown> extends CredentialAuthStrategyConfig<TContext, TUser> {
3
3
  }
@@ -1,16 +1,30 @@
1
1
  import * as Soap from "@soapjs/soap";
2
- import { TokenConfig, AuthResult } from "../../types";
3
- import { TokenBasedAuthStrategy } from "../token-based-auth.strategy";
2
+ import { AuthResult } from "../../types";
4
3
  import { OAuth2StrategyConfig } from "./oauth2.types";
5
4
  import { SessionHandler } from "../../session/session-handler";
6
- export declare class OAuth2Strategy<TContext = unknown, TUser = unknown> extends TokenBasedAuthStrategy<TContext, TUser> {
5
+ import { BaseAuthStrategy } from "../base-auth.strategy";
6
+ export declare class OAuth2Strategy<TContext = unknown, TUser = unknown> extends BaseAuthStrategy<TContext, TUser> {
7
7
  protected config: OAuth2StrategyConfig<TContext, TUser>;
8
- protected accessTokenConfig: TokenConfig;
9
- protected refreshTokenConfig?: TokenConfig;
10
8
  protected session?: SessionHandler;
11
9
  protected logger?: Soap.Logger;
12
- constructor(config: OAuth2StrategyConfig<TContext, TUser>, accessTokenConfig: TokenConfig, refreshTokenConfig?: TokenConfig, session?: SessionHandler, logger?: Soap.Logger);
10
+ constructor(config: OAuth2StrategyConfig<TContext, TUser>, session?: SessionHandler, logger?: Soap.Logger);
11
+ logout(context: TContext): Promise<void>;
12
+ protected getCredentialsForPasswordGrant(context: TContext): Promise<{
13
+ identifier: string;
14
+ password: string;
15
+ }>;
16
+ protected retrieveAccessToken(context: TContext): Promise<string | undefined>;
17
+ protected retrieveRefreshToken(context: TContext): Promise<string | undefined>;
18
+ protected storeAccessToken(token: string, context: TContext): Promise<void>;
19
+ protected storeRefreshToken(token: string, context: TContext): Promise<void>;
20
+ protected embedAccessToken(token: string, context: TContext): void;
21
+ protected embedRefreshToken(token: string, context: TContext): void;
22
+ isTokenExpired(token: string): Promise<boolean>;
13
23
  authenticate(context: TContext): Promise<AuthResult<TUser>>;
24
+ protected processOAuthFlow(context: TContext): Promise<{
25
+ accessToken: string;
26
+ refreshToken?: string;
27
+ }>;
14
28
  protected verifyAuthorizationCode(context: TContext, code: string): void;
15
29
  protected extractAuthorizationCode(context: TContext): string | null;
16
30
  protected redirectUser(context: TContext, authUrl: string): void;
@@ -24,7 +38,7 @@ export declare class OAuth2Strategy<TContext = unknown, TUser = unknown> extends
24
38
  protected exchangeClientCredentials(): Promise<{
25
39
  accessToken: string;
26
40
  }>;
27
- protected exchangePasswordGrant(): Promise<{
41
+ protected exchangePasswordGrant(username: string, password: string): Promise<{
28
42
  accessToken: string;
29
43
  }>;
30
44
  refreshAccessToken(context: TContext): Promise<{
@@ -6,85 +6,163 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.OAuth2Strategy = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  const errors_1 = require("../../errors");
9
- const token_based_auth_strategy_1 = require("../token-based-auth.strategy");
10
9
  const oauth2_tools_1 = require("./oauth2.tools");
11
- class OAuth2Strategy extends token_based_auth_strategy_1.TokenBasedAuthStrategy {
10
+ const base_auth_strategy_1 = require("../base-auth.strategy");
11
+ class OAuth2Strategy extends base_auth_strategy_1.BaseAuthStrategy {
12
12
  config;
13
- accessTokenConfig;
14
- refreshTokenConfig;
15
13
  session;
16
14
  logger;
17
- constructor(config, accessTokenConfig, refreshTokenConfig, session, logger) {
18
- super(config, accessTokenConfig, refreshTokenConfig, session, logger);
15
+ constructor(config, session, logger) {
16
+ super(config, session, logger);
19
17
  this.config = config;
20
- this.accessTokenConfig = accessTokenConfig;
21
- this.refreshTokenConfig = refreshTokenConfig;
22
18
  this.session = session;
23
19
  this.logger = logger;
24
20
  this.config.scope = this.config.scope ?? "email";
25
21
  }
22
+ async logout(context) {
23
+ try {
24
+ await this.storeAccessToken("", context);
25
+ await this.storeRefreshToken("", context);
26
+ if (this.config.endpoints.logoutUrl) {
27
+ this.logger?.info("Redirecting to OAuth2 logout endpoint.");
28
+ this.redirectUser(context, this.config.endpoints.logoutUrl);
29
+ }
30
+ }
31
+ catch (error) {
32
+ this.logger?.error("Logout failed:", error);
33
+ throw new Error("Logout failed.");
34
+ }
35
+ }
36
+ async getCredentialsForPasswordGrant(context) {
37
+ if (this.config.credentials?.extractCredentials) {
38
+ return this.config.credentials.extractCredentials(context);
39
+ }
40
+ else if (typeof context === "object" && "body" in context) {
41
+ const body = context.body;
42
+ if (body.username && body.password) {
43
+ return {
44
+ identifier: body.username,
45
+ password: body.password,
46
+ };
47
+ }
48
+ }
49
+ throw new Error("Missing credentials for password grant.");
50
+ }
51
+ retrieveAccessToken(context) {
52
+ if (this.config.accessToken?.retrieve) {
53
+ return this.config.accessToken.retrieve(context);
54
+ }
55
+ if (typeof context === "object" && "headers" in context) {
56
+ const authHeader = context.headers?.authorization;
57
+ if (authHeader?.startsWith("Bearer ")) {
58
+ return authHeader.split(" ")[1];
59
+ }
60
+ }
61
+ if (typeof context === "object" && "cookies" in context) {
62
+ return context.cookies?.access_token;
63
+ }
64
+ return undefined;
65
+ }
66
+ retrieveRefreshToken(context) {
67
+ if (this.config.refreshToken?.retrieve) {
68
+ return this.config.refreshToken.retrieve(context);
69
+ }
70
+ if (typeof context === "object" && "cookies" in context) {
71
+ return context.cookies?.refresh_token;
72
+ }
73
+ return undefined;
74
+ }
75
+ storeAccessToken(token, context) {
76
+ if (this.config.accessToken?.persistence?.store) {
77
+ return this.config.accessToken.persistence.store(token, context, this.config.accessToken.issuer.options.expiresIn);
78
+ }
79
+ if (typeof context === "object" && "cookies" in context) {
80
+ context.cookies.set("access_token", token, { httpOnly: true });
81
+ }
82
+ }
83
+ storeRefreshToken(token, context) {
84
+ if (this.config.refreshToken?.persistence?.store) {
85
+ return this.config.refreshToken.persistence.store(token, context, this.config.refreshToken.issuer.options.expiresIn);
86
+ }
87
+ if (typeof context === "object" && "cookies" in context) {
88
+ context.cookies.set("refresh_token", token, { httpOnly: true });
89
+ }
90
+ }
91
+ embedAccessToken(token, context) {
92
+ if (this.config.accessToken?.embed) {
93
+ this.config.accessToken.embed(context, token);
94
+ }
95
+ else if (typeof context === "object" && "response" in context) {
96
+ context.response.setHeader("Authorization", `Bearer ${token}`);
97
+ }
98
+ }
99
+ embedRefreshToken(token, context) {
100
+ if (this.config.refreshToken?.embed) {
101
+ return this.config.refreshToken.embed(context, token);
102
+ }
103
+ else if (typeof context === "object" && "cookies" in context) {
104
+ context.cookies.set("refresh_token", token, { httpOnly: true });
105
+ }
106
+ }
107
+ async isTokenExpired(token) {
108
+ try {
109
+ const parts = token.split(".");
110
+ if (parts.length !== 3) {
111
+ this.logger?.warn("Non-JWT token provided, cannot determine expiration.");
112
+ return false;
113
+ }
114
+ const decoded = JSON.parse(Buffer.from(parts[1], "base64").toString());
115
+ if (!decoded.exp)
116
+ return false;
117
+ const currentTime = Math.floor(Date.now() / 1000);
118
+ return decoded.exp < currentTime;
119
+ }
120
+ catch (error) {
121
+ this.logger?.warn("Failed to decode token:", error);
122
+ return false;
123
+ }
124
+ }
26
125
  async authenticate(context) {
27
126
  try {
28
127
  let user;
29
128
  let refreshToken;
30
- let accessToken = await this.accessTokenConfig.retrieve?.(context);
129
+ let accessToken = await this.retrieveAccessToken(context);
31
130
  if (!accessToken) {
32
131
  this.logger?.info("No access token found, checking for refresh token.");
33
- refreshToken = await this.refreshTokenConfig?.retrieve?.(context);
132
+ refreshToken = await this.retrieveRefreshToken(context);
34
133
  if (refreshToken) {
35
134
  this.logger?.info("Found refresh token, attempting to refresh access token.");
36
135
  const newTokens = await this.refreshAccessToken(context);
37
136
  accessToken = newTokens.accessToken;
38
- this.accessTokenConfig.embed?.(context, accessToken);
137
+ this.embedAccessToken(accessToken, context);
39
138
  if (newTokens.refreshToken) {
40
139
  refreshToken = newTokens.refreshToken;
41
- this.refreshTokenConfig?.embed?.(context, newTokens.refreshToken);
140
+ this.embedRefreshToken(newTokens.refreshToken, context);
42
141
  }
43
142
  }
44
143
  else {
45
144
  this.logger?.info("No refresh token found, attempting authentication using grant type.");
46
- switch (this.config.grantType) {
47
- case "authorization_code":
48
- const authorizationCode = this.extractAuthorizationCode(context);
49
- this.verifyAuthorizationCode(context, authorizationCode);
50
- const tokenResult = await this.exchangeCodeForToken(context, authorizationCode);
51
- accessToken = tokenResult.accessToken;
52
- refreshToken = tokenResult.refreshToken;
53
- break;
54
- case "client_credentials":
55
- this.logger?.info("Using client credentials grant.");
56
- const clientCredResult = await this.exchangeClientCredentials();
57
- accessToken = clientCredResult.accessToken;
58
- break;
59
- case "password":
60
- this.logger?.info("Using password grant.");
61
- if (!this.config.credentials) {
62
- throw new Error("Missing credentials for password grant.");
63
- }
64
- const passwordResult = await this.exchangePasswordGrant();
65
- accessToken = passwordResult.accessToken;
66
- break;
67
- default:
68
- throw new Error(`Unsupported grant type: ${this.config.grantType}`);
69
- }
70
- this.accessTokenConfig.embed?.(context, accessToken);
145
+ const tokens = await this.processOAuthFlow(context);
146
+ accessToken = tokens.accessToken;
147
+ refreshToken = tokens.refreshToken;
148
+ this.embedAccessToken(accessToken, context);
71
149
  if (refreshToken) {
72
- this.refreshTokenConfig?.embed?.(context, refreshToken);
150
+ this.embedRefreshToken(refreshToken, context);
73
151
  }
74
152
  }
75
153
  }
76
154
  else if (accessToken && (await this.isTokenExpired(accessToken))) {
77
155
  this.logger?.info("Access token expired, attempting refresh.");
78
- refreshToken = await this.refreshTokenConfig?.retrieve?.(context);
156
+ refreshToken = await this.retrieveRefreshToken(context);
79
157
  if (!refreshToken) {
80
158
  throw new errors_1.MissingTokenError("Refresh");
81
159
  }
82
160
  const newTokens = await this.refreshAccessToken(context);
83
161
  accessToken = newTokens.accessToken;
84
- this.accessTokenConfig.embed?.(context, accessToken);
162
+ this.embedAccessToken(accessToken, context);
85
163
  if (newTokens.refreshToken && newTokens.refreshToken !== refreshToken) {
86
164
  refreshToken = newTokens.refreshToken;
87
- this.refreshTokenConfig?.embed?.(context, newTokens.refreshToken);
165
+ this.embedRefreshToken(newTokens.refreshToken, context);
88
166
  }
89
167
  }
90
168
  if (!accessToken) {
@@ -92,6 +170,7 @@ class OAuth2Strategy extends token_based_auth_strategy_1.TokenBasedAuthStrategy
92
170
  }
93
171
  user = await this.retrieveUser(accessToken);
94
172
  if (!user) {
173
+ this.logger?.error("User retrieval failed: No user found for access token.");
95
174
  throw new errors_1.UserNotFoundError();
96
175
  }
97
176
  await this.isAuthorized(user);
@@ -102,6 +181,29 @@ class OAuth2Strategy extends token_based_auth_strategy_1.TokenBasedAuthStrategy
102
181
  throw new errors_1.AuthError(error, "OAuth2 authentication failed.");
103
182
  }
104
183
  }
184
+ async processOAuthFlow(context) {
185
+ if (this.config.grantType === "authorization_code") {
186
+ const authorizationCode = this.extractAuthorizationCode(context);
187
+ this.verifyAuthorizationCode(context, authorizationCode);
188
+ const tokenResult = await this.exchangeCodeForToken(context, authorizationCode);
189
+ return tokenResult;
190
+ }
191
+ if (this.config.grantType === "client_credentials") {
192
+ this.logger?.info("Using client credentials grant.");
193
+ const clientCredResult = await this.exchangeClientCredentials();
194
+ return { accessToken: clientCredResult.accessToken };
195
+ }
196
+ if (this.config.grantType === "password") {
197
+ this.logger?.info("Using password grant.");
198
+ const credentials = await this.getCredentialsForPasswordGrant(context);
199
+ if (!credentials) {
200
+ throw new Error("Missing credentials for password grant.");
201
+ }
202
+ const passwordResult = await this.exchangePasswordGrant(credentials.identifier, credentials.password);
203
+ return { accessToken: passwordResult.accessToken };
204
+ }
205
+ throw new Error(`Unsupported grant type: ${this.config.grantType}`);
206
+ }
105
207
  verifyAuthorizationCode(context, code) {
106
208
  if (!code) {
107
209
  this.logger?.warn("Authorization code missing, redirecting user.");
@@ -185,7 +287,7 @@ class OAuth2Strategy extends token_based_auth_strategy_1.TokenBasedAuthStrategy
185
287
  const response = await axios_1.default.get(this.config.endpoints.userInfoUrl, {
186
288
  headers: { Authorization: `Bearer ${accessToken}` },
187
289
  });
188
- return (await this.config.validateUser?.(response.data)) || null;
290
+ return (await this.config.user.validateUser(response.data)) || null;
189
291
  }
190
292
  catch (error) {
191
293
  this.logger?.error("Failed to fetch user information:", error);
@@ -200,22 +302,22 @@ class OAuth2Strategy extends token_based_auth_strategy_1.TokenBasedAuthStrategy
200
302
  });
201
303
  return { accessToken: response.data.access_token };
202
304
  }
203
- async exchangePasswordGrant() {
204
- if (!this.config.credentials) {
305
+ async exchangePasswordGrant(username, password) {
306
+ if (!username || !password) {
205
307
  throw new Error("Missing credentials for password grant.");
206
308
  }
207
309
  const response = await axios_1.default.post(this.config.endpoints.tokenUrl, {
208
310
  grant_type: "password",
209
311
  client_id: this.config.clientId,
210
312
  client_secret: this.config.clientSecret,
211
- username: this.config.credentials.username,
212
- password: this.config.credentials.password,
313
+ username,
314
+ password,
213
315
  });
214
316
  return { accessToken: response.data.access_token };
215
317
  }
216
318
  async refreshAccessToken(context) {
217
319
  try {
218
- const refreshToken = await this.refreshTokenConfig?.retrieve?.(context);
320
+ const refreshToken = await this.retrieveRefreshToken(context);
219
321
  if (!refreshToken) {
220
322
  throw new errors_1.MissingTokenError("Refresh");
221
323
  }
@@ -225,13 +327,20 @@ class OAuth2Strategy extends token_based_auth_strategy_1.TokenBasedAuthStrategy
225
327
  client_secret: this.config.clientSecret,
226
328
  refresh_token: refreshToken,
227
329
  });
330
+ if (response.status !== 200 || !response.data.access_token) {
331
+ throw new Error("Failed to refresh token");
332
+ }
228
333
  const refreshedTokens = {
229
334
  accessToken: response.data.access_token,
230
335
  refreshToken: response.data.refresh_token,
231
336
  };
232
- await this.accessTokenConfig.embed?.(context, refreshedTokens.accessToken);
337
+ await this.storeAccessToken(refreshedTokens.accessToken, context);
338
+ if (refreshedTokens.refreshToken) {
339
+ await this.storeRefreshToken(refreshedTokens.refreshToken, context);
340
+ }
341
+ await this.embedAccessToken(refreshedTokens.accessToken, context);
233
342
  if (refreshedTokens.refreshToken) {
234
- await this.refreshTokenConfig?.embed?.(context, refreshedTokens.refreshToken);
343
+ await this.embedRefreshToken(refreshedTokens.refreshToken, context);
235
344
  }
236
345
  return refreshedTokens;
237
346
  }