@civic/auth 0.9.1-beta.1 → 0.9.1-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/dist/lib/logger.d.ts +6 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +7 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/oauth.d.ts +2 -1
- package/dist/lib/oauth.d.ts.map +1 -1
- package/dist/lib/oauth.js +1 -1
- package/dist/lib/oauth.js.map +1 -1
- package/dist/nextjs/config.d.ts +2 -4
- package/dist/nextjs/config.d.ts.map +1 -1
- package/dist/nextjs/config.js +4 -57
- package/dist/nextjs/config.js.map +1 -1
- package/dist/react-router-7/components/UserButton.d.ts +15 -0
- package/dist/react-router-7/components/UserButton.d.ts.map +1 -0
- package/dist/react-router-7/components/UserButton.js +112 -0
- package/dist/react-router-7/components/UserButton.js.map +1 -0
- package/dist/react-router-7/components/UserButtonPresentation.d.ts +10 -0
- package/dist/react-router-7/components/UserButtonPresentation.d.ts.map +1 -0
- package/dist/react-router-7/components/UserButtonPresentation.js +19 -0
- package/dist/react-router-7/components/UserButtonPresentation.js.map +1 -0
- package/dist/react-router-7/config.d.ts +113 -0
- package/dist/react-router-7/config.d.ts.map +1 -0
- package/dist/react-router-7/config.js +88 -0
- package/dist/react-router-7/config.js.map +1 -0
- package/dist/react-router-7/cookies.d.ts +41 -0
- package/dist/react-router-7/cookies.d.ts.map +1 -0
- package/dist/react-router-7/cookies.js +188 -0
- package/dist/react-router-7/cookies.js.map +1 -0
- package/dist/react-router-7/index.d.ts +10 -0
- package/dist/react-router-7/index.d.ts.map +1 -0
- package/dist/react-router-7/index.js +12 -0
- package/dist/react-router-7/index.js.map +1 -0
- package/dist/react-router-7/routeHandler.d.ts +54 -0
- package/dist/react-router-7/routeHandler.d.ts.map +1 -0
- package/dist/react-router-7/routeHandler.js +397 -0
- package/dist/react-router-7/routeHandler.js.map +1 -0
- package/dist/react-router-7/useUser.d.ts +38 -0
- package/dist/react-router-7/useUser.d.ts.map +1 -0
- package/dist/react-router-7/useUser.js +92 -0
- package/dist/react-router-7/useUser.js.map +1 -0
- package/dist/reactjs/core/GlobalAuthManager.d.ts +6 -4
- package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.js +17 -6
- package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
- package/dist/reactjs/hooks/useUser.js.map +1 -1
- package/dist/server/config.d.ts +1 -0
- package/dist/server/config.d.ts.map +1 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/session.d.ts.map +1 -1
- package/dist/server/session.js +1 -0
- package/dist/server/session.js.map +1 -1
- package/dist/services/AuthenticationService.d.ts.map +1 -1
- package/dist/services/AuthenticationService.js +0 -5
- package/dist/services/AuthenticationService.js.map +1 -1
- package/dist/shared/hooks/useCivicAuthConfig.d.ts +1 -1
- package/dist/shared/hooks/useCivicAuthConfig.d.ts.map +1 -1
- package/dist/shared/lib/cookieConfig.d.ts +46 -0
- package/dist/shared/lib/cookieConfig.d.ts.map +1 -0
- package/dist/shared/lib/cookieConfig.js +99 -0
- package/dist/shared/lib/cookieConfig.js.map +1 -0
- package/dist/shared/lib/util.d.ts +5 -0
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +65 -3
- package/dist/shared/lib/util.js.map +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/version.js +1 -1
- package/dist/shared/version.js.map +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts +1 -1
- package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
- package/dist/vanillajs/auth/CivicAuth.js +33 -12
- package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
- package/dist/vanillajs/auth/SessionManager.d.ts +9 -1
- package/dist/vanillajs/auth/SessionManager.d.ts.map +1 -1
- package/dist/vanillajs/auth/SessionManager.js +103 -47
- package/dist/vanillajs/auth/SessionManager.js.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
- package/dist/vanillajs/auth/config/ConfigProcessor.js +16 -2
- package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +1 -1
- package/dist/vanillajs/auth/handlers/MessageHandler.js +3 -0
- package/dist/vanillajs/auth/handlers/MessageHandler.js.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
- package/dist/vanillajs/iframe/IframeManager.js +13 -0
- package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
- package/package.json +12 -3
|
@@ -5,6 +5,9 @@ import { retrieveTokens, clearTokens, getBackendEndpoints, } from "../../shared/
|
|
|
5
5
|
import { getUser } from "../../shared/lib/session.js";
|
|
6
6
|
import { GenericUserSession } from "../../shared/lib/UserSession.js";
|
|
7
7
|
import { AUTOREFRESH_TIMEOUT_NAME, REFRESH_IN_PROGRESS, } from "../../constants.js";
|
|
8
|
+
import { verify } from "@civic/auth-verify";
|
|
9
|
+
import { OAuthTokenTypes } from "../../shared/lib/types.js";
|
|
10
|
+
import { addSlashIfNeeded } from "../../lib/oauth.js";
|
|
8
11
|
export class SessionManager {
|
|
9
12
|
storage;
|
|
10
13
|
events;
|
|
@@ -49,7 +52,18 @@ export class SessionManager {
|
|
|
49
52
|
const tokens = await retrieveTokens(this.storage);
|
|
50
53
|
const user = await this.getCurrentUser();
|
|
51
54
|
// If we have tokens and user (normal flow), create full session
|
|
52
|
-
if (tokens?.id_token && user) {
|
|
55
|
+
if ((tokens?.id_token || tokens?.access_token) && user) {
|
|
56
|
+
// Validate all available tokens
|
|
57
|
+
const validationResults = await this.validateTokens({
|
|
58
|
+
id_token: tokens.id_token,
|
|
59
|
+
access_token: tokens.access_token,
|
|
60
|
+
});
|
|
61
|
+
// Check if any tokens failed validation
|
|
62
|
+
if (!validationResults.idTokenValid ||
|
|
63
|
+
!validationResults.accessTokenValid) {
|
|
64
|
+
this.logger.warn("Token validation failed in getCurrentSession, returning null");
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
53
67
|
return {
|
|
54
68
|
user,
|
|
55
69
|
accessToken: tokens.access_token,
|
|
@@ -99,30 +113,36 @@ export class SessionManager {
|
|
|
99
113
|
this.logger.debug("No tokens accessible, checking backend session...", await this.checkBackendSession());
|
|
100
114
|
return await this.checkBackendSession();
|
|
101
115
|
}
|
|
102
|
-
// If we have
|
|
116
|
+
// If we have tokens, validate them
|
|
103
117
|
if (hasIdToken) {
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
|
|
118
|
+
const validationResults = await this.validateTokens({
|
|
119
|
+
id_token: tokens.id_token,
|
|
120
|
+
access_token: tokens.access_token,
|
|
121
|
+
});
|
|
122
|
+
// Both tokens must be valid (if they exist) for authentication to be considered valid
|
|
123
|
+
const allTokensValid = validationResults.idTokenValid && validationResults.accessTokenValid;
|
|
124
|
+
if (allTokensValid) {
|
|
125
|
+
this.logger.debug("All available tokens are valid, user is authenticated");
|
|
107
126
|
return true;
|
|
108
127
|
}
|
|
109
|
-
//
|
|
128
|
+
// Some tokens are invalid/expired - attempt refresh if refresh token exists
|
|
110
129
|
if (hasRefreshToken && this.tokenRefresher) {
|
|
111
|
-
this.logger.info("
|
|
130
|
+
this.logger.info("Some tokens expired/invalid, attempting refresh with refresh token");
|
|
112
131
|
try {
|
|
113
132
|
// Attempt token refresh
|
|
114
133
|
await this.tokenRefresher.refreshTokens();
|
|
115
134
|
this.logger.info("Token refresh successful during authentication check");
|
|
116
135
|
// Check if we now have valid tokens after refresh
|
|
117
136
|
const refreshedTokens = await retrieveTokens(this.storage);
|
|
118
|
-
const
|
|
119
|
-
refreshedTokens
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
137
|
+
const refreshedValidationResults = await this.validateTokens({
|
|
138
|
+
id_token: refreshedTokens?.id_token,
|
|
139
|
+
access_token: refreshedTokens?.access_token,
|
|
140
|
+
});
|
|
141
|
+
const allRefreshedTokensValid = refreshedValidationResults.idTokenValid &&
|
|
142
|
+
refreshedValidationResults.accessTokenValid;
|
|
143
|
+
if (allRefreshedTokensValid) {
|
|
144
|
+
this.logger.info("Successfully restored session via refresh token");
|
|
145
|
+
return true;
|
|
126
146
|
}
|
|
127
147
|
}
|
|
128
148
|
catch (error) {
|
|
@@ -132,7 +152,7 @@ export class SessionManager {
|
|
|
132
152
|
}
|
|
133
153
|
}
|
|
134
154
|
else {
|
|
135
|
-
this.logger.warn("
|
|
155
|
+
this.logger.warn("Some tokens invalid and no refresh token available, clearing tokens");
|
|
136
156
|
await clearTokens(this.storage);
|
|
137
157
|
}
|
|
138
158
|
}
|
|
@@ -145,13 +165,15 @@ export class SessionManager {
|
|
|
145
165
|
this.logger.info("Token refresh successful during session restore");
|
|
146
166
|
// Check if we now have valid tokens after refresh
|
|
147
167
|
const refreshedTokens = await retrieveTokens(this.storage);
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
168
|
+
const refreshedValidationResults = await this.validateTokens({
|
|
169
|
+
id_token: refreshedTokens?.id_token,
|
|
170
|
+
access_token: refreshedTokens?.access_token,
|
|
171
|
+
});
|
|
172
|
+
const allRefreshedTokensValid = refreshedValidationResults.idTokenValid &&
|
|
173
|
+
refreshedValidationResults.accessTokenValid;
|
|
174
|
+
if (allRefreshedTokensValid) {
|
|
175
|
+
this.logger.info("Successfully restored session from refresh token only");
|
|
176
|
+
return true;
|
|
155
177
|
}
|
|
156
178
|
}
|
|
157
179
|
catch (error) {
|
|
@@ -168,38 +190,72 @@ export class SessionManager {
|
|
|
168
190
|
}
|
|
169
191
|
}
|
|
170
192
|
/**
|
|
171
|
-
* Validate if a token is
|
|
193
|
+
* Validate if a token is cryptographically valid and not expired
|
|
194
|
+
* Uses proper JWT verification with signature validation using JWKS
|
|
172
195
|
* @param token JWT token to validate
|
|
196
|
+
* @param tokenType Type of token (for logging and cleanup purposes)
|
|
173
197
|
* @returns true if token is valid, false if expired or invalid
|
|
174
198
|
*/
|
|
175
|
-
async validateToken(token) {
|
|
199
|
+
async validateToken(token, tokenType = "id_token") {
|
|
176
200
|
try {
|
|
177
|
-
//
|
|
178
|
-
|
|
179
|
-
if (
|
|
180
|
-
this.logger.
|
|
181
|
-
return
|
|
201
|
+
// For backend flows with httpOnly cookies, we can't validate tokens client-side
|
|
202
|
+
// since they're not accessible to JavaScript
|
|
203
|
+
if (this.isBrowserCookieStorage()) {
|
|
204
|
+
this.logger.debug("Backend flow: skipping client-side token validation");
|
|
205
|
+
return true; // Backend will validate tokens server-side
|
|
182
206
|
}
|
|
183
|
-
//
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
207
|
+
// Configure verification options based on token type
|
|
208
|
+
const verifyOptions = {
|
|
209
|
+
issuer: addSlashIfNeeded(this.config.oauthServerBaseUrl ?? "https://auth.civic.com/oauth/"),
|
|
210
|
+
};
|
|
211
|
+
// Set audience based on token type
|
|
212
|
+
if (tokenType === "id_token" && this.config.clientId) {
|
|
213
|
+
// ID tokens should have the client ID as audience for proper OIDC compliance
|
|
214
|
+
verifyOptions.aud = this.config.clientId;
|
|
215
|
+
}
|
|
216
|
+
else if (tokenType === "access_token") {
|
|
217
|
+
// Access tokens have "civic" as audience based on auth server configuration
|
|
218
|
+
verifyOptions.aud = "civic";
|
|
219
|
+
verifyOptions.clientId = this.config.clientId;
|
|
194
220
|
}
|
|
195
|
-
this.logger.debug(
|
|
221
|
+
this.logger.debug(`Verifying ${tokenType} with options:`, verifyOptions);
|
|
222
|
+
// Use the @civic/auth-verify package for proper JWT verification
|
|
223
|
+
await verify(token, verifyOptions);
|
|
224
|
+
this.logger.debug(`${tokenType} cryptographically verified and valid`);
|
|
196
225
|
return true;
|
|
197
226
|
}
|
|
198
227
|
catch (error) {
|
|
199
|
-
this.logger.warn(
|
|
228
|
+
this.logger.warn(`${tokenType} validation failed`, error);
|
|
229
|
+
// Clear the specific token that failed validation
|
|
230
|
+
if (tokenType === "id_token") {
|
|
231
|
+
this.storage.delete(OAuthTokenTypes.ID_TOKEN);
|
|
232
|
+
}
|
|
233
|
+
else if (tokenType === "access_token") {
|
|
234
|
+
this.storage.delete(OAuthTokenTypes.ACCESS_TOKEN);
|
|
235
|
+
}
|
|
200
236
|
return false;
|
|
201
237
|
}
|
|
202
238
|
}
|
|
239
|
+
/**
|
|
240
|
+
* Validate both ID token and access token if they exist
|
|
241
|
+
* @param tokens Token object containing id_token and access_token
|
|
242
|
+
* @returns Object indicating which tokens are valid
|
|
243
|
+
*/
|
|
244
|
+
async validateTokens(tokens) {
|
|
245
|
+
const results = {
|
|
246
|
+
idTokenValid: true, // Default to true if token doesn't exist
|
|
247
|
+
accessTokenValid: true, // Default to true if token doesn't exist
|
|
248
|
+
};
|
|
249
|
+
// Validate ID token if it exists
|
|
250
|
+
if (tokens.id_token && tokens.id_token.trim() !== "") {
|
|
251
|
+
results.idTokenValid = await this.validateToken(tokens.id_token, "id_token");
|
|
252
|
+
}
|
|
253
|
+
// Validate access token if it exists
|
|
254
|
+
if (tokens.access_token && tokens.access_token.trim() !== "") {
|
|
255
|
+
results.accessTokenValid = await this.validateToken(tokens.access_token, "access_token");
|
|
256
|
+
}
|
|
257
|
+
return results;
|
|
258
|
+
}
|
|
203
259
|
/**
|
|
204
260
|
* Check if we're using BrowserCookieStorage
|
|
205
261
|
*/
|
|
@@ -343,10 +399,10 @@ export class SessionManager {
|
|
|
343
399
|
// Clear all token-related keys except LOGOUT_STATE
|
|
344
400
|
// These are the OAuth token types from the constants
|
|
345
401
|
const keysToDelete = [
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
402
|
+
OAuthTokenTypes.ID_TOKEN,
|
|
403
|
+
OAuthTokenTypes.ACCESS_TOKEN,
|
|
404
|
+
OAuthTokenTypes.REFRESH_TOKEN,
|
|
405
|
+
OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,
|
|
350
406
|
REFRESH_IN_PROGRESS,
|
|
351
407
|
AUTOREFRESH_TIMEOUT_NAME,
|
|
352
408
|
// Note: NOT clearing LOGOUT_STATE here - it's needed for cleanup after redirect
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/SessionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthStorage } from \"../../types.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport type { User, Session } from \"../types/index.js\"; // Assuming Session might be used internally\nimport { AuthEvent } from \"../types/index.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { TokenRefresher } from \"./TokenRefresher.js\";\nimport type { AuthConfig } from \"../../server/config.js\";\nimport {\n retrieveTokens,\n clearTokens,\n getBackendEndpoints,\n} from \"../../shared/lib/util.js\";\nimport { getUser } from \"../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../shared/lib/UserSession.js\";\nimport {\n AUTOREFRESH_TIMEOUT_NAME,\n REFRESH_IN_PROGRESS,\n} from \"../../constants.js\";\n\nexport class SessionManager {\n private storage: AuthStorage;\n private events: AuthenticationEvents;\n private tokenRefresher?: TokenRefresher;\n private logger = createLogger(\"session\");\n private config: AuthConfig;\n\n // Simple cache for backend session check to avoid excessive API calls\n private backendSessionCache: {\n result: boolean;\n timestamp: number;\n } | null = null;\n private readonly CACHE_DURATION = 30 * 1000; // 30 seconds\n\n constructor(\n storageAdapter: AuthStorage,\n events: AuthenticationEvents,\n config: AuthConfig,\n ) {\n this.storage = storageAdapter;\n this.events = events;\n this.config = config;\n this.logger.info(\n \"SessionManager initialized with shared lib token storage\",\n );\n }\n\n /**\n * Initialize the session manager with auth configuration to enable token refresh\n */\n async initializeWithAuthConfig(authConfig: AuthConfig): Promise<void> {\n try {\n // Initialize token refresher\n this.tokenRefresher = new TokenRefresher(\n this.storage,\n this.events,\n authConfig,\n );\n await this.tokenRefresher.initialize(authConfig);\n\n // Check current authentication state (this now includes token validation and refresh attempts)\n const isAuthenticated = await this.isAuthenticated();\n\n // Set authentication state on the token refresher\n // This will enable auto-refresh if the user is authenticated (including after successful refresh)\n this.tokenRefresher.setAuthenticationState(isAuthenticated);\n\n this.logger.info(\n \"SessionManager initialized with token refresh capability\",\n { isAuthenticated },\n );\n } catch (error) {\n this.logger.error(\n \"Failed to initialize SessionManager with auth config:\",\n error,\n );\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n }\n\n /**\n * Build current session from shared lib storage or backend API\n * For backend flows with httpOnly cookies, creates limited session when tokens aren't accessible\n */\n async getCurrentSession(): Promise<Session | null> {\n try {\n const tokens = await retrieveTokens(this.storage);\n const user = await this.getCurrentUser();\n\n // If we have tokens and user (normal flow), create full session\n if (tokens?.id_token && user) {\n return {\n user,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token ?? undefined,\n expiresAt: tokens.oidc_session_expires_at ?? undefined,\n };\n }\n\n // If we have user but no accessible tokens (backend flow with httpOnly cookies),\n // create a limited session with just user info\n if (user && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Creating limited session for backend flow (tokens in httpOnly cookies)\",\n );\n return {\n user,\n accessToken: undefined, // Not accessible in httpOnly cookies\n idToken: undefined, // Not accessible in httpOnly cookies\n refreshToken: undefined, // Not accessible in httpOnly cookies\n expiresAt: undefined, // Not accessible in httpOnly cookies\n };\n }\n\n this.logger.debug(\"No session available - no tokens or user found\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to load session:\", error);\n return null;\n }\n }\n\n /**\n * Check if user is authenticated using shared lib utilities\n * For backend flows with httpOnly cookies, falls back to API check\n *\n * This method now validates tokens on load and attempts refresh if:\n * - Tokens exist but are expired/invalid\n * - A refresh token is available\n */\n async isAuthenticated(): Promise<boolean> {\n try {\n // First, try the standard token-based check\n const tokens = await retrieveTokens(this.storage);\n\n // Normalize empty strings to null for consistent checking\n const hasIdToken = tokens?.id_token && tokens.id_token.trim() !== \"\";\n const hasRefreshToken =\n tokens?.refresh_token && tokens.refresh_token.trim() !== \"\";\n\n // If no tokens found and we're using BrowserCookieStorage,\n // try checking backend session (for httpOnly cookies)\n if (!hasIdToken && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"No tokens accessible, checking backend session...\",\n await this.checkBackendSession(),\n );\n return await this.checkBackendSession();\n }\n\n // If we have an ID token, validate it\n if (hasIdToken) {\n const isTokenValid = await this.validateToken(tokens.id_token!);\n\n if (isTokenValid) {\n this.logger.debug(\"ID token is valid, user is authenticated\");\n return true;\n }\n\n // Token is invalid/expired - attempt refresh if refresh token exists\n if (hasRefreshToken && this.tokenRefresher) {\n this.logger.info(\n \"ID token expired/invalid, attempting refresh with refresh token\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\n \"Token refresh successful during authentication check\",\n );\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const hasRefreshedIdToken =\n refreshedTokens?.id_token &&\n refreshedTokens.id_token.trim() !== \"\";\n if (hasRefreshedIdToken) {\n const isRefreshedTokenValid = await this.validateToken(\n refreshedTokens.id_token!,\n );\n if (isRefreshedTokenValid) {\n this.logger.info(\n \"Successfully restored session via refresh token\",\n );\n return true;\n }\n }\n } catch (error) {\n this.logger.warn(\n \"Token refresh failed during authentication check:\",\n error,\n );\n // Clear invalid tokens and refresh token since refresh failed\n await clearTokens(this.storage);\n }\n } else {\n this.logger.warn(\n \"ID token invalid and no refresh token available, clearing tokens\",\n );\n await clearTokens(this.storage);\n }\n } else if (hasRefreshToken && this.tokenRefresher) {\n // No ID token but we have a refresh token - attempt to restore session\n this.logger.info(\n \"No ID token found but refresh token exists, attempting session restore\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\"Token refresh successful during session restore\");\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const hasRefreshedIdToken =\n refreshedTokens?.id_token && refreshedTokens.id_token.trim() !== \"\";\n if (hasRefreshedIdToken) {\n const isRefreshedTokenValid = await this.validateToken(\n refreshedTokens.id_token!,\n );\n if (isRefreshedTokenValid) {\n this.logger.info(\n \"Successfully restored session from refresh token only\",\n );\n return true;\n }\n }\n } catch (error) {\n this.logger.warn(\"Session restore from refresh token failed:\", error);\n // Clear invalid refresh token since refresh failed\n await clearTokens(this.storage);\n }\n }\n\n return false;\n } catch (error) {\n this.logger.error(\"Error checking authentication:\", error);\n return false;\n }\n }\n\n /**\n * Validate if a token is still valid (not expired)\n * @param token JWT token to validate\n * @returns true if token is valid, false if expired or invalid\n */\n private async validateToken(token: string): Promise<boolean> {\n try {\n // Validate JWT format (should have 3 parts separated by dots)\n const parts = token.split(\".\");\n if (parts.length !== 3 || !parts[1]) {\n this.logger.warn(\"Invalid JWT format\");\n return false;\n }\n\n // Decode the JWT to check expiration\n const decoded = JSON.parse(atob(parts[1]));\n const now = Math.floor(Date.now() / 1000);\n\n // Check if token is expired (with 30 second buffer for clock skew)\n if (decoded.exp && decoded.exp <= now + 30) {\n this.logger.debug(\"Token is expired\", {\n exp: decoded.exp,\n now: now,\n expired: decoded.exp <= now,\n });\n return false;\n }\n\n this.logger.debug(\"Token is valid\");\n return true;\n } catch (error) {\n this.logger.warn(\"Token validation failed\", error);\n return false;\n }\n }\n\n /**\n * Check if we're using BrowserCookieStorage\n */\n private isBrowserCookieStorage(): boolean {\n return this.storage.constructor.name === \"BrowserCookieStorage\";\n }\n\n /**\n * Simple backend session check via API call (with caching)\n */\n private async checkBackendSession(): Promise<boolean> {\n try {\n // Check if we have a valid cached result\n if (this.backendSessionCache) {\n const age = Date.now() - this.backendSessionCache.timestamp;\n if (age < this.CACHE_DURATION) {\n this.logger.debug(\n `Using cached backend session result: ${this.backendSessionCache.result}`,\n );\n return this.backendSessionCache.result;\n }\n }\n\n if (!this.config.loginUrl) {\n return false;\n }\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(`${backendUrl}${endpoints.user}`, {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n });\n\n const result = response.ok;\n\n // Cache the result\n this.backendSessionCache = {\n result,\n timestamp: Date.now(),\n };\n\n this.logger.debug(\n `Backend session check: ${result} (cached for ${this.CACHE_DURATION / 1000}s)`,\n );\n return result;\n } catch (error) {\n this.logger.debug(\"Backend session check failed:\", error);\n\n // Cache negative result for shorter time\n this.backendSessionCache = {\n result: false,\n timestamp: Date.now(),\n };\n\n return false;\n }\n }\n\n /**\n * Get current user from shared lib storage or backend API\n * For backend flows with httpOnly cookies, falls back to API check\n */\n async getCurrentUser(): Promise<User | null> {\n try {\n // First, try to get user from accessible tokens\n const user = await getUser(this.storage);\n if (user) {\n this.logger.debug(\"Found user from accessible tokens\");\n return user;\n }\n\n // If no user found and we're using BrowserCookieStorage,\n // try getting user from backend API (for httpOnly cookies)\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\"No user from tokens, trying backend API...\");\n return await this.getUserFromBackendApi();\n }\n\n this.logger.debug(\"No user found and not using browser cookie storage\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to get user from shared storage:\", error);\n return null;\n }\n }\n\n /**\n * Get user information from backend API (with caching)\n */\n private async getUserFromBackendApi(): Promise<User | null> {\n try {\n if (!this.config.loginUrl) {\n this.logger.debug(\"No backend URL available for user fetch\");\n return null;\n }\n\n this.logger.debug(\"Fetching user from backend API...\");\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(`${backendUrl}${endpoints.user}`, {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n if (response.ok) {\n const data = await response.json();\n const user = data.user;\n this.logger.debug(\"Successfully fetched user from backend API\");\n return user;\n } else {\n this.logger.debug(`Backend user fetch failed: ${response.status}`);\n return null;\n }\n } catch (error) {\n this.logger.debug(\"Backend user fetch failed:\", error);\n return null;\n }\n }\n\n /**\n * Clear all authentication data using shared lib utilities\n * @param preserveLogoutState - If true, preserves logout state for cleanup after redirect\n */\n async clearSession(preserveLogoutState: boolean = false): Promise<void> {\n try {\n if (preserveLogoutState) {\n // During logout, we need to preserve logout state for cleanup after redirect\n await this.clearTokensExceptLogoutState();\n } else {\n // Normal session clearing - clear everything\n await clearTokens(this.storage);\n }\n\n // Clear user session using shared utilities\n const userSession = new GenericUserSession(this.storage);\n await userSession.clear();\n\n // Clear backend session cache\n this.backendSessionCache = null;\n\n // Stop token refresher when session is cleared\n this.tokenRefresher?.setAuthenticationState(false);\n\n this.events.emit(AuthEvent.USER_SESSION_CHANGED, null);\n this.logger.info(\"Session cleared using shared lib utilities\");\n } catch (error) {\n this.logger.error(\"Failed to clear session:\", error);\n throw error;\n }\n }\n\n /**\n * Clear tokens from storage except logout state\n * This is needed during logout to preserve the logout state for cleanup after redirect\n */\n private async clearTokensExceptLogoutState(): Promise<void> {\n // Clear all token-related keys except LOGOUT_STATE\n // These are the OAuth token types from the constants\n const keysToDelete = [\n \"id_token\",\n \"access_token\",\n \"refresh_token\",\n \"oidc_session_expires_at\",\n REFRESH_IN_PROGRESS,\n AUTOREFRESH_TIMEOUT_NAME,\n // Note: NOT clearing LOGOUT_STATE here - it's needed for cleanup after redirect\n ];\n\n const clearPromises = keysToDelete.map(async (key) => {\n await this.storage.delete(key);\n });\n\n await Promise.all(clearPromises);\n }\n\n /**\n * Manually trigger token refresh\n */\n async refreshTokens(): Promise<void> {\n if (!this.tokenRefresher) {\n throw new Error(\n \"Token refresher not initialized. Call initializeWithAuthConfig first.\",\n );\n }\n\n return this.tokenRefresher.refreshTokens();\n }\n\n /**\n * Get token refresher state for debugging\n */\n getTokenRefresherState(): {\n isInitialized: boolean;\n isAuthenticated: boolean;\n isAutoRefreshActive: boolean;\n } | null {\n return this.tokenRefresher?.getState() || null;\n }\n\n /**\n * Clean up resources when session manager is destroyed\n */\n async destroy(): Promise<void> {\n await this.tokenRefresher?.destroy();\n this.tokenRefresher = undefined;\n this.logger.info(\"SessionManager destroyed\");\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"SessionManager.js","sourceRoot":"","sources":["../../../src/vanillajs/auth/SessionManager.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AuthStorage } from \"../../types.js\";\nimport type { AuthenticationEvents } from \"./AuthenticationEvents.js\";\nimport type { User, Session } from \"../types/index.js\"; // Assuming Session might be used internally\nimport { AuthEvent } from \"../types/index.js\";\nimport { createLogger } from \"../utils/logger.js\";\nimport { TokenRefresher } from \"./TokenRefresher.js\";\nimport type { AuthConfig } from \"../../server/config.js\";\nimport {\n retrieveTokens,\n clearTokens,\n getBackendEndpoints,\n} from \"../../shared/lib/util.js\";\nimport { getUser } from \"../../shared/lib/session.js\";\nimport { GenericUserSession } from \"../../shared/lib/UserSession.js\";\nimport {\n AUTOREFRESH_TIMEOUT_NAME,\n REFRESH_IN_PROGRESS,\n} from \"../../constants.js\";\nimport { verify, type VerifyOptions } from \"@civic/auth-verify\";\nimport { OAuthTokenTypes } from \"@/shared/lib/types.js\";\nimport { addSlashIfNeeded } from \"@/lib/oauth.js\";\n\nexport class SessionManager {\n private storage: AuthStorage;\n private events: AuthenticationEvents;\n private tokenRefresher?: TokenRefresher;\n private logger = createLogger(\"session\");\n private config: AuthConfig;\n\n // Simple cache for backend session check to avoid excessive API calls\n private backendSessionCache: {\n result: boolean;\n timestamp: number;\n } | null = null;\n private readonly CACHE_DURATION = 30 * 1000; // 30 seconds\n\n constructor(\n storageAdapter: AuthStorage,\n events: AuthenticationEvents,\n config: AuthConfig,\n ) {\n this.storage = storageAdapter;\n this.events = events;\n this.config = config;\n this.logger.info(\n \"SessionManager initialized with shared lib token storage\",\n );\n }\n\n /**\n * Initialize the session manager with auth configuration to enable token refresh\n */\n async initializeWithAuthConfig(authConfig: AuthConfig): Promise<void> {\n try {\n // Initialize token refresher\n this.tokenRefresher = new TokenRefresher(\n this.storage,\n this.events,\n authConfig,\n );\n await this.tokenRefresher.initialize(authConfig);\n\n // Check current authentication state (this now includes token validation and refresh attempts)\n const isAuthenticated = await this.isAuthenticated();\n\n // Set authentication state on the token refresher\n // This will enable auto-refresh if the user is authenticated (including after successful refresh)\n this.tokenRefresher.setAuthenticationState(isAuthenticated);\n\n this.logger.info(\n \"SessionManager initialized with token refresh capability\",\n { isAuthenticated },\n );\n } catch (error) {\n this.logger.error(\n \"Failed to initialize SessionManager with auth config:\",\n error,\n );\n this.events.emit(AuthEvent.TOKEN_REFRESH_ERROR, error);\n }\n }\n\n /**\n * Build current session from shared lib storage or backend API\n * For backend flows with httpOnly cookies, creates limited session when tokens aren't accessible\n */\n async getCurrentSession(): Promise<Session | null> {\n try {\n const tokens = await retrieveTokens(this.storage);\n\n const user = await this.getCurrentUser();\n\n // If we have tokens and user (normal flow), create full session\n if ((tokens?.id_token || tokens?.access_token) && user) {\n // Validate all available tokens\n const validationResults = await this.validateTokens({\n id_token: tokens.id_token,\n access_token: tokens.access_token,\n });\n\n // Check if any tokens failed validation\n if (\n !validationResults.idTokenValid ||\n !validationResults.accessTokenValid\n ) {\n this.logger.warn(\n \"Token validation failed in getCurrentSession, returning null\",\n );\n return null;\n }\n\n return {\n user,\n accessToken: tokens.access_token,\n idToken: tokens.id_token,\n refreshToken: tokens.refresh_token ?? undefined,\n expiresAt: tokens.oidc_session_expires_at ?? undefined,\n };\n }\n\n // If we have user but no accessible tokens (backend flow with httpOnly cookies),\n // create a limited session with just user info\n if (user && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Creating limited session for backend flow (tokens in httpOnly cookies)\",\n );\n return {\n user,\n accessToken: undefined, // Not accessible in httpOnly cookies\n idToken: undefined, // Not accessible in httpOnly cookies\n refreshToken: undefined, // Not accessible in httpOnly cookies\n expiresAt: undefined, // Not accessible in httpOnly cookies\n };\n }\n\n this.logger.debug(\"No session available - no tokens or user found\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to load session:\", error);\n return null;\n }\n }\n\n /**\n * Check if user is authenticated using shared lib utilities\n * For backend flows with httpOnly cookies, falls back to API check\n *\n * This method now validates tokens on load and attempts refresh if:\n * - Tokens exist but are expired/invalid\n * - A refresh token is available\n */\n async isAuthenticated(): Promise<boolean> {\n try {\n // First, try the standard token-based check\n const tokens = await retrieveTokens(this.storage);\n\n // Normalize empty strings to null for consistent checking\n const hasIdToken = tokens?.id_token && tokens.id_token.trim() !== \"\";\n const hasRefreshToken =\n tokens?.refresh_token && tokens.refresh_token.trim() !== \"\";\n\n // If no tokens found and we're using BrowserCookieStorage,\n // try checking backend session (for httpOnly cookies)\n if (!hasIdToken && this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"No tokens accessible, checking backend session...\",\n await this.checkBackendSession(),\n );\n return await this.checkBackendSession();\n }\n\n // If we have tokens, validate them\n if (hasIdToken) {\n const validationResults = await this.validateTokens({\n id_token: tokens.id_token,\n access_token: tokens.access_token,\n });\n\n // Both tokens must be valid (if they exist) for authentication to be considered valid\n const allTokensValid =\n validationResults.idTokenValid && validationResults.accessTokenValid;\n\n if (allTokensValid) {\n this.logger.debug(\n \"All available tokens are valid, user is authenticated\",\n );\n return true;\n }\n\n // Some tokens are invalid/expired - attempt refresh if refresh token exists\n if (hasRefreshToken && this.tokenRefresher) {\n this.logger.info(\n \"Some tokens expired/invalid, attempting refresh with refresh token\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\n \"Token refresh successful during authentication check\",\n );\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const refreshedValidationResults = await this.validateTokens({\n id_token: refreshedTokens?.id_token,\n access_token: refreshedTokens?.access_token,\n });\n\n const allRefreshedTokensValid =\n refreshedValidationResults.idTokenValid &&\n refreshedValidationResults.accessTokenValid;\n\n if (allRefreshedTokensValid) {\n this.logger.info(\n \"Successfully restored session via refresh token\",\n );\n return true;\n }\n } catch (error) {\n this.logger.warn(\n \"Token refresh failed during authentication check:\",\n error,\n );\n // Clear invalid tokens and refresh token since refresh failed\n await clearTokens(this.storage);\n }\n } else {\n this.logger.warn(\n \"Some tokens invalid and no refresh token available, clearing tokens\",\n );\n await clearTokens(this.storage);\n }\n } else if (hasRefreshToken && this.tokenRefresher) {\n // No ID token but we have a refresh token - attempt to restore session\n this.logger.info(\n \"No ID token found but refresh token exists, attempting session restore\",\n );\n\n try {\n // Attempt token refresh\n await this.tokenRefresher.refreshTokens();\n this.logger.info(\"Token refresh successful during session restore\");\n\n // Check if we now have valid tokens after refresh\n const refreshedTokens = await retrieveTokens(this.storage);\n const refreshedValidationResults = await this.validateTokens({\n id_token: refreshedTokens?.id_token,\n access_token: refreshedTokens?.access_token,\n });\n\n const allRefreshedTokensValid =\n refreshedValidationResults.idTokenValid &&\n refreshedValidationResults.accessTokenValid;\n\n if (allRefreshedTokensValid) {\n this.logger.info(\n \"Successfully restored session from refresh token only\",\n );\n return true;\n }\n } catch (error) {\n this.logger.warn(\"Session restore from refresh token failed:\", error);\n // Clear invalid refresh token since refresh failed\n await clearTokens(this.storage);\n }\n }\n\n return false;\n } catch (error) {\n this.logger.error(\"Error checking authentication:\", error);\n return false;\n }\n }\n\n /**\n * Validate if a token is cryptographically valid and not expired\n * Uses proper JWT verification with signature validation using JWKS\n * @param token JWT token to validate\n * @param tokenType Type of token (for logging and cleanup purposes)\n * @returns true if token is valid, false if expired or invalid\n */\n private async validateToken(\n token: string,\n tokenType: \"id_token\" | \"access_token\" = \"id_token\",\n ): Promise<boolean> {\n try {\n // For backend flows with httpOnly cookies, we can't validate tokens client-side\n // since they're not accessible to JavaScript\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\n \"Backend flow: skipping client-side token validation\",\n );\n return true; // Backend will validate tokens server-side\n }\n\n // Configure verification options based on token type\n const verifyOptions: VerifyOptions = {\n issuer: addSlashIfNeeded(\n this.config.oauthServerBaseUrl ?? \"https://auth.civic.com/oauth/\",\n ),\n };\n\n // Set audience based on token type\n if (tokenType === \"id_token\" && this.config.clientId) {\n // ID tokens should have the client ID as audience for proper OIDC compliance\n verifyOptions.aud = this.config.clientId;\n } else if (tokenType === \"access_token\") {\n // Access tokens have \"civic\" as audience based on auth server configuration\n verifyOptions.aud = \"civic\";\n verifyOptions.clientId = this.config.clientId;\n }\n\n this.logger.debug(`Verifying ${tokenType} with options:`, verifyOptions);\n\n // Use the @civic/auth-verify package for proper JWT verification\n await verify(token, verifyOptions);\n\n this.logger.debug(`${tokenType} cryptographically verified and valid`);\n return true;\n } catch (error) {\n this.logger.warn(`${tokenType} validation failed`, error);\n // Clear the specific token that failed validation\n if (tokenType === \"id_token\") {\n this.storage.delete(OAuthTokenTypes.ID_TOKEN);\n } else if (tokenType === \"access_token\") {\n this.storage.delete(OAuthTokenTypes.ACCESS_TOKEN);\n }\n return false;\n }\n }\n\n /**\n * Validate both ID token and access token if they exist\n * @param tokens Token object containing id_token and access_token\n * @returns Object indicating which tokens are valid\n */\n private async validateTokens(tokens: {\n id_token?: string;\n access_token?: string;\n }): Promise<{\n idTokenValid: boolean;\n accessTokenValid: boolean;\n }> {\n const results = {\n idTokenValid: true, // Default to true if token doesn't exist\n accessTokenValid: true, // Default to true if token doesn't exist\n };\n\n // Validate ID token if it exists\n if (tokens.id_token && tokens.id_token.trim() !== \"\") {\n results.idTokenValid = await this.validateToken(\n tokens.id_token,\n \"id_token\",\n );\n }\n\n // Validate access token if it exists\n if (tokens.access_token && tokens.access_token.trim() !== \"\") {\n results.accessTokenValid = await this.validateToken(\n tokens.access_token,\n \"access_token\",\n );\n }\n\n return results;\n }\n\n /**\n * Check if we're using BrowserCookieStorage\n */\n private isBrowserCookieStorage(): boolean {\n return this.storage.constructor.name === \"BrowserCookieStorage\";\n }\n\n /**\n * Simple backend session check via API call (with caching)\n */\n private async checkBackendSession(): Promise<boolean> {\n try {\n // Check if we have a valid cached result\n if (this.backendSessionCache) {\n const age = Date.now() - this.backendSessionCache.timestamp;\n if (age < this.CACHE_DURATION) {\n this.logger.debug(\n `Using cached backend session result: ${this.backendSessionCache.result}`,\n );\n return this.backendSessionCache.result;\n }\n }\n\n if (!this.config.loginUrl) {\n return false;\n }\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(`${backendUrl}${endpoints.user}`, {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n });\n\n const result = response.ok;\n\n // Cache the result\n this.backendSessionCache = {\n result,\n timestamp: Date.now(),\n };\n\n this.logger.debug(\n `Backend session check: ${result} (cached for ${this.CACHE_DURATION / 1000}s)`,\n );\n return result;\n } catch (error) {\n this.logger.debug(\"Backend session check failed:\", error);\n\n // Cache negative result for shorter time\n this.backendSessionCache = {\n result: false,\n timestamp: Date.now(),\n };\n\n return false;\n }\n }\n\n /**\n * Get current user from shared lib storage or backend API\n * For backend flows with httpOnly cookies, falls back to API check\n */\n async getCurrentUser(): Promise<User | null> {\n try {\n // First, try to get user from accessible tokens\n const user = await getUser(this.storage);\n if (user) {\n this.logger.debug(\"Found user from accessible tokens\");\n return user;\n }\n\n // If no user found and we're using BrowserCookieStorage,\n // try getting user from backend API (for httpOnly cookies)\n if (this.isBrowserCookieStorage()) {\n this.logger.debug(\"No user from tokens, trying backend API...\");\n return await this.getUserFromBackendApi();\n }\n\n this.logger.debug(\"No user found and not using browser cookie storage\");\n return null;\n } catch (error) {\n this.logger.error(\"Failed to get user from shared storage:\", error);\n return null;\n }\n }\n\n /**\n * Get user information from backend API (with caching)\n */\n private async getUserFromBackendApi(): Promise<User | null> {\n try {\n if (!this.config.loginUrl) {\n this.logger.debug(\"No backend URL available for user fetch\");\n return null;\n }\n\n this.logger.debug(\"Fetching user from backend API...\");\n\n const backendUrl = new URL(this.config.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.config.backendEndpoints);\n const response = await fetch(`${backendUrl}${endpoints.user}`, {\n method: \"GET\",\n credentials: \"include\", // Send httpOnly cookies\n headers: { \"Content-Type\": \"application/json\" },\n });\n\n if (response.ok) {\n const data = await response.json();\n const user = data.user;\n this.logger.debug(\"Successfully fetched user from backend API\");\n return user;\n } else {\n this.logger.debug(`Backend user fetch failed: ${response.status}`);\n return null;\n }\n } catch (error) {\n this.logger.debug(\"Backend user fetch failed:\", error);\n return null;\n }\n }\n\n /**\n * Clear all authentication data using shared lib utilities\n * @param preserveLogoutState - If true, preserves logout state for cleanup after redirect\n */\n async clearSession(preserveLogoutState: boolean = false): Promise<void> {\n try {\n if (preserveLogoutState) {\n // During logout, we need to preserve logout state for cleanup after redirect\n await this.clearTokensExceptLogoutState();\n } else {\n // Normal session clearing - clear everything\n await clearTokens(this.storage);\n }\n\n // Clear user session using shared utilities\n const userSession = new GenericUserSession(this.storage);\n await userSession.clear();\n\n // Clear backend session cache\n this.backendSessionCache = null;\n\n // Stop token refresher when session is cleared\n this.tokenRefresher?.setAuthenticationState(false);\n\n this.events.emit(AuthEvent.USER_SESSION_CHANGED, null);\n this.logger.info(\"Session cleared using shared lib utilities\");\n } catch (error) {\n this.logger.error(\"Failed to clear session:\", error);\n throw error;\n }\n }\n\n /**\n * Clear tokens from storage except logout state\n * This is needed during logout to preserve the logout state for cleanup after redirect\n */\n private async clearTokensExceptLogoutState(): Promise<void> {\n // Clear all token-related keys except LOGOUT_STATE\n // These are the OAuth token types from the constants\n const keysToDelete = [\n OAuthTokenTypes.ID_TOKEN,\n OAuthTokenTypes.ACCESS_TOKEN,\n OAuthTokenTypes.REFRESH_TOKEN,\n OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT,\n REFRESH_IN_PROGRESS,\n AUTOREFRESH_TIMEOUT_NAME,\n // Note: NOT clearing LOGOUT_STATE here - it's needed for cleanup after redirect\n ];\n\n const clearPromises = keysToDelete.map(async (key) => {\n await this.storage.delete(key);\n });\n\n await Promise.all(clearPromises);\n }\n\n /**\n * Manually trigger token refresh\n */\n async refreshTokens(): Promise<void> {\n if (!this.tokenRefresher) {\n throw new Error(\n \"Token refresher not initialized. Call initializeWithAuthConfig first.\",\n );\n }\n\n return this.tokenRefresher.refreshTokens();\n }\n\n /**\n * Get token refresher state for debugging\n */\n getTokenRefresherState(): {\n isInitialized: boolean;\n isAuthenticated: boolean;\n isAutoRefreshActive: boolean;\n } | null {\n return this.tokenRefresher?.getState() || null;\n }\n\n /**\n * Clean up resources when session manager is destroyed\n */\n async destroy(): Promise<void> {\n await this.tokenRefresher?.destroy();\n this.tokenRefresher = undefined;\n this.logger.info(\"SessionManager destroyed\");\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigProcessor.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EAEzB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,wBAAwB,
|
|
1
|
+
{"version":3,"file":"ConfigProcessor.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,qBAAqB,EACrB,wBAAwB,EAEzB,MAAM,uBAAuB,CAAC;AAO/B;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,wBAAwB,CA2E1B"}
|
|
@@ -18,7 +18,21 @@ export function processConfigWithDefaults(config) {
|
|
|
18
18
|
// the original displaymode doesn't suppors embedded, so we need to proxy it to iframe + iframeDisplayMode: "embedded"
|
|
19
19
|
const originalDisplayMode = config.displayMode || "iframe";
|
|
20
20
|
const processedDisplayMode = originalDisplayMode === "embedded" ? "iframe" : originalDisplayMode;
|
|
21
|
-
|
|
21
|
+
// Determine iframeDisplayMode with proper precedence:
|
|
22
|
+
// 1. User explicitly provided iframeDisplayMode (highest priority)
|
|
23
|
+
// 2. If displayMode is "embedded", set to "embedded"
|
|
24
|
+
// 3. Default to "modal" for iframe mode
|
|
25
|
+
const processedIframeDisplayMode = config.iframeDisplayMode ??
|
|
26
|
+
(originalDisplayMode === "embedded"
|
|
27
|
+
? "embedded"
|
|
28
|
+
: processedDisplayMode === "iframe"
|
|
29
|
+
? "modal"
|
|
30
|
+
: undefined);
|
|
31
|
+
// Determine preloadIframe with proper precedence:
|
|
32
|
+
// 1. User explicitly provided preloadIframe (highest priority)
|
|
33
|
+
// 2. If displayMode is "embedded", set to false (better for embedded visibility)
|
|
34
|
+
// 3. Default to true
|
|
35
|
+
const processedPreloadIframe = config.preloadIframe ?? originalDisplayMode !== "embedded";
|
|
22
36
|
// Process redirectUrl - default to current page without query parameters
|
|
23
37
|
const redirectUrl = config.redirectUrl ||
|
|
24
38
|
`${window.location.origin}${window.location.pathname}`;
|
|
@@ -50,7 +64,7 @@ export function processConfigWithDefaults(config) {
|
|
|
50
64
|
storageAdapter,
|
|
51
65
|
loginUrl: config.loginUrl, // Include loginUrl in processed config
|
|
52
66
|
backendEndpoints: config.backendEndpoints, // Include backend endpoints in processed config
|
|
53
|
-
preloadIframe:
|
|
67
|
+
preloadIframe: processedPreloadIframe, // Use the processed preloadIframe value
|
|
54
68
|
autoRedirect: config.autoRedirect !== false, // Default to true unless explicitly set to false
|
|
55
69
|
}; // Type assertion: we've validated the config and ensured all required properties are present
|
|
56
70
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ConfigProcessor.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6CAA6C,CAAC;AACnF,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAO5E,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,uBAAuB,CAAC;AAE/B;;GAEG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAA6B;IAE7B,kCAAkC;IAClC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,aAAa,GAAkB;QACnC,OAAO,EAAE,KAAK;QACd,SAAS,EAAE,GAAG;QACd,KAAK,EAAE,OAAgB;QACvB,GAAG,MAAM,CAAC,OAAO;KAClB,CAAC;IAEF,uFAAuF;IACvF,sHAAsH;IACtH,MAAM,mBAAmB,GAAG,MAAM,CAAC,WAAW,IAAI,QAAQ,CAAC;IAC3D,MAAM,oBAAoB,GACxB,mBAAmB,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,mBAAmB,CAAC;IAEtE,MAAM,0BAA0B,GAC9B,mBAAmB,KAAK,UAAU,CAAC,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"ConfigProcessor.js","sourceRoot":"","sources":["../../../../src/vanillajs/auth/config/ConfigProcessor.ts"],"names":[],"mappings":"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","sourcesContent":["import { LocalStorageAdapter } from \"../../../browser/storage.js\";\nimport { BrowserCookieStorage } from \"../../../shared/lib/BrowserCookieStorage.js\";\nimport { DEFAULT_SCOPES, DEFAULT_AUTH_SERVER } from \"../../../constants.js\";\nimport type { DisplayMode } from \"../../../types.js\";\nimport type {\n CivicAuthClientConfig,\n ProcessedCivicAuthConfig,\n LoggingConfig,\n} from \"../types/AuthTypes.js\";\nimport {\n CivicAuthError,\n CivicAuthErrorCode,\n CIVIC_AUTH_CONSTANTS,\n} from \"../types/AuthTypes.js\";\n\n/**\n * Process the configuration with defaults and validation\n */\nexport function processConfigWithDefaults(\n config: CivicAuthClientConfig,\n): ProcessedCivicAuthConfig {\n // Validate required configuration\n validateRequiredConfig(config);\n\n const loggingConfig: LoggingConfig = {\n enabled: false,\n namespace: \"*\",\n level: \"debug\" as const,\n ...config.logging,\n };\n\n // Handle displayMode proxy: map \"embedded\" to \"iframe\" + iframeDisplayMode: \"embedded\"\n // the original displaymode doesn't suppors embedded, so we need to proxy it to iframe + iframeDisplayMode: \"embedded\"\n const originalDisplayMode = config.displayMode || \"iframe\";\n const processedDisplayMode: DisplayMode =\n originalDisplayMode === \"embedded\" ? \"iframe\" : originalDisplayMode;\n\n // Determine iframeDisplayMode with proper precedence:\n // 1. User explicitly provided iframeDisplayMode (highest priority)\n // 2. If displayMode is \"embedded\", set to \"embedded\"\n // 3. Default to \"modal\" for iframe mode\n const processedIframeDisplayMode =\n config.iframeDisplayMode ??\n (originalDisplayMode === \"embedded\"\n ? \"embedded\"\n : processedDisplayMode === \"iframe\"\n ? \"modal\"\n : undefined);\n\n // Determine preloadIframe with proper precedence:\n // 1. User explicitly provided preloadIframe (highest priority)\n // 2. If displayMode is \"embedded\", set to false (better for embedded visibility)\n // 3. Default to true\n const processedPreloadIframe =\n config.preloadIframe ?? originalDisplayMode !== \"embedded\";\n\n // Process redirectUrl - default to current page without query parameters\n const redirectUrl =\n config.redirectUrl ||\n `${window.location.origin}${window.location.pathname}`;\n\n // Process logoutRedirectUrl - default to redirectUrl if not provided (same behavior as reactjs implementation)\n const logoutRedirectUrl = config.logoutRedirectUrl || redirectUrl;\n\n // Auto-select storage adapter based on loginUrl\n // If loginUrl is provided (backend integration), automatically use BrowserCookieStorage\n // Otherwise, use provided storageAdapter or default to LocalStorageAdapter\n const storageAdapter = config.loginUrl\n ? new BrowserCookieStorage()\n : config.storageAdapter || new LocalStorageAdapter();\n\n return {\n ...config,\n redirectUrl,\n logoutRedirectUrl,\n oauthServerBaseUrl: config.oauthServerBaseUrl || DEFAULT_AUTH_SERVER,\n scopes: config.scopes || DEFAULT_SCOPES,\n textSignals: config.textSignals || {\n success: \"Authentication successful!\",\n error: \"Authentication failed. Please try again.\",\n },\n displayMode: processedDisplayMode,\n iframeDisplayMode: processedIframeDisplayMode,\n authProcessTimeout:\n config.authProcessTimeout ||\n CIVIC_AUTH_CONSTANTS.DEFAULT_AUTH_PROCESS_TIMEOUT,\n iframeId: config.iframeId || CIVIC_AUTH_CONSTANTS.DEFAULT_IFRAME_ID,\n prompt: \"consent\",\n logging: loggingConfig,\n storageAdapter,\n loginUrl: config.loginUrl, // Include loginUrl in processed config\n backendEndpoints: config.backendEndpoints, // Include backend endpoints in processed config\n preloadIframe: processedPreloadIframe, // Use the processed preloadIframe value\n autoRedirect: config.autoRedirect !== false, // Default to true unless explicitly set to false\n } as ProcessedCivicAuthConfig; // Type assertion: we've validated the config and ensured all required properties are present\n}\n\n/**\n * Validates required configuration properties\n */\nfunction validateRequiredConfig(config: CivicAuthClientConfig): void {\n // Dynamic validation: clientId is only required if loginUrl is not provided\n if (!config.loginUrl && !config.clientId) {\n throw new CivicAuthError(\n \"CivicAuth: clientId is required when loginUrl is not provided.\",\n CivicAuthErrorCode.CONFIG_REQUIRED,\n );\n }\n\n // Conditional validation for targetContainerElement\n // Handle both the new \"embedded\" displayMode and the legacy iframe + iframeDisplayMode approach\n const displayMode = config.displayMode || \"iframe\";\n const iframeDisplayMode = config.iframeDisplayMode;\n\n // Check if we need a container element\n const needsContainer =\n displayMode === \"embedded\" || // New simplified API\n (displayMode === \"iframe\" && iframeDisplayMode === \"embedded\"); // Legacy API\n\n if (needsContainer && !config.targetContainerElement) {\n throw new CivicAuthError(\n \"CivicAuth: targetContainerElement is required for embedded iframe mode. \" +\n \"You can use displayMode: 'embedded' for a simplified API, \" +\n \"or use displayMode: 'iframe' with iframeDisplayMode: 'embedded'. \" +\n \"For modal iframe mode, use displayMode: 'iframe' (default). \" +\n \"For non-iframe modes, use displayMode 'redirect' or 'new_tab'.\",\n CivicAuthErrorCode.CONFIG_REQUIRED,\n );\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MessageHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/MessageHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAIV,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,0BAA0B,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,0BAA0B,CAG9B;IACJ,OAAO,CAAC,OAAO,CAAa;IAG5B,OAAO,CAAC,oBAAoB,CAAC,CAAS;gBAE1B,aAAa,EAAE,oBAAoB;IAU/C;;;;;;;;OAQG;IACI,mBAAmB,CAAC,aAAa,EAAE,iBAAiB,GAAG,IAAI;IAIlE;;;;;;;OAOG;IACI,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAQ5D;;OAEG;IACI,yBAAyB,IAAI,IAAI;IAOxC;;;;;;;OAOG;IACI,aAAa,UAAW,YAAY,KAAG,IAAI,CAYhD;IAEF;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;
|
|
1
|
+
{"version":3,"file":"MessageHandler.d.ts","sourceRoot":"","sources":["../../../../src/vanillajs/auth/handlers/MessageHandler.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,KAAK,EAIV,wBAAwB,EACzB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAI1D,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,wBAAwB,CAAC;IACjC,MAAM,EAAE,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;IACxC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAClC,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,KAAK,IAAI,CAAC;IAC5C,WAAW,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,cAAc,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,0BAA0B,EAAE,CAAC,SAAS,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IAClE,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED;;;GAGG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,MAAM,CAAqC;IACnD,OAAO,CAAC,aAAa,CAAC,CAAoB;IAC1C,OAAO,CAAC,aAAa,CAA+B;IACpD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,cAAc,CAA+B;IACrD,OAAO,CAAC,0BAA0B,CAG9B;IACJ,OAAO,CAAC,OAAO,CAAa;IAG5B,OAAO,CAAC,oBAAoB,CAAC,CAAS;gBAE1B,aAAa,EAAE,oBAAoB;IAU/C;;;;;;;;OAQG;IACI,mBAAmB,CAAC,aAAa,EAAE,iBAAiB,GAAG,IAAI;IAIlE;;;;;;;OAOG;IACI,uBAAuB,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI;IAQ5D;;OAEG;IACI,yBAAyB,IAAI,IAAI;IAOxC;;;;;;;OAOG;IACI,aAAa,UAAW,YAAY,KAAG,IAAI,CAYhD;IAEF;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IAa1B;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IA6D5B;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;IAoC1B;;;;;;;;OAQG;IACH,OAAO,CAAC,sBAAsB;IAS9B;;;;;;;;OAQG;IACH,OAAO,CAAC,0BAA0B;IA6DlC;;;;;;;OAOG;IAEH,OAAO,CAAC,sBAAsB;IAc9B;;;;;;;OAOG;IACH,OAAO,CAAC,wBAAwB;IAoBhC;;;;;OAKG;IACH,OAAO,CAAC,8BAA8B;IAkBtC;;;;;;;;OAQG;IACH,OAAO,CAAC,kBAAkB;IA2B1B;;;;;;;OAOG;IACH,OAAO,CAAC,iCAAiC;IAqBzC;;;;;;;;OAQG;IACH,OAAO,CAAC,sBAAsB;IAY9B;;;;;;;OAOG;IACH,OAAO,CAAC,0BAA0B;IAYlC;;;;;;;OAOG;IACH,OAAO,CAAC,yBAAyB;IAmCjC;;;;;;;OAOG;IACH,OAAO,CAAC,iBAAiB;IASzB;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;CAcxB"}
|
|
@@ -123,6 +123,9 @@ export class MessageHandler {
|
|
|
123
123
|
// ignore URL parsing errors
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
|
+
if (this.config.oauthServerBaseUrl) {
|
|
127
|
+
allowedOrigins.push(new URL(this.config.oauthServerBaseUrl).origin);
|
|
128
|
+
}
|
|
126
129
|
// Add the client app's own origin (same-origin) for messages sent after token exchange
|
|
127
130
|
// This is needed when the iframe navigates to the client app's callback URL
|
|
128
131
|
const clientOrigin = window.location.origin;
|