@civic/auth 0.10.0-beta.6 → 0.10.0-beta.7
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 +3 -0
- package/README.md +1 -0
- package/dist/lib/logger.d.ts +1 -0
- package/dist/lib/logger.d.ts.map +1 -1
- package/dist/lib/logger.js +1 -0
- package/dist/lib/logger.js.map +1 -1
- package/dist/nextjs/hooks/useInitialAuthConfig.d.ts.map +1 -1
- package/dist/nextjs/hooks/useInitialAuthConfig.js +3 -0
- package/dist/nextjs/hooks/useInitialAuthConfig.js.map +1 -1
- package/dist/nextjs/middleware.d.ts +2 -1
- package/dist/nextjs/middleware.d.ts.map +1 -1
- package/dist/nextjs/middleware.js +33 -51
- package/dist/nextjs/middleware.js.map +1 -1
- package/dist/nextjs/routeHandler.d.ts +3 -0
- package/dist/nextjs/routeHandler.d.ts.map +1 -1
- package/dist/nextjs/routeHandler.js +3 -0
- package/dist/nextjs/routeHandler.js.map +1 -1
- package/dist/nextjs/utils.d.ts +16 -1
- package/dist/nextjs/utils.d.ts.map +1 -1
- package/dist/nextjs/utils.js +78 -10
- package/dist/nextjs/utils.js.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.d.ts +1 -0
- package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
- package/dist/reactjs/core/GlobalAuthManager.js +5 -1
- package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
- package/dist/server/ServerAuthenticationResolver.d.ts +3 -2
- package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
- package/dist/server/ServerAuthenticationResolver.js +23 -6
- package/dist/server/ServerAuthenticationResolver.js.map +1 -1
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/login.d.ts +2 -1
- package/dist/server/login.d.ts.map +1 -1
- package/dist/server/login.js.map +1 -1
- package/dist/server/session.d.ts +4 -3
- package/dist/server/session.d.ts.map +1 -1
- package/dist/server/session.js.map +1 -1
- package/dist/server/users.d.ts +4 -3
- package/dist/server/users.d.ts.map +1 -1
- package/dist/server/users.js.map +1 -1
- package/dist/services/types.d.ts +1 -1
- package/dist/services/types.d.ts.map +1 -1
- package/dist/services/types.js.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.d.ts.map +1 -1
- package/dist/shared/lib/BrowserAuthenticationRefresher.js +6 -6
- package/dist/shared/lib/BrowserAuthenticationRefresher.js.map +1 -1
- package/dist/shared/lib/session.d.ts +2 -1
- package/dist/shared/lib/session.d.ts.map +1 -1
- package/dist/shared/lib/session.js +5 -2
- package/dist/shared/lib/session.js.map +1 -1
- package/dist/shared/lib/util.d.ts +2 -2
- package/dist/shared/lib/util.d.ts.map +1 -1
- package/dist/shared/lib/util.js +4 -4
- 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 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts +4 -3
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.js +34 -21
- package/dist/vanillajs/auth/BackendAuthenticationRefresher.js.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.d.ts.map +1 -1
- package/dist/vanillajs/auth/TokenRefresher.js +3 -3
- package/dist/vanillajs/auth/TokenRefresher.js.map +1 -1
- package/package.json +1 -1
package/dist/server/login.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/server/login.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/server/login.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,4BAA4B,EAAE,MAAM,0CAA0C,CAAC;AAExF,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAa/C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAY,EACZ,KAAa,EACb,OAAsB,EACtB,MAAkB;IAElB,MAAM,kBAAkB,GAAG,MAAM,4BAA4B,CAAC,KAAK,CACjE;QACE,GAAG,MAAM;QACT,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,mBAAmB;KACvD,EACD,OAAO,EACP,MAAM,CAAC,iBAAiB,CACzB,CAAC;IAEF,OAAO,kBAAkB,CAAC,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AACvD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,OAAoB;IACnD,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAOG,EACH,OAAqB;IAErB,oFAAoF;IACpF,IAAI,KAAa,CAAC;IAClB,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QACjB,sEAAsE;QACtE,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;IACvB,CAAC;SAAM,IAAI,MAAM,CAAC,UAAU,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACjD,wDAAwD;QACxD,KAAK,GAAG,aAAa,CAAC;YACpB,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;SAC9B,CAAC,CAAC;IACL,CAAC;SAAM,CAAC;QACN,oCAAoC;QACpC,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,cAAc,CAAC;IAE/C,mDAAmD;IACnD,8DAA8D;IAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,KAAK,KAAK,CAAC;IAEtC,iEAAiE;IACjE,MAAM,YAAY,GAChB,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,IAAI,+BAA+B,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAE3E,kDAAkD;IAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,CAAC;IAED,MAAM,aAAa,GAAG,IAAI,8BAA8B,CAAC;QACvD,GAAG,MAAM;QACT,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,KAAK;QACL,MAAM;QACN,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,mBAAmB;QACtD,mGAAmG;QACnG,kEAAkE;QAClE,YAAY,EAAE,YAAY,IAAI,SAAS;KACxC,CAAC,CAAC;IAEH,OAAO,aAAa,CAAC,MAAM,EAAE,CAAC;AAChC,CAAC","sourcesContent":["import type {\n AuthStorage,\n OIDCTokenResponseBody,\n FrameworkType,\n} from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from \"@/constants.js\";\nimport { GenericAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport type { AuthConfig } from \"@/server/config.ts\";\nimport { generateState } from \"@/lib/oauth.js\";\nimport type { CookieStorage } from \"./index.js\";\n\n/**\n * Context interface for detecting frontend vs backend requests\n */\nexport interface RequestContext {\n referer?: string;\n origin?: string;\n userAgent?: string;\n acceptsJson?: boolean;\n}\n\n/**\n * Resolve an OAuth access code to a set of OIDC tokens\n * @param code The access code, typically from a query parameter in the redirect url\n * @param state The oauth random state string, used to distinguish between requests. Typically also passed in the redirect url\n * @param storage The place that this server uses to store session data (e.g. a cookie store)\n * @param config Oauth Server configuration\n */\nexport async function resolveOAuthAccessCode(\n code: string,\n state: string,\n storage: CookieStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const authSessionService = await ServerAuthenticationResolver.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return authSessionService.tokenExchange(code, state);\n}\n\nexport async function isLoggedIn(storage: AuthStorage): Promise<boolean> {\n return !!(await storage.get(\"id_token\"));\n}\n\nexport async function buildLoginUrl(\n config: Pick<AuthConfig, \"clientId\" | \"redirectUrl\"> &\n Partial<Pick<AuthConfig, \"oauthServer\" | \"pkce\" | \"clientSecret\">> & {\n scopes?: string[];\n state?: string;\n nonce?: string;\n framework?: FrameworkType;\n sdkVersion?: string;\n },\n storage?: AuthStorage,\n): Promise<URL> {\n // Generate state: prioritize provided state (which preserves frontend display mode)\n let state: string;\n if (config.state) {\n // Use the provided state (e.g., from frontend with display mode info)\n state = config.state;\n } else if (config.sdkVersion || config.framework) {\n // Generate new structured state with framework/SDK info\n state = generateState({\n framework: config.framework,\n sdkVersion: config.sdkVersion,\n });\n } else {\n // Generate random state as fallback\n state = Math.random().toString(36).substring(2);\n }\n\n const scopes = config.scopes ?? DEFAULT_SCOPES;\n\n // Determine if PKCE should be used based on config\n // Default to true for backward compatibility if not specified\n const usePkce = config.pkce !== false;\n\n // Only create PKCE producer if we're using PKCE and have storage\n const pkceProducer =\n usePkce && storage ? new GenericPublicClientPKCEProducer(storage) : null;\n\n // Ensure clientId is present for OAuth operations\n if (!config.clientId) {\n throw new Error(\"clientId is required for OAuth login operations\");\n }\n\n const authInitiator = new GenericAuthenticationInitiator({\n ...config,\n clientId: config.clientId,\n state,\n scopes,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session\n // For confidential clients not using PKCE, this will be undefined\n pkceConsumer: pkceProducer ?? undefined,\n });\n\n return authInitiator.signIn();\n}\n"]}
|
package/dist/server/session.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type OAuthTokens, type User, type EmptyObject, type UnknownObject, type OIDCTokenResponseBody } from "../types.js";
|
|
2
2
|
import type { AuthConfig } from "../server/config.js";
|
|
3
3
|
import type { AuthenticationResolver } from "../services/types.js";
|
|
4
|
+
import type { CookieStorage } from "./index.js";
|
|
4
5
|
export type UrlDetectionRequest = {
|
|
5
6
|
url: string;
|
|
6
7
|
headers: Record<string, string | string[] | undefined>;
|
|
@@ -34,10 +35,10 @@ export type HandleCallbackParams = {
|
|
|
34
35
|
* It provides a unified interface to all the authentication functions.
|
|
35
36
|
*/
|
|
36
37
|
export declare class CivicAuth {
|
|
37
|
-
readonly storage:
|
|
38
|
+
readonly storage: CookieStorage;
|
|
38
39
|
readonly authConfig: AuthConfig;
|
|
39
40
|
_authResolver: AuthenticationResolver | null;
|
|
40
|
-
constructor(storage:
|
|
41
|
+
constructor(storage: CookieStorage, authConfig: AuthConfig);
|
|
41
42
|
get oauthServer(): string;
|
|
42
43
|
getAuthResolver(): Promise<AuthenticationResolver>;
|
|
43
44
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type AuthStorage,\n type OAuthTokens,\n type User,\n type EmptyObject,\n type UnknownObject,\n type OIDCTokenResponseBody,\n tokenKeys,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport {\n getUser as getUserFromShared,\n getTokens as getTokensFromShared,\n} from \"@/shared/lib/session.js\";\nimport { clearTokens as clearTokensUtil } from \"@/shared/lib/util.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { buildLoginUrl } from \"@/server/login.js\";\nimport { buildLogoutRedirectUrl } from \"@/server/logout.js\";\nimport {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { refreshTokens } from \"@/server/refresh.js\";\nimport { getVersion } from \"@/shared/index.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport {\n DEFAULT_AUTH_SERVER,\n JWT_PAYLOAD_KNOWN_CLAIM_KEYS,\n} from \"@/constants.js\";\nimport type { AuthenticationResolver } from \"@/services/types.js\";\nimport { displayModeFromState, loginSuccessUrlFromState } from \"@/lib/oauth.js\";\nimport { decodeJwt, type JWTPayload } from \"jose\";\nimport { generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { getBackendEndpoints, resolveEndpointUrl } from \"@/shared/lib/util.js\";\n\n// Generic request interface for framework-agnostic URL detection\nexport type UrlDetectionRequest = {\n url: string;\n headers: Record<string, string | string[] | undefined>;\n searchParams: {\n get(name: string): string | null;\n };\n cookies: {\n get(name: string): { value: string } | undefined;\n };\n};\n\nexport type HandleCallbackRequest = {\n headers: {\n [key: string]: string | string[] | undefined;\n referer?: string;\n origin?: string;\n \"user-agent\"?: string;\n accept?: string;\n \"sec-fetch-dest\"?: string;\n };\n url?: string;\n};\n\nexport type HandleCallbackParams = {\n code: string;\n state: string;\n req: HandleCallbackRequest;\n};\n\n// Function to omit keys from an object\nconst omitKeys = <K extends keyof T, T extends Record<string, unknown>>(\n keys: K[],\n obj: T,\n): Omit<T, K> => {\n const result = { ...obj };\n keys.forEach((key) => {\n delete result[key];\n });\n return result;\n};\n\n/**\n * Helper to detect if this is a same-domain callback request (for iframe workaround)\n */\nconst isSameDomainCallback = (req: HandleCallbackRequest): boolean => {\n if (!req.url) return false;\n return req.url.includes(\"sameDomainCallback=true\");\n};\n\n/**\n * Extract user information directly from OIDC tokens\n * @param tokens The OIDC tokens response\n * @returns The user object or null if no valid ID token\n */\nfunction getUserFromTokens<T extends UnknownObject = EmptyObject>(\n tokens: OIDCTokenResponseBody,\n): User<T> | null {\n if (!tokens.id_token) return null;\n\n const parsedToken = decodeJwt(tokens.id_token) as JWTPayload & T;\n if (!parsedToken.sub) return null;\n\n // set the user ID from the token sub\n const userWithAdditionalTokenFields = {\n ...(parsedToken as T),\n id: parsedToken.sub,\n };\n\n // Remove the token keys from the user object to stop it getting too large\n return omitKeys(\n [...JWT_PAYLOAD_KNOWN_CLAIM_KEYS, ...tokenKeys],\n userWithAdditionalTokenFields,\n ) as User<T>;\n}\n\n/**\n * CivicAuth is the main entry point for server-side authentication operations.\n * It provides a unified interface to all the authentication functions.\n */\nexport class CivicAuth {\n _authResolver: AuthenticationResolver | null = null;\n constructor(\n readonly storage: AuthStorage,\n readonly authConfig: AuthConfig,\n ) {}\n\n get oauthServer(): string {\n return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async getAuthResolver(): Promise<AuthenticationResolver> {\n if (this._authResolver) {\n return Promise.resolve(this._authResolver);\n }\n this._authResolver = await ServerAuthenticationResolver.build(\n {\n ...this.authConfig,\n oauthServer: this.oauthServer,\n },\n this.storage,\n );\n return this._authResolver;\n }\n /**\n * Gets the authenticated user with token validation\n * @returns The user object if authenticated, null otherwise\n */\n async getUser<\n T extends UnknownObject = EmptyObject,\n >(): Promise<User<T> | null> {\n const resolver = await this.getAuthResolver();\n\n try {\n // Validate the session before returning the user\n const session = await resolver.validateExistingSession();\n if (!session?.authenticated) {\n return null;\n }\n\n // If session is valid, use the shared implementation to get the user\n return getUserFromShared<T>(this.storage);\n } catch (error) {\n console.error(\"Token validation failed during getUser\", error);\n return null;\n }\n }\n\n /**\n * Gets the authentication tokens with token validation\n * @returns The tokens if authenticated, null otherwise\n */\n async getTokens(): Promise<OAuthTokens | null> {\n const resolver = await this.getAuthResolver();\n\n try {\n // Validate the session before returning the tokens\n const session = await resolver.validateExistingSession();\n\n if (!session?.authenticated) {\n return null;\n }\n\n // If session is valid, use the shared implementation to get the tokens\n const tokens = await getTokensFromShared(this.storage);\n return tokens;\n } catch (error) {\n console.error(\"❌ Token validation failed during getTokens\", error);\n return null;\n }\n }\n\n /**\n * Resolve an OAuth access code to a set of OIDC tokens\n * @param code The access code from the query parameter\n * @param state The OAuth state parameter\n * @returns OIDC tokens\n */\n async resolveOAuthAccessCode(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n return resolveOAuthAccessCode(code, state, this.storage, this.authConfig);\n }\n\n /**\n * Check if the user is currently logged in\n * @returns true if logged in, false otherwise\n */\n async isLoggedIn(): Promise<boolean> {\n const resolver = await this.getAuthResolver();\n const session = await resolver.validateExistingSession();\n return session?.authenticated ?? false;\n }\n\n /**\n * Build a login URL to redirect the user to\n * @param options Additional options for building the login URL\n * @returns The login URL\n */\n async buildLoginUrl(options?: {\n scopes?: string[];\n state?: string;\n nonce?: string;\n }): Promise<URL> {\n return buildLoginUrl(\n {\n ...this.authConfig,\n scopes: options?.scopes,\n state: options?.state,\n nonce: options?.nonce,\n framework: \"server\",\n sdkVersion: getVersion(),\n },\n this.storage,\n );\n }\n\n /**\n * Build a logout URL to redirect the user to\n * @param options Additional options for building the logout URL\n * @returns The logout URL\n */\n async buildLogoutRedirectUrl(options?: {\n scopes?: string[];\n state?: string;\n }): Promise<URL> {\n // Check if this is backend integration mode (loginUrl provided)\n if (this.authConfig.loginUrl) {\n // Backend integration mode: redirect to backend logout endpoint\n // This matches the vanilla client's logout logic for backend integration\n const backendUrl = new URL(this.authConfig.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.authConfig.backendEndpoints);\n const backendLogoutUrl = resolveEndpointUrl(backendUrl, endpoints.logout);\n\n const logoutUrl = new URL(backendLogoutUrl);\n\n // Include logoutRedirectUrl as query parameter if configured\n if (this.authConfig.postLogoutRedirectUrl) {\n logoutUrl.searchParams.set(\n \"logoutRedirectUrl\",\n this.authConfig.postLogoutRedirectUrl,\n );\n }\n\n // Include state if provided\n if (options?.state) {\n logoutUrl.searchParams.set(\"state\", options.state);\n }\n\n return logoutUrl;\n }\n\n // Standard OAuth flow - redirect to OAuth provider's logout endpoint\n try {\n // Use the shared getTokens function directly - this bypasses session validation\n // since for logout we just need the raw ID token, not validated tokens\n const tokens = await getTokensFromShared(this.storage);\n\n if (tokens?.idToken) {\n // Ensure clientId is present for OAuth operations\n if (!this.authConfig.clientId) {\n throw new Error(\"clientId is required for OAuth logout operations\");\n }\n\n // We have access to the ID token from HTTP-only cookies\n // Build the logout URL manually using the shared utility\n\n const logoutUrl = await generateOauthLogoutUrl({\n clientId: this.authConfig.clientId,\n redirectUrl: this.authConfig.postLogoutRedirectUrl || \"/\",\n idToken: tokens.idToken,\n state: options?.state ?? Math.random().toString(36).substring(2),\n oauthServer: this.oauthServer,\n });\n\n return logoutUrl;\n }\n } catch (error) {\n // If direct token access fails, fall back to the generic function\n console.warn(\n \"❌ Could not get tokens directly from storage, falling back to generic logout method:\",\n error,\n );\n }\n\n // Fallback to the generic function for other storage types or when tokens aren't accessible\n return buildLogoutRedirectUrl(\n {\n ...this.authConfig,\n scopes: options?.scopes,\n state: options?.state,\n },\n this.storage,\n );\n }\n\n /**\n * Refresh the current set of OIDC tokens\n * @returns The refreshed tokens or null for backend flows where tokens are managed in HTTP-only cookies\n */\n async refreshTokens(): Promise<OIDCTokenResponseBody | null> {\n return refreshTokens(this.storage, this.authConfig);\n }\n\n /**\n * Clear all authentication tokens from storage\n */\n async clearTokens(): Promise<void> {\n return clearTokensUtil(this.storage);\n }\n\n /**\n * Framework-agnostic URL detection and resolution helpers\n * These methods handle proxy environments and can be used by any framework\n */\n\n /**\n * Try to URI decode a value, returning the original value on error\n */\n static tryUriDecode(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch (e) {\n console.error(\"Error decoding URI component:\", e);\n return value;\n }\n }\n\n /**\n * Get decoded query parameter from request\n */\n static getDecodedQueryParam(\n request: UrlDetectionRequest,\n paramName: string,\n ): string | null {\n const queryParam = request.searchParams.get(paramName);\n if (queryParam) {\n return CivicAuth.tryUriDecode(queryParam);\n }\n return null;\n }\n\n /**\n * Get value from cookie or query parameter (cookie takes precedence)\n */\n static getCookieOrQueryParam(\n request: UrlDetectionRequest,\n cookieName: string,\n queryName: string,\n ): string | null {\n // First check the cookie as it might have the full path with base directory\n const cookieValue = request.cookies.get(cookieName)?.value;\n if (cookieValue) {\n return CivicAuth.tryUriDecode(cookieValue);\n }\n\n // Fallback to query parameter\n return CivicAuth.getDecodedQueryParam(request, queryName);\n }\n\n /**\n * Get app URL from request (for proxy environment support)\n * Checks cookies first, then query parameters\n */\n static getAppUrl(request: UrlDetectionRequest): string | null {\n return CivicAuth.getCookieOrQueryParam(\n request,\n CodeVerifier.APP_URL,\n \"appUrl\",\n );\n }\n\n /**\n * Get login success URL with proper base URL handling\n * Extracts from state parameter or query parameters, resolves with baseUrl if provided\n */\n static getLoginSuccessUrl(\n request: UrlDetectionRequest,\n baseUrl?: string | null,\n ): string | null {\n const state = request.searchParams.get(\"state\");\n const loginSuccessUrl =\n loginSuccessUrlFromState(state) ||\n CivicAuth.getDecodedQueryParam(request, \"loginSuccessUrl\");\n\n if (!loginSuccessUrl) {\n return null;\n }\n\n return baseUrl ? new URL(loginSuccessUrl, baseUrl).href : loginSuccessUrl;\n }\n\n /**\n * Convert relative URL to absolute URL using appUrl for proxy environments\n */\n static toAbsoluteUrl(\n request: UrlDetectionRequest,\n url: string,\n appUrl?: string | null,\n ): string {\n if (url.startsWith(\"http\")) {\n return url;\n }\n\n // Use appUrl if available (for proxy environments), otherwise fall back to request origin\n const baseUrl = appUrl || new URL(request.url).origin;\n return new URL(url, baseUrl).href;\n }\n\n /**\n * Get post-logout redirect URL with proxy environment support\n */\n getPostLogoutRedirectUrl(request: UrlDetectionRequest): string {\n // Check if we have a target URL in the request (from middleware)\n const targetUrl = request.searchParams.get(\"targetUrl\");\n if (targetUrl) {\n return targetUrl;\n }\n\n const redirectTarget = this.authConfig.loginSuccessUrl ?? \"/\";\n\n // If loginSuccessUrl is absolute, use it as-is\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n if (isAbsoluteRedirect) {\n return redirectTarget;\n }\n\n // Use appUrl from client for proxy environments\n const appUrl = CivicAuth.getAppUrl(request);\n if (appUrl) {\n return new URL(redirectTarget, appUrl).href;\n }\n\n // Fallback to request origin\n return new URL(request.url).origin;\n }\n\n /**\n * Smart callback handler that automatically detects frontend vs backend requests\n * and redirects appropriately. Use this instead of resolveOAuthAccessCode + manual redirect.\n *\n * @param params An object containing the authorization code, state, and the incoming request.\n * @param params.code The authorization code from query parameters.\n * @param params.state The OAuth state parameter.\n * @param params.req The incoming request object (e.g., from Express).\n * @param options Configuration options (frontendUrl override, apiResponse flag).\n * @returns Object with redirect information or HTML content for iframe completion.\n *\n * @example\n * ```javascript\n * app.get('/auth/callback', async (req, res) => {\n * const { code, state } = req.query;\n * // The request object 'req' is passed directly\n * const result = await req.civicAuth.handleCallback({ code, state, req });\n *\n * if (result.htmlContent) {\n * res.setHeader('Content-Type', 'text/html');\n * res.send(result.htmlContent);\n * } else if (result.redirectTo) {\n * res.redirect(result.redirectTo);\n * } else {\n * res.json({ success: true, user: result.user });\n * }\n * });\n * ```\n */\n async handleCallback(\n { code, state, req }: HandleCallbackParams,\n options?: {\n frontendUrl?: string;\n apiResponse?: boolean;\n },\n ): Promise<{\n redirectTo?: string;\n content?: string | { success: boolean; user?: User | null };\n }> {\n // Handle same-domain callback for iframe workaround\n if (isSameDomainCallback(req)) {\n try {\n // Check if user is already authenticated before attempting token exchange\n const isAlreadyLoggedIn = await this.isLoggedIn();\n let user: User | null = null;\n\n if (isAlreadyLoggedIn) {\n // User is already authenticated, get existing user data\n user = await this.getUser();\n console.log(\n \"User already authenticated in same-domain callback:\",\n !!user,\n );\n } else {\n // For same-domain callbacks, we should have access to cookies\n const tokens = await this.resolveOAuthAccessCode(code, state);\n user = getUserFromTokens(tokens);\n console.log(\n \"Completed token exchange in same-domain callback:\",\n !!user,\n );\n }\n\n // Return JSON response for same-domain callback\n const currentUrl = new URL(req.url || \"\");\n const newSearchParams = new URLSearchParams(currentUrl.search);\n newSearchParams.delete(\"sameDomainCallback\");\n newSearchParams.delete(\"appUrl\");\n newSearchParams.delete(\"loginSuccessUrl\");\n\n const redirectUrl = `${currentUrl.pathname}?${newSearchParams.toString()}${currentUrl.hash}`;\n return {\n content: {\n success: true,\n redirectUrl,\n } as { success: boolean; redirectUrl: string },\n };\n } catch (error) {\n console.error(\"Same-domain callback failed:\", error);\n throw error;\n }\n }\n\n // Try to resolve the OAuth code and create session\n let tokens: OIDCTokenResponseBody;\n let user: User | null;\n\n try {\n tokens = await this.resolveOAuthAccessCode(code, state);\n user = getUserFromTokens(tokens);\n } catch (error) {\n // Check if this is a code verifier error and we're in iframe mode\n const isCodeVerifierError =\n error instanceof Error &&\n error.message.includes(\"Code verifier not found in storage\");\n\n if (isCodeVerifierError) {\n // First check if user is already authenticated before trying iframe workaround\n try {\n const isAlreadyLoggedIn = await this.isLoggedIn();\n\n if (isAlreadyLoggedIn) {\n // \"User already authenticated, skipping iframe workaround\",\n const user = await this.getUser();\n const loginSuccessUrlFromStateValue =\n loginSuccessUrlFromState(state);\n const frontendUrl =\n options?.frontendUrl ||\n loginSuccessUrlFromStateValue ||\n this.authConfig.loginSuccessUrl;\n\n // Check if this is an iframe context - if so, generate iframe completion HTML\n const stateDisplayMode = displayModeFromState(state, undefined);\n const isConfiguredForIframe = stateDisplayMode === \"iframe\";\n\n if (\n isConfiguredForIframe &&\n !this.authConfig.disableIframeDetection &&\n user &&\n frontendUrl\n ) {\n // Generating iframe completion HTML for already authenticated user\",\n const completionHtml = this.generateIframeCompletionHtml(\n user,\n frontendUrl,\n );\n return { content: completionHtml };\n }\n\n if (frontendUrl) {\n return { redirectTo: frontendUrl };\n } else {\n return { content: { success: true, user } };\n }\n }\n } catch (authCheckError) {\n console.warn(\n \"Failed to check authentication status:\",\n authCheckError,\n );\n // Continue with iframe workaround if auth check fails\n }\n\n const stateDisplayMode = displayModeFromState(state, undefined);\n const isConfiguredForIframe = stateDisplayMode === \"iframe\";\n\n if (isConfiguredForIframe && !this.authConfig.disableIframeDetection) {\n // Generate HTML that will trigger same-domain callback\n const loginSuccessUrlFromStateValue = loginSuccessUrlFromState(state);\n const frontendUrl =\n options?.frontendUrl ||\n loginSuccessUrlFromStateValue ||\n this.authConfig.loginSuccessUrl;\n\n const callbackUrl = req.url || \"\";\n const sameDomainHtml = this.generateSameDomainCallbackHtml(\n callbackUrl,\n frontendUrl,\n );\n return { content: sameDomainHtml };\n }\n\n // For non-iframe mode or when iframe detection is disabled, return trigger text\n return {\n content: `<html lang=\"en\"><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n };\n }\n\n // Re-throw other errors\n throw error;\n }\n\n // Extract loginSuccessUrl from state if present\n const loginSuccessUrlFromStateValue = loginSuccessUrlFromState(state);\n\n // Priority: options.frontendUrl > loginSuccessUrl from state > config loginSuccessUrl\n const frontendUrl =\n options?.frontendUrl ||\n loginSuccessUrlFromStateValue ||\n this.authConfig.loginSuccessUrl;\n\n // Priority 1: Check state for display mode configuration\n const stateDisplayMode = displayModeFromState(state, undefined);\n const isConfiguredForIframe = stateDisplayMode === \"iframe\";\n\n // Determine if this should be treated as an iframe request\n // Configuration (from state) takes precedence over auto-detection\n const shouldTreatAsIframe =\n isConfiguredForIframe && !this.authConfig.disableIframeDetection;\n\n const isTopLevelRedirect = req.headers[\"sec-fetch-dest\"] === \"document\";\n const isIframeRequest = req.headers[\"sec-fetch-dest\"] === \"iframe\";\n const isApiRequest =\n options?.apiResponse || req.headers.accept?.includes(\"application/json\");\n\n // Detect Safari or other browsers where iframe postMessage may fail due to cross-origin restrictions\n //TODO: Find a better way to detect this\n const userAgent = req.headers[\"user-agent\"] || \"\";\n const isSafari =\n userAgent.includes(\"Safari\") && !userAgent.includes(\"Chrome\");\n const isLikelyCrossOriginIframe =\n isSafari ||\n (userAgent.includes(\"WebKit\") && !userAgent.includes(\"Chrome\"));\n\n // Case 1: The request should be treated as iframe. Return HTML content.\n // Unless iframe detection is disabled via configuration OR we detect cross-origin issues\n if (\n shouldTreatAsIframe &&\n user &&\n frontendUrl &&\n !isLikelyCrossOriginIframe\n ) {\n const completionHtml = this.generateIframeCompletionHtml(\n user,\n frontendUrl,\n );\n return { content: completionHtml };\n }\n\n // Case 1b: Safari/cross-origin iframe case - redirect instead of HTML\n if (\n shouldTreatAsIframe &&\n user &&\n frontendUrl &&\n isLikelyCrossOriginIframe\n ) {\n return { redirectTo: frontendUrl };\n }\n\n // Case 2: The request is a top-level navigation. Return redirect URL.\n if (isTopLevelRedirect && frontendUrl) {\n return { redirectTo: frontendUrl };\n }\n\n // Case 2a: The request is from an iframe (detected by sec-fetch-dest)\n // Even if not configured for iframe in state, we should still generate iframe completion HTML\n if (isIframeRequest && user && frontendUrl) {\n if (isLikelyCrossOriginIframe) {\n console.log(\n \"Iframe request detected but cross-origin issues likely - redirecting\",\n );\n return { redirectTo: frontendUrl };\n } else {\n console.log(\n \"Generating iframe completion HTML for iframe request (detected by sec-fetch-dest)\",\n );\n const completionHtml = this.generateIframeCompletionHtml(\n user,\n frontendUrl,\n );\n return { content: completionHtml };\n }\n }\n\n // Case 3: The request is an API call. Return JSON content.\n if (isApiRequest) {\n return {\n content: {\n success: true,\n user,\n },\n };\n }\n\n // Fallback for older browsers or other contexts: if a frontend URL is configured,\n // assume a redirect to it.\n if (frontendUrl) {\n return { redirectTo: frontendUrl };\n }\n\n // Server-side fallback: if no frontend URL is configured but we have a postLogoutRedirectUrl,\n // redirect there instead of returning JSON content\n if (this.authConfig.postLogoutRedirectUrl) {\n return { redirectTo: this.authConfig.postLogoutRedirectUrl };\n }\n\n // Absolute fallback: return success as JSON content if no other conditions are met.\n // This could happen if no loginSuccessUrl or postLogoutRedirectUrl is configured.\n return {\n content: {\n success: true,\n user,\n },\n };\n }\n\n /**\n * Generate HTML content for iframe completion that sends postMessage to parent\n */\n private generateIframeCompletionHtml(\n user: User,\n frontendUrl?: string,\n ): string {\n const escapedUser = JSON.stringify(user).replace(/'/g, \"\\\\'\");\n const clientId = this.authConfig.clientId;\n\n // Determine fallback redirect URL\n const fallbackUrl =\n frontendUrl ||\n this.authConfig.redirectUrl ||\n this.authConfig.postLogoutRedirectUrl ||\n \"/\";\n\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>Authentication Complete</title>\n <meta charset=\"utf-8\">\n </head>\n <body> \n <!-- Success signal for SignalObserver -->\n <div id=\"civic-auth-success-signal\" style=\"display: none;\" data-user-info='${escapedUser}'>\n ${TOKEN_EXCHANGE_SUCCESS_TEXT}\n </div>\n \n <script> \n // Send postMessage to parent to resolve authentication promise\n if (window.parent && window.parent !== window) {\n try {\n window.parent.postMessage({\n type: 'auth_success',\n detail: 'Authentication successful',\n data: {\n user: ${escapedUser}\n }\n }, '*');\n } catch (error) {\n console.error('❌ Failed to send postMessage:', error);\n }\n \n // Also send civicloginApp format message for compatibility\n try {\n window.parent.postMessage({\n source: 'civicloginApp',\n type: 'auth_success',\n clientId: '${clientId}',\n data: {\n user: ${escapedUser}\n }\n }, '*');\n } catch (error) {\n console.error('❌ Failed to send civicloginApp message:', error);\n }\n } else {\n console.log('❌ Not in iframe context or no parent window');\n }\n \n // Fallback redirect after 500ms delay to handle cases where:\n // 1. postMessage fails or parent doesn't respond\n // 2. Not in iframe context\n // 3. Any other edge cases where the user gets stuck\n setTimeout(function() {\n console.log('🔄 Executing fallback redirect to: ${fallbackUrl}');\n window.location.href = '${fallbackUrl}';\n }, 500);\n </script>\n </body>\n </html>\n `;\n }\n\n /**\n * Generate HTML response that triggers same-domain callback for iframe workaround\n */\n private generateSameDomainCallbackHtml = (\n callbackUrl: string,\n frontendUrl?: string,\n ): string => {\n const loginSuccessSegment = frontendUrl\n ? `&loginSuccessUrl=${encodeURIComponent(frontendUrl)}`\n : \"\";\n\n return `<html lang=\"en\">\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n // Get the complete URL including origin and path\n // This ensures we capture any base path like /directory\n const appUrl = window.location.href.substring(\n 0,\n window.location.href.indexOf(\"/api/auth\")\n );\n fetch('${callbackUrl}&sameDomainCallback=true&appUrl=' + encodeURIComponent(appUrl) + '${loginSuccessSegment}').then((response) => {\n response.json().then((jsonResponse) => {\n // For login: Redirect back to the callback route, so Case 2 in handleTokenExchangeComplete will be triggered\n // For logout: Redirect to the postLogoutRedirectUrl\n if(jsonResponse.redirectUrl) {\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n</html>\n`;\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n type OAuthTokens,\n type User,\n type EmptyObject,\n type UnknownObject,\n type OIDCTokenResponseBody,\n tokenKeys,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport {\n getUser as getUserFromShared,\n getTokens as getTokensFromShared,\n} from \"@/shared/lib/session.js\";\nimport { clearTokens as clearTokensUtil } from \"@/shared/lib/util.js\";\nimport { resolveOAuthAccessCode } from \"@/server/login.js\";\nimport { buildLoginUrl } from \"@/server/login.js\";\nimport { buildLogoutRedirectUrl } from \"@/server/logout.js\";\nimport {\n TOKEN_EXCHANGE_SUCCESS_TEXT,\n TOKEN_EXCHANGE_TRIGGER_TEXT,\n} from \"@/constants.js\";\nimport { refreshTokens } from \"@/server/refresh.js\";\nimport { getVersion } from \"@/shared/index.js\";\nimport { ServerAuthenticationResolver } from \"@/server/ServerAuthenticationResolver.js\";\nimport {\n DEFAULT_AUTH_SERVER,\n JWT_PAYLOAD_KNOWN_CLAIM_KEYS,\n} from \"@/constants.js\";\nimport type { AuthenticationResolver } from \"@/services/types.js\";\nimport { displayModeFromState, loginSuccessUrlFromState } from \"@/lib/oauth.js\";\nimport { decodeJwt, type JWTPayload } from \"jose\";\nimport { generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { getBackendEndpoints, resolveEndpointUrl } from \"@/shared/lib/util.js\";\nimport type { CookieStorage } from \"./index.js\";\n\n// Generic request interface for framework-agnostic URL detection\nexport type UrlDetectionRequest = {\n url: string;\n headers: Record<string, string | string[] | undefined>;\n searchParams: {\n get(name: string): string | null;\n };\n cookies: {\n get(name: string): { value: string } | undefined;\n };\n};\n\nexport type HandleCallbackRequest = {\n headers: {\n [key: string]: string | string[] | undefined;\n referer?: string;\n origin?: string;\n \"user-agent\"?: string;\n accept?: string;\n \"sec-fetch-dest\"?: string;\n };\n url?: string;\n};\n\nexport type HandleCallbackParams = {\n code: string;\n state: string;\n req: HandleCallbackRequest;\n};\n\n// Function to omit keys from an object\nconst omitKeys = <K extends keyof T, T extends Record<string, unknown>>(\n keys: K[],\n obj: T,\n): Omit<T, K> => {\n const result = { ...obj };\n keys.forEach((key) => {\n delete result[key];\n });\n return result;\n};\n\n/**\n * Helper to detect if this is a same-domain callback request (for iframe workaround)\n */\nconst isSameDomainCallback = (req: HandleCallbackRequest): boolean => {\n if (!req.url) return false;\n return req.url.includes(\"sameDomainCallback=true\");\n};\n\n/**\n * Extract user information directly from OIDC tokens\n * @param tokens The OIDC tokens response\n * @returns The user object or null if no valid ID token\n */\nfunction getUserFromTokens<T extends UnknownObject = EmptyObject>(\n tokens: OIDCTokenResponseBody,\n): User<T> | null {\n if (!tokens.id_token) return null;\n\n const parsedToken = decodeJwt(tokens.id_token) as JWTPayload & T;\n if (!parsedToken.sub) return null;\n\n // set the user ID from the token sub\n const userWithAdditionalTokenFields = {\n ...(parsedToken as T),\n id: parsedToken.sub,\n };\n\n // Remove the token keys from the user object to stop it getting too large\n return omitKeys(\n [...JWT_PAYLOAD_KNOWN_CLAIM_KEYS, ...tokenKeys],\n userWithAdditionalTokenFields,\n ) as User<T>;\n}\n\n/**\n * CivicAuth is the main entry point for server-side authentication operations.\n * It provides a unified interface to all the authentication functions.\n */\nexport class CivicAuth {\n _authResolver: AuthenticationResolver | null = null;\n constructor(\n readonly storage: CookieStorage,\n readonly authConfig: AuthConfig,\n ) {}\n\n get oauthServer(): string {\n return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async getAuthResolver(): Promise<AuthenticationResolver> {\n if (this._authResolver) {\n return Promise.resolve(this._authResolver);\n }\n this._authResolver = await ServerAuthenticationResolver.build(\n {\n ...this.authConfig,\n oauthServer: this.oauthServer,\n },\n this.storage,\n );\n return this._authResolver;\n }\n /**\n * Gets the authenticated user with token validation\n * @returns The user object if authenticated, null otherwise\n */\n async getUser<\n T extends UnknownObject = EmptyObject,\n >(): Promise<User<T> | null> {\n const resolver = await this.getAuthResolver();\n\n try {\n // Validate the session before returning the user\n const session = await resolver.validateExistingSession();\n if (!session?.authenticated) {\n return null;\n }\n\n // If session is valid, use the shared implementation to get the user\n return getUserFromShared<T>(this.storage);\n } catch (error) {\n console.error(\"Token validation failed during getUser\", error);\n return null;\n }\n }\n\n /**\n * Gets the authentication tokens with token validation\n * @returns The tokens if authenticated, null otherwise\n */\n async getTokens(): Promise<OAuthTokens | null> {\n const resolver = await this.getAuthResolver();\n\n try {\n // Validate the session before returning the tokens\n const session = await resolver.validateExistingSession();\n\n if (!session?.authenticated) {\n return null;\n }\n\n // If session is valid, use the shared implementation to get the tokens\n const tokens = await getTokensFromShared(this.storage);\n return tokens;\n } catch (error) {\n console.error(\"❌ Token validation failed during getTokens\", error);\n return null;\n }\n }\n\n /**\n * Resolve an OAuth access code to a set of OIDC tokens\n * @param code The access code from the query parameter\n * @param state The OAuth state parameter\n * @returns OIDC tokens\n */\n async resolveOAuthAccessCode(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n return resolveOAuthAccessCode(code, state, this.storage, this.authConfig);\n }\n\n /**\n * Check if the user is currently logged in\n * @returns true if logged in, false otherwise\n */\n async isLoggedIn(): Promise<boolean> {\n const resolver = await this.getAuthResolver();\n const session = await resolver.validateExistingSession();\n return session?.authenticated ?? false;\n }\n\n /**\n * Build a login URL to redirect the user to\n * @param options Additional options for building the login URL\n * @returns The login URL\n */\n async buildLoginUrl(options?: {\n scopes?: string[];\n state?: string;\n nonce?: string;\n }): Promise<URL> {\n return buildLoginUrl(\n {\n ...this.authConfig,\n scopes: options?.scopes,\n state: options?.state,\n nonce: options?.nonce,\n framework: \"server\",\n sdkVersion: getVersion(),\n },\n this.storage,\n );\n }\n\n /**\n * Build a logout URL to redirect the user to\n * @param options Additional options for building the logout URL\n * @returns The logout URL\n */\n async buildLogoutRedirectUrl(options?: {\n scopes?: string[];\n state?: string;\n }): Promise<URL> {\n // Check if this is backend integration mode (loginUrl provided)\n if (this.authConfig.loginUrl) {\n // Backend integration mode: redirect to backend logout endpoint\n // This matches the vanilla client's logout logic for backend integration\n const backendUrl = new URL(this.authConfig.loginUrl).origin;\n const endpoints = getBackendEndpoints(this.authConfig.backendEndpoints);\n const backendLogoutUrl = resolveEndpointUrl(backendUrl, endpoints.logout);\n\n const logoutUrl = new URL(backendLogoutUrl);\n\n // Include logoutRedirectUrl as query parameter if configured\n if (this.authConfig.postLogoutRedirectUrl) {\n logoutUrl.searchParams.set(\n \"logoutRedirectUrl\",\n this.authConfig.postLogoutRedirectUrl,\n );\n }\n\n // Include state if provided\n if (options?.state) {\n logoutUrl.searchParams.set(\"state\", options.state);\n }\n\n return logoutUrl;\n }\n\n // Standard OAuth flow - redirect to OAuth provider's logout endpoint\n try {\n // Use the shared getTokens function directly - this bypasses session validation\n // since for logout we just need the raw ID token, not validated tokens\n const tokens = await getTokensFromShared(this.storage);\n\n if (tokens?.idToken) {\n // Ensure clientId is present for OAuth operations\n if (!this.authConfig.clientId) {\n throw new Error(\"clientId is required for OAuth logout operations\");\n }\n\n // We have access to the ID token from HTTP-only cookies\n // Build the logout URL manually using the shared utility\n\n const logoutUrl = await generateOauthLogoutUrl({\n clientId: this.authConfig.clientId,\n redirectUrl: this.authConfig.postLogoutRedirectUrl || \"/\",\n idToken: tokens.idToken,\n state: options?.state ?? Math.random().toString(36).substring(2),\n oauthServer: this.oauthServer,\n });\n\n return logoutUrl;\n }\n } catch (error) {\n // If direct token access fails, fall back to the generic function\n console.warn(\n \"❌ Could not get tokens directly from storage, falling back to generic logout method:\",\n error,\n );\n }\n\n // Fallback to the generic function for other storage types or when tokens aren't accessible\n return buildLogoutRedirectUrl(\n {\n ...this.authConfig,\n scopes: options?.scopes,\n state: options?.state,\n },\n this.storage,\n );\n }\n\n /**\n * Refresh the current set of OIDC tokens\n * @returns The refreshed tokens or null for backend flows where tokens are managed in HTTP-only cookies\n */\n async refreshTokens(): Promise<OIDCTokenResponseBody | null> {\n return refreshTokens(this.storage, this.authConfig);\n }\n\n /**\n * Clear all authentication tokens from storage\n */\n async clearTokens(): Promise<void> {\n return clearTokensUtil(this.storage);\n }\n\n /**\n * Framework-agnostic URL detection and resolution helpers\n * These methods handle proxy environments and can be used by any framework\n */\n\n /**\n * Try to URI decode a value, returning the original value on error\n */\n static tryUriDecode(value: string): string {\n try {\n return decodeURIComponent(value);\n } catch (e) {\n console.error(\"Error decoding URI component:\", e);\n return value;\n }\n }\n\n /**\n * Get decoded query parameter from request\n */\n static getDecodedQueryParam(\n request: UrlDetectionRequest,\n paramName: string,\n ): string | null {\n const queryParam = request.searchParams.get(paramName);\n if (queryParam) {\n return CivicAuth.tryUriDecode(queryParam);\n }\n return null;\n }\n\n /**\n * Get value from cookie or query parameter (cookie takes precedence)\n */\n static getCookieOrQueryParam(\n request: UrlDetectionRequest,\n cookieName: string,\n queryName: string,\n ): string | null {\n // First check the cookie as it might have the full path with base directory\n const cookieValue = request.cookies.get(cookieName)?.value;\n if (cookieValue) {\n return CivicAuth.tryUriDecode(cookieValue);\n }\n\n // Fallback to query parameter\n return CivicAuth.getDecodedQueryParam(request, queryName);\n }\n\n /**\n * Get app URL from request (for proxy environment support)\n * Checks cookies first, then query parameters\n */\n static getAppUrl(request: UrlDetectionRequest): string | null {\n return CivicAuth.getCookieOrQueryParam(\n request,\n CodeVerifier.APP_URL,\n \"appUrl\",\n );\n }\n\n /**\n * Get login success URL with proper base URL handling\n * Extracts from state parameter or query parameters, resolves with baseUrl if provided\n */\n static getLoginSuccessUrl(\n request: UrlDetectionRequest,\n baseUrl?: string | null,\n ): string | null {\n const state = request.searchParams.get(\"state\");\n const loginSuccessUrl =\n loginSuccessUrlFromState(state) ||\n CivicAuth.getDecodedQueryParam(request, \"loginSuccessUrl\");\n\n if (!loginSuccessUrl) {\n return null;\n }\n\n return baseUrl ? new URL(loginSuccessUrl, baseUrl).href : loginSuccessUrl;\n }\n\n /**\n * Convert relative URL to absolute URL using appUrl for proxy environments\n */\n static toAbsoluteUrl(\n request: UrlDetectionRequest,\n url: string,\n appUrl?: string | null,\n ): string {\n if (url.startsWith(\"http\")) {\n return url;\n }\n\n // Use appUrl if available (for proxy environments), otherwise fall back to request origin\n const baseUrl = appUrl || new URL(request.url).origin;\n return new URL(url, baseUrl).href;\n }\n\n /**\n * Get post-logout redirect URL with proxy environment support\n */\n getPostLogoutRedirectUrl(request: UrlDetectionRequest): string {\n // Check if we have a target URL in the request (from middleware)\n const targetUrl = request.searchParams.get(\"targetUrl\");\n if (targetUrl) {\n return targetUrl;\n }\n\n const redirectTarget = this.authConfig.loginSuccessUrl ?? \"/\";\n\n // If loginSuccessUrl is absolute, use it as-is\n const isAbsoluteRedirect = /^(https?:\\/\\/|www\\.).+/i.test(redirectTarget);\n if (isAbsoluteRedirect) {\n return redirectTarget;\n }\n\n // Use appUrl from client for proxy environments\n const appUrl = CivicAuth.getAppUrl(request);\n if (appUrl) {\n return new URL(redirectTarget, appUrl).href;\n }\n\n // Fallback to request origin\n return new URL(request.url).origin;\n }\n\n /**\n * Smart callback handler that automatically detects frontend vs backend requests\n * and redirects appropriately. Use this instead of resolveOAuthAccessCode + manual redirect.\n *\n * @param params An object containing the authorization code, state, and the incoming request.\n * @param params.code The authorization code from query parameters.\n * @param params.state The OAuth state parameter.\n * @param params.req The incoming request object (e.g., from Express).\n * @param options Configuration options (frontendUrl override, apiResponse flag).\n * @returns Object with redirect information or HTML content for iframe completion.\n *\n * @example\n * ```javascript\n * app.get('/auth/callback', async (req, res) => {\n * const { code, state } = req.query;\n * // The request object 'req' is passed directly\n * const result = await req.civicAuth.handleCallback({ code, state, req });\n *\n * if (result.htmlContent) {\n * res.setHeader('Content-Type', 'text/html');\n * res.send(result.htmlContent);\n * } else if (result.redirectTo) {\n * res.redirect(result.redirectTo);\n * } else {\n * res.json({ success: true, user: result.user });\n * }\n * });\n * ```\n */\n async handleCallback(\n { code, state, req }: HandleCallbackParams,\n options?: {\n frontendUrl?: string;\n apiResponse?: boolean;\n },\n ): Promise<{\n redirectTo?: string;\n content?: string | { success: boolean; user?: User | null };\n }> {\n // Handle same-domain callback for iframe workaround\n if (isSameDomainCallback(req)) {\n try {\n // Check if user is already authenticated before attempting token exchange\n const isAlreadyLoggedIn = await this.isLoggedIn();\n let user: User | null = null;\n\n if (isAlreadyLoggedIn) {\n // User is already authenticated, get existing user data\n user = await this.getUser();\n console.log(\n \"User already authenticated in same-domain callback:\",\n !!user,\n );\n } else {\n // For same-domain callbacks, we should have access to cookies\n const tokens = await this.resolveOAuthAccessCode(code, state);\n user = getUserFromTokens(tokens);\n console.log(\n \"Completed token exchange in same-domain callback:\",\n !!user,\n );\n }\n\n // Return JSON response for same-domain callback\n const currentUrl = new URL(req.url || \"\");\n const newSearchParams = new URLSearchParams(currentUrl.search);\n newSearchParams.delete(\"sameDomainCallback\");\n newSearchParams.delete(\"appUrl\");\n newSearchParams.delete(\"loginSuccessUrl\");\n\n const redirectUrl = `${currentUrl.pathname}?${newSearchParams.toString()}${currentUrl.hash}`;\n return {\n content: {\n success: true,\n redirectUrl,\n } as { success: boolean; redirectUrl: string },\n };\n } catch (error) {\n console.error(\"Same-domain callback failed:\", error);\n throw error;\n }\n }\n\n // Try to resolve the OAuth code and create session\n let tokens: OIDCTokenResponseBody;\n let user: User | null;\n\n try {\n tokens = await this.resolveOAuthAccessCode(code, state);\n user = getUserFromTokens(tokens);\n } catch (error) {\n // Check if this is a code verifier error and we're in iframe mode\n const isCodeVerifierError =\n error instanceof Error &&\n error.message.includes(\"Code verifier not found in storage\");\n\n if (isCodeVerifierError) {\n // First check if user is already authenticated before trying iframe workaround\n try {\n const isAlreadyLoggedIn = await this.isLoggedIn();\n\n if (isAlreadyLoggedIn) {\n // \"User already authenticated, skipping iframe workaround\",\n const user = await this.getUser();\n const loginSuccessUrlFromStateValue =\n loginSuccessUrlFromState(state);\n const frontendUrl =\n options?.frontendUrl ||\n loginSuccessUrlFromStateValue ||\n this.authConfig.loginSuccessUrl;\n\n // Check if this is an iframe context - if so, generate iframe completion HTML\n const stateDisplayMode = displayModeFromState(state, undefined);\n const isConfiguredForIframe = stateDisplayMode === \"iframe\";\n\n if (\n isConfiguredForIframe &&\n !this.authConfig.disableIframeDetection &&\n user &&\n frontendUrl\n ) {\n // Generating iframe completion HTML for already authenticated user\",\n const completionHtml = this.generateIframeCompletionHtml(\n user,\n frontendUrl,\n );\n return { content: completionHtml };\n }\n\n if (frontendUrl) {\n return { redirectTo: frontendUrl };\n } else {\n return { content: { success: true, user } };\n }\n }\n } catch (authCheckError) {\n console.warn(\n \"Failed to check authentication status:\",\n authCheckError,\n );\n // Continue with iframe workaround if auth check fails\n }\n\n const stateDisplayMode = displayModeFromState(state, undefined);\n const isConfiguredForIframe = stateDisplayMode === \"iframe\";\n\n if (isConfiguredForIframe && !this.authConfig.disableIframeDetection) {\n // Generate HTML that will trigger same-domain callback\n const loginSuccessUrlFromStateValue = loginSuccessUrlFromState(state);\n const frontendUrl =\n options?.frontendUrl ||\n loginSuccessUrlFromStateValue ||\n this.authConfig.loginSuccessUrl;\n\n const callbackUrl = req.url || \"\";\n const sameDomainHtml = this.generateSameDomainCallbackHtml(\n callbackUrl,\n frontendUrl,\n );\n return { content: sameDomainHtml };\n }\n\n // For non-iframe mode or when iframe detection is disabled, return trigger text\n return {\n content: `<html lang=\"en\"><body><span style=\"display:none\">${TOKEN_EXCHANGE_TRIGGER_TEXT}</span></body></html>`,\n };\n }\n\n // Re-throw other errors\n throw error;\n }\n\n // Extract loginSuccessUrl from state if present\n const loginSuccessUrlFromStateValue = loginSuccessUrlFromState(state);\n\n // Priority: options.frontendUrl > loginSuccessUrl from state > config loginSuccessUrl\n const frontendUrl =\n options?.frontendUrl ||\n loginSuccessUrlFromStateValue ||\n this.authConfig.loginSuccessUrl;\n\n // Priority 1: Check state for display mode configuration\n const stateDisplayMode = displayModeFromState(state, undefined);\n const isConfiguredForIframe = stateDisplayMode === \"iframe\";\n\n // Determine if this should be treated as an iframe request\n // Configuration (from state) takes precedence over auto-detection\n const shouldTreatAsIframe =\n isConfiguredForIframe && !this.authConfig.disableIframeDetection;\n\n const isTopLevelRedirect = req.headers[\"sec-fetch-dest\"] === \"document\";\n const isIframeRequest = req.headers[\"sec-fetch-dest\"] === \"iframe\";\n const isApiRequest =\n options?.apiResponse || req.headers.accept?.includes(\"application/json\");\n\n // Detect Safari or other browsers where iframe postMessage may fail due to cross-origin restrictions\n //TODO: Find a better way to detect this\n const userAgent = req.headers[\"user-agent\"] || \"\";\n const isSafari =\n userAgent.includes(\"Safari\") && !userAgent.includes(\"Chrome\");\n const isLikelyCrossOriginIframe =\n isSafari ||\n (userAgent.includes(\"WebKit\") && !userAgent.includes(\"Chrome\"));\n\n // Case 1: The request should be treated as iframe. Return HTML content.\n // Unless iframe detection is disabled via configuration OR we detect cross-origin issues\n if (\n shouldTreatAsIframe &&\n user &&\n frontendUrl &&\n !isLikelyCrossOriginIframe\n ) {\n const completionHtml = this.generateIframeCompletionHtml(\n user,\n frontendUrl,\n );\n return { content: completionHtml };\n }\n\n // Case 1b: Safari/cross-origin iframe case - redirect instead of HTML\n if (\n shouldTreatAsIframe &&\n user &&\n frontendUrl &&\n isLikelyCrossOriginIframe\n ) {\n return { redirectTo: frontendUrl };\n }\n\n // Case 2: The request is a top-level navigation. Return redirect URL.\n if (isTopLevelRedirect && frontendUrl) {\n return { redirectTo: frontendUrl };\n }\n\n // Case 2a: The request is from an iframe (detected by sec-fetch-dest)\n // Even if not configured for iframe in state, we should still generate iframe completion HTML\n if (isIframeRequest && user && frontendUrl) {\n if (isLikelyCrossOriginIframe) {\n console.log(\n \"Iframe request detected but cross-origin issues likely - redirecting\",\n );\n return { redirectTo: frontendUrl };\n } else {\n console.log(\n \"Generating iframe completion HTML for iframe request (detected by sec-fetch-dest)\",\n );\n const completionHtml = this.generateIframeCompletionHtml(\n user,\n frontendUrl,\n );\n return { content: completionHtml };\n }\n }\n\n // Case 3: The request is an API call. Return JSON content.\n if (isApiRequest) {\n return {\n content: {\n success: true,\n user,\n },\n };\n }\n\n // Fallback for older browsers or other contexts: if a frontend URL is configured,\n // assume a redirect to it.\n if (frontendUrl) {\n return { redirectTo: frontendUrl };\n }\n\n // Server-side fallback: if no frontend URL is configured but we have a postLogoutRedirectUrl,\n // redirect there instead of returning JSON content\n if (this.authConfig.postLogoutRedirectUrl) {\n return { redirectTo: this.authConfig.postLogoutRedirectUrl };\n }\n\n // Absolute fallback: return success as JSON content if no other conditions are met.\n // This could happen if no loginSuccessUrl or postLogoutRedirectUrl is configured.\n return {\n content: {\n success: true,\n user,\n },\n };\n }\n\n /**\n * Generate HTML content for iframe completion that sends postMessage to parent\n */\n private generateIframeCompletionHtml(\n user: User,\n frontendUrl?: string,\n ): string {\n const escapedUser = JSON.stringify(user).replace(/'/g, \"\\\\'\");\n const clientId = this.authConfig.clientId;\n\n // Determine fallback redirect URL\n const fallbackUrl =\n frontendUrl ||\n this.authConfig.redirectUrl ||\n this.authConfig.postLogoutRedirectUrl ||\n \"/\";\n\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <title>Authentication Complete</title>\n <meta charset=\"utf-8\">\n </head>\n <body> \n <!-- Success signal for SignalObserver -->\n <div id=\"civic-auth-success-signal\" style=\"display: none;\" data-user-info='${escapedUser}'>\n ${TOKEN_EXCHANGE_SUCCESS_TEXT}\n </div>\n \n <script> \n // Send postMessage to parent to resolve authentication promise\n if (window.parent && window.parent !== window) {\n try {\n window.parent.postMessage({\n type: 'auth_success',\n detail: 'Authentication successful',\n data: {\n user: ${escapedUser}\n }\n }, '*');\n } catch (error) {\n console.error('❌ Failed to send postMessage:', error);\n }\n \n // Also send civicloginApp format message for compatibility\n try {\n window.parent.postMessage({\n source: 'civicloginApp',\n type: 'auth_success',\n clientId: '${clientId}',\n data: {\n user: ${escapedUser}\n }\n }, '*');\n } catch (error) {\n console.error('❌ Failed to send civicloginApp message:', error);\n }\n } else {\n console.log('❌ Not in iframe context or no parent window');\n }\n \n // Fallback redirect after 500ms delay to handle cases where:\n // 1. postMessage fails or parent doesn't respond\n // 2. Not in iframe context\n // 3. Any other edge cases where the user gets stuck\n setTimeout(function() {\n console.log('🔄 Executing fallback redirect to: ${fallbackUrl}');\n window.location.href = '${fallbackUrl}';\n }, 500);\n </script>\n </body>\n </html>\n `;\n }\n\n /**\n * Generate HTML response that triggers same-domain callback for iframe workaround\n */\n private generateSameDomainCallbackHtml = (\n callbackUrl: string,\n frontendUrl?: string,\n ): string => {\n const loginSuccessSegment = frontendUrl\n ? `&loginSuccessUrl=${encodeURIComponent(frontendUrl)}`\n : \"\";\n\n return `<html lang=\"en\">\n <body>\n <span style=\"display:none\">\n <script>\n window.onload = function () {\n // Get the complete URL including origin and path\n // This ensures we capture any base path like /directory\n const appUrl = window.location.href.substring(\n 0,\n window.location.href.indexOf(\"/api/auth\")\n );\n fetch('${callbackUrl}&sameDomainCallback=true&appUrl=' + encodeURIComponent(appUrl) + '${loginSuccessSegment}').then((response) => {\n response.json().then((jsonResponse) => {\n // For login: Redirect back to the callback route, so Case 2 in handleTokenExchangeComplete will be triggered\n // For logout: Redirect to the postLogoutRedirectUrl\n if(jsonResponse.redirectUrl) {\n window.location.href = jsonResponse.redirectUrl;\n }\n });\n });\n };\n </script>\n </span>\n </body>\n</html>\n`;\n };\n}\n"]}
|
package/dist/server/users.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type OAuthTokens, type User, type EmptyObject, type UnknownObject } from "../types.js";
|
|
2
2
|
import type { AuthConfig } from "../server/config.js";
|
|
3
|
+
import type { CookieStorage } from "../shared/lib/storage.js";
|
|
3
4
|
/**
|
|
4
5
|
* Gets the authenticated user with token validation
|
|
5
6
|
* @param storage The auth storage
|
|
6
7
|
* @param config The auth configuration
|
|
7
8
|
*/
|
|
8
|
-
export declare function getUser<T extends UnknownObject = EmptyObject>(storage:
|
|
9
|
+
export declare function getUser<T extends UnknownObject = EmptyObject>(storage: CookieStorage, config: AuthConfig): Promise<User<T> | null>;
|
|
9
10
|
/**
|
|
10
11
|
* Gets the authentication tokens with token validation
|
|
11
12
|
* @param storage The auth storage
|
|
12
13
|
* @param config The auth configuration
|
|
13
14
|
*/
|
|
14
|
-
export declare function getTokens(storage:
|
|
15
|
+
export declare function getTokens(storage: CookieStorage, config: AuthConfig): Promise<OAuthTokens | null>;
|
|
15
16
|
//# sourceMappingURL=users.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/server/users.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,
|
|
1
|
+
{"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../src/server/users.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,CAAC,SAAS,aAAa,GAAG,WAAW,EACjE,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAGzB;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAG7B"}
|
package/dist/server/users.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/server/users.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"users.js","sourceRoot":"","sources":["../../src/server/users.ts"],"names":[],"mappings":"AAAA,OAAO,EAKN,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAsB,EACtB,MAAkB;IAElB,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC,OAAO,EAAK,CAAC;AAChC,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAsB,EACtB,MAAkB;IAElB,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC,SAAS,EAAE,CAAC;AAC/B,CAAC","sourcesContent":["import {\n type OAuthTokens,\n type User,\n type EmptyObject,\n type UnknownObject,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport { CivicAuth } from \"@/server/session.js\";\nimport type { CookieStorage } from \"@/shared/lib/storage.js\";\n\n/**\n * Gets the authenticated user with token validation\n * @param storage The auth storage\n * @param config The auth configuration\n */\nexport async function getUser<T extends UnknownObject = EmptyObject>(\n storage: CookieStorage,\n config: AuthConfig,\n): Promise<User<T> | null> {\n const civicAuth = new CivicAuth(storage, config);\n return civicAuth.getUser<T>();\n}\n\n/**\n * Gets the authentication tokens with token validation\n * @param storage The auth storage\n * @param config The auth configuration\n */\nexport async function getTokens(\n storage: CookieStorage,\n config: AuthConfig,\n): Promise<OAuthTokens | null> {\n const civicAuth = new CivicAuth(storage, config);\n return civicAuth.getTokens();\n}\n"]}
|
package/dist/services/types.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export interface AuthenticationResolver {
|
|
|
13
13
|
tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;
|
|
14
14
|
getSessionData(): Promise<SessionData | null>;
|
|
15
15
|
getEndSessionEndpoint(): Promise<string | null>;
|
|
16
|
-
validateExistingSession(
|
|
16
|
+
validateExistingSession(attemptRehydration?: boolean): Promise<SessionData>;
|
|
17
17
|
tryRefreshTokens(sessionData: SessionData | null): Promise<SessionData>;
|
|
18
18
|
}
|
|
19
19
|
export interface AuthenticationRefresher {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AASrE,MAAM,WAAW,YAAY;IAE3B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAGD,MAAM,WAAW,YAAa,SAAQ,YAAY;IAEhD,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC3C;AAGD,MAAM,WAAW,uBAAuB;IAEtC,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAG1D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7E;AAGD,MAAM,WAAW,sBAAsB;IAKrC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAG3E,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEhD,uBAAuB,CAAC,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AASrE,MAAM,WAAW,YAAY;IAE3B,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;CACrC;AAGD,MAAM,WAAW,YAAa,SAAQ,YAAY;IAEhD,eAAe,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC3C;AAGD,MAAM,WAAW,uBAAuB;IAEtC,MAAM,CAAC,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;IAG1D,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,GAAG,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;CAC7E;AAGD,MAAM,WAAW,sBAAsB;IAKrC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAG3E,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAE9C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEhD,uBAAuB,CAAC,kBAAkB,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAI5E,gBAAgB,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACzE;AAED,MAAM,WAAW,uBAAuB;IACtC,aAAa,EAAE,MAAM,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAAC;CAC5D;AAED,qBAAa,UAAW,SAAQ,KAAK;gBACvB,OAAO,EAAE,MAAM;CAI5B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAqDA,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF","sourcesContent":["import type { OIDCTokenResponseBody, SessionData } from \"@/types.js\";\n\n// A PKCEConsumer can get a code challenge to use in the login process\n// A PKCEProducer can also generate and store verifiers. The producer must also be a consumer in order to get the challenge from an existing flow\n// Examples:\n// - Client-only SPA: The SPA generates the code challenge and verifier, stores the verifier in state and returns the code challenge\n// Note - The SPA should use PKCEProducer instead to do both\n// - Client-side of a client/server app: The client calls the backend to get the challenge.\n// - Server-side: The server should generate a new stored verifier and derive the challenge from it.\nexport interface PKCEConsumer {\n // Retrieve a new PKCE challenge\n getCodeChallenge(): Promise<string>;\n}\n\n// All producers are consumers, because the producer can get its own challenge\nexport interface PKCEProducer extends PKCEConsumer {\n // Retrieve the PKCE challenge from the session if one exists\n getCodeVerifier(): Promise<string | null>;\n}\n\n// A service that can initiate requests to login or log out\nexport interface AuthenticationInitiator {\n // trigger a new login\n signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;\n\n // trigger a new logout\n signOut(idToken: string, iframeRef: HTMLIFrameElement | null): Promise<URL>;\n}\n\n// A service that can resolve an authentication request according to the OAuth Auth Code grant types\nexport interface AuthenticationResolver {\n // Given an auth code, get the tokens from the auth server and store them. works in PKCE and non-PKCE environments\n // Note, if we choose later to implement other grants, this method would move into a subinterface specifically\n // for the authorization code grant type.\n // The return type is just for convenience and can be ignored, as the same data would be provided by getSessionData\n tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;\n\n // If the tokens have already been retrieved, return them\n getSessionData(): Promise<SessionData | null>;\n\n getEndSessionEndpoint(): Promise<string | null>;\n // If an existing session is found, validate it and return the session data\n validateExistingSession(
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/services/types.ts"],"names":[],"mappings":"AAqDA,MAAM,OAAO,UAAW,SAAQ,KAAK;IACnC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC;IACpD,CAAC;CACF","sourcesContent":["import type { OIDCTokenResponseBody, SessionData } from \"@/types.js\";\n\n// A PKCEConsumer can get a code challenge to use in the login process\n// A PKCEProducer can also generate and store verifiers. The producer must also be a consumer in order to get the challenge from an existing flow\n// Examples:\n// - Client-only SPA: The SPA generates the code challenge and verifier, stores the verifier in state and returns the code challenge\n// Note - The SPA should use PKCEProducer instead to do both\n// - Client-side of a client/server app: The client calls the backend to get the challenge.\n// - Server-side: The server should generate a new stored verifier and derive the challenge from it.\nexport interface PKCEConsumer {\n // Retrieve a new PKCE challenge\n getCodeChallenge(): Promise<string>;\n}\n\n// All producers are consumers, because the producer can get its own challenge\nexport interface PKCEProducer extends PKCEConsumer {\n // Retrieve the PKCE challenge from the session if one exists\n getCodeVerifier(): Promise<string | null>;\n}\n\n// A service that can initiate requests to login or log out\nexport interface AuthenticationInitiator {\n // trigger a new login\n signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;\n\n // trigger a new logout\n signOut(idToken: string, iframeRef: HTMLIFrameElement | null): Promise<URL>;\n}\n\n// A service that can resolve an authentication request according to the OAuth Auth Code grant types\nexport interface AuthenticationResolver {\n // Given an auth code, get the tokens from the auth server and store them. works in PKCE and non-PKCE environments\n // Note, if we choose later to implement other grants, this method would move into a subinterface specifically\n // for the authorization code grant type.\n // The return type is just for convenience and can be ignored, as the same data would be provided by getSessionData\n tokenExchange(code: string, state: string): Promise<OIDCTokenResponseBody>;\n\n // If the tokens have already been retrieved, return them\n getSessionData(): Promise<SessionData | null>;\n\n getEndSessionEndpoint(): Promise<string | null>;\n // If an existing session is found, validate it and return the session data\n validateExistingSession(attemptRehydration?: boolean): Promise<SessionData>;\n\n // if there's a refresh token, use it to get new tokens\n // failing gracefully and deleting the bad refresh_token on failure\n tryRefreshTokens(sessionData: SessionData | null): Promise<SessionData>;\n}\n\nexport interface AuthenticationRefresher {\n refreshTokens: () => Promise<OIDCTokenResponseBody | null>;\n}\n\nexport class PopupError extends Error {\n constructor(message: string) {\n super(message);\n Object.setPrototypeOf(this, PopupError.prototype);\n }\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowserAuthenticationRefresher.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/BrowserAuthenticationRefresher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACzC;AAED,qBAAa,8BAA+B,SAAQ,2BAA2B;IAC7E,OAAO,CAAC,qBAAqB,CAAC,CAAwB;WAChC,KAAK,CACzB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,EACtC,qBAAqB,CAAC,EAAE,qBAAqB,GAC5C,OAAO,CAAC,8BAA8B,CAAC;IAa1C,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK;cAMlB,iBAAiB;IAsC3B,gBAAgB;
|
|
1
|
+
{"version":3,"file":"BrowserAuthenticationRefresher.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/BrowserAuthenticationRefresher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACzC;AAED,qBAAa,8BAA+B,SAAQ,2BAA2B;IAC7E,OAAO,CAAC,qBAAqB,CAAC,CAAwB;WAChC,KAAK,CACzB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,EACtC,qBAAqB,CAAC,EAAE,qBAAqB,GAC5C,OAAO,CAAC,8BAA8B,CAAC;IAa1C,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK;cAMlB,iBAAiB;IAsC3B,gBAAgB;IAmCtB,gBAAgB;CASjB"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AUTOREFRESH_TIMEOUT_NAME, REFRESH_IN_PROGRESS } from "../../constants.js";
|
|
2
|
-
import {
|
|
2
|
+
import { retrieveOidcSessionExpiredAtSeconds } from "../../shared/lib/util.js";
|
|
3
3
|
import { AuthenticationRefresherImpl } from "./AuthenticationRefresherImpl.js";
|
|
4
4
|
import { UserStorage } from "./types.js";
|
|
5
5
|
export class BrowserAuthenticationRefresher extends AuthenticationRefresherImpl {
|
|
@@ -50,19 +50,19 @@ export class BrowserAuthenticationRefresher extends AuthenticationRefresherImpl
|
|
|
50
50
|
// Clear any existing timeout
|
|
51
51
|
this.clearAutorefresh();
|
|
52
52
|
// get expires_in
|
|
53
|
-
const
|
|
54
|
-
const
|
|
53
|
+
const nowSeconds = Math.floor(Date.now() / 1000);
|
|
54
|
+
const expiresAtSeconds = await retrieveOidcSessionExpiredAtSeconds(this.storage);
|
|
55
55
|
// If there's no expiration time, don't set up auto-refresh
|
|
56
|
-
if (!
|
|
56
|
+
if (!expiresAtSeconds) {
|
|
57
57
|
console.warn("BrowserAuthenticationRefresher: No OIDC_SESSION_EXPIRES_AT found, skipping auto-refresh setup");
|
|
58
58
|
return;
|
|
59
59
|
}
|
|
60
60
|
// Calculate time until expiry (subtract 30 seconds as buffer)
|
|
61
61
|
const bufferTime = 30; // 30 seconds
|
|
62
|
-
const
|
|
62
|
+
const refreshTimeSeconds = Math.max(0, expiresAtSeconds - bufferTime - nowSeconds); // handle case were token has expired in the past
|
|
63
63
|
const refreshTimeout = setTimeout(() => {
|
|
64
64
|
this.handleAutoRefresh();
|
|
65
|
-
}, 1000 *
|
|
65
|
+
}, 1000 * refreshTimeSeconds);
|
|
66
66
|
localStorage.setItem(AUTOREFRESH_TIMEOUT_NAME, refreshTimeout.toString());
|
|
67
67
|
}
|
|
68
68
|
clearAutorefresh() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BrowserAuthenticationRefresher.js","sourceRoot":"","sources":["../../../src/shared/lib/BrowserAuthenticationRefresher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAC/E,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"BrowserAuthenticationRefresher.js","sourceRoot":"","sources":["../../../src/shared/lib/BrowserAuthenticationRefresher.ts"],"names":[],"mappings":"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","sourcesContent":["import { AUTOREFRESH_TIMEOUT_NAME, REFRESH_IN_PROGRESS } from \"@/constants.js\";\nimport { retrieveOidcSessionExpiredAtSeconds } from \"@/shared/lib/util.js\";\nimport { AuthenticationRefresherImpl } from \"./AuthenticationRefresherImpl.js\";\nimport type { AuthStorage, Endpoints } from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport { UserStorage } from \"./types.js\";\n\nexport interface RefreshEventCallbacks {\n onRefreshStarted?: () => void;\n onRefreshComplete?: () => void;\n onRefreshError?: (error: Error) => void;\n}\n\nexport class BrowserAuthenticationRefresher extends AuthenticationRefresherImpl {\n private refreshEventCallbacks?: RefreshEventCallbacks;\n static override async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n onError: (error: Error) => Promise<void>,\n endpointOverrides?: Partial<Endpoints>,\n refreshEventCallbacks?: RefreshEventCallbacks,\n ): Promise<BrowserAuthenticationRefresher> {\n const refresher = new BrowserAuthenticationRefresher(\n authConfig,\n storage,\n onError,\n endpointOverrides,\n );\n refresher.refreshEventCallbacks = refreshEventCallbacks;\n await refresher.init();\n\n return refresher;\n }\n\n protected handleError(error: Error) {\n console.error(\"BrowserAuthenticationRefresher: Error\", error);\n this.clearAutorefresh();\n this.onError(error);\n }\n\n protected async handleAutoRefresh() {\n try {\n const existingUser = await this.storage?.get(UserStorage.USER);\n if (!existingUser) {\n console.warn(\n \"BrowserAuthenticationRefresher: No user found, skipping refresh\",\n );\n this.clearAutorefresh();\n return;\n }\n // ensure only one refresh is in progress\n if (localStorage.getItem(REFRESH_IN_PROGRESS) !== \"true\") {\n localStorage.setItem(REFRESH_IN_PROGRESS, \"true\");\n\n // Call onRefreshStarted callback\n this.refreshEventCallbacks?.onRefreshStarted?.();\n\n await this.refreshTokens();\n\n // Call onRefreshComplete callback\n this.refreshEventCallbacks?.onRefreshComplete?.();\n\n await this.setupAutorefresh(); // Reset the timeout after successful refresh\n }\n } catch (error) {\n console.error(\n \"BrowserAuthenticationRefresher: Failed to refresh tokens:\",\n error,\n );\n\n // Call onRefreshError callback\n this.refreshEventCallbacks?.onRefreshError?.(error as Error);\n\n // TODO detect if refresh token has expired and if yes then logout\n this.handleError(error as Error);\n }\n }\n\n async setupAutorefresh() {\n // clear any existing state\n localStorage.removeItem(REFRESH_IN_PROGRESS);\n\n if (!this.storage) throw new Error(\"No storage available\");\n // Clear any existing timeout\n this.clearAutorefresh();\n\n // get expires_in\n const nowSeconds = Math.floor(Date.now() / 1000);\n const expiresAtSeconds = await retrieveOidcSessionExpiredAtSeconds(\n this.storage,\n );\n\n // If there's no expiration time, don't set up auto-refresh\n if (!expiresAtSeconds) {\n console.warn(\n \"BrowserAuthenticationRefresher: No OIDC_SESSION_EXPIRES_AT found, skipping auto-refresh setup\",\n );\n return;\n }\n\n // Calculate time until expiry (subtract 30 seconds as buffer)\n const bufferTime = 30; // 30 seconds\n const refreshTimeSeconds = Math.max(\n 0,\n expiresAtSeconds - bufferTime - nowSeconds,\n ); // handle case were token has expired in the past\n\n const refreshTimeout = setTimeout(() => {\n this.handleAutoRefresh();\n }, 1000 * refreshTimeSeconds);\n localStorage.setItem(AUTOREFRESH_TIMEOUT_NAME, refreshTimeout.toString());\n }\n\n clearAutorefresh() {\n // use local storage to store the timeout id so that if multiple instances\n // of the refresher are created they can all clear the same timeout\n const existingTimeout = localStorage.getItem(AUTOREFRESH_TIMEOUT_NAME);\n if (existingTimeout) {\n clearTimeout(Number(existingTimeout));\n localStorage.removeItem(AUTOREFRESH_TIMEOUT_NAME);\n }\n }\n}\n"]}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { type AuthStorage, type OAuthTokens, type User, type EmptyObject, type UnknownObject } from "../../types.js";
|
|
1
|
+
import { type AuthStorage, type OAuthTokens, type User, type EmptyObject, type UnknownObject, type OIDCTokenResponseBody } from "../../types.js";
|
|
2
|
+
export declare function getUserFromTokens<T extends UnknownObject = EmptyObject>(tokens: Partial<OIDCTokenResponseBody> | null): Promise<User<T> | null>;
|
|
2
3
|
export declare function getUser<T extends UnknownObject = EmptyObject>(storage: AuthStorage): Promise<User<T> | null>;
|
|
3
4
|
export declare function getTokens(storage: AuthStorage): Promise<OAuthTokens | null>;
|
|
4
5
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/session.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/session.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAC3B,MAAM,YAAY,CAAC;AAsBpB,wBAAsB,iBAAiB,CAAC,CAAC,SAAS,aAAa,GAAG,WAAW,EAC3E,MAAM,EAAE,OAAO,CAAC,qBAAqB,CAAC,GAAG,IAAI,GAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAmBzB;AAED,wBAAsB,OAAO,CAAC,CAAC,SAAS,aAAa,GAAG,WAAW,EACjE,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAGzB;AAED,wBAAsB,SAAS,CAC7B,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAS7B;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,YAAmB,WAAW,kBAI1D,CAAC"}
|
|
@@ -14,8 +14,7 @@ const parseJWTToType = (jwt) => {
|
|
|
14
14
|
const parseResult = decodeJwt(jwt);
|
|
15
15
|
return parseResult;
|
|
16
16
|
};
|
|
17
|
-
export async function
|
|
18
|
-
const tokens = await retrieveTokens(storage);
|
|
17
|
+
export async function getUserFromTokens(tokens) {
|
|
19
18
|
if (!tokens || !tokens.id_token)
|
|
20
19
|
return null;
|
|
21
20
|
const parsedToken = parseJWTToType(tokens.id_token);
|
|
@@ -31,6 +30,10 @@ export async function getUser(storage) {
|
|
|
31
30
|
// remove the token keys from the user object to stop it getting too large
|
|
32
31
|
return omitKeys([...JWT_PAYLOAD_KNOWN_CLAIM_KEYS, ...tokenKeys], userWithAdditionalTokenFields);
|
|
33
32
|
}
|
|
33
|
+
export async function getUser(storage) {
|
|
34
|
+
const tokens = await retrieveTokens(storage);
|
|
35
|
+
return getUserFromTokens(tokens);
|
|
36
|
+
}
|
|
34
37
|
export async function getTokens(storage) {
|
|
35
38
|
const storageData = await retrieveTokens(storage);
|
|
36
39
|
if (!storageData)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/shared/lib/session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,SAAS,EACT,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAmB,MAAM,MAAM,CAAC;AAClD,OAAO,EACL,SAAS,
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../../src/shared/lib/session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,WAAW,EACX,SAAS,EACT,cAAc,GACf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAmB,MAAM,MAAM,CAAC;AAClD,OAAO,EACL,SAAS,GAOV,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,4BAA4B,EAAE,MAAM,gBAAgB,CAAC;AAE9D,uCAAuC;AACvC,MAAM,QAAQ,GAAG,CACf,IAAS,EACT,GAAM,EACM,EAAE;IACd,MAAM,MAAM,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC;IAC1B,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,EAAE;QACnB,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC;AAEF,MAAM,cAAc,GAAG,CACrB,GAAW,EACK,EAAE;IAClB,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IACnC,OAAO,WAA6B,CAAC;AACvC,CAAC,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,MAA6C;IAE7C,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE7C,MAAM,WAAW,GAAG,cAAc,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACpD,uCAAuC;IACvC,IAAI,CAAC,WAAW,CAAC,GAAG;QAAE,OAAO,IAAI,CAAC;IAElC,qCAAqC;IACrC,MAAM,6BAA6B,GAAG;QACpC,GAAI,WAAiB;QACrB,EAAE,EAAE,WAAW,CAAC,GAAG;KACpB,CAAC;IAEF,6CAA6C;IAC7C,0EAA0E;IAC1E,OAAO,QAAQ,CACb,CAAC,GAAG,4BAA4B,EAAE,GAAG,SAAS,CAAC,EAC/C,6BAA6B,CACnB,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAAoB;IAEpB,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAC7C,OAAO,iBAAiB,CAAI,MAAM,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAoB;IAEpB,MAAM,WAAW,GAAG,MAAM,cAAc,CAAC,OAAO,CAAC,CAAC;IAClD,IAAI,CAAC,WAAW;QAAE,OAAO,IAAI,CAAC;IAE9B,OAAO;QACL,OAAO,EAAE,WAAW,CAAC,QAAQ;QAC7B,WAAW,EAAE,WAAW,CAAC,YAAY;QACrC,YAAY,EAAE,WAAW,CAAC,aAAa;KACxC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,KAAK,EAAE,OAAoB,EAAE,EAAE;IAC7D,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3B,MAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IACzB,MAAM,sBAAsB,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC,CAAC","sourcesContent":["import {\n clearAuthServerSession,\n clearTokens,\n clearUser,\n retrieveTokens,\n} from \"@/shared/lib/util.js\";\nimport { decodeJwt, type JWTPayload } from \"jose\";\nimport {\n tokenKeys,\n type AuthStorage,\n type OAuthTokens,\n type User,\n type EmptyObject,\n type UnknownObject,\n type OIDCTokenResponseBody,\n} from \"@/types.js\";\nimport { JWT_PAYLOAD_KNOWN_CLAIM_KEYS } from \"@/constants.js\";\n\n// Function to omit keys from an object\nconst omitKeys = <K extends keyof T, T extends Record<string, unknown>>(\n keys: K[],\n obj: T,\n): Omit<T, K> => {\n const result = { ...obj };\n keys.forEach((key) => {\n delete result[key];\n });\n return result;\n};\n\nconst parseJWTToType = <T extends UnknownObject = EmptyObject>(\n jwt: string,\n): JWTPayload & T => {\n const parseResult = decodeJwt(jwt);\n return parseResult as JWTPayload & T;\n};\n\nexport async function getUserFromTokens<T extends UnknownObject = EmptyObject>(\n tokens: Partial<OIDCTokenResponseBody> | null,\n): Promise<User<T> | null> {\n if (!tokens || !tokens.id_token) return null;\n\n const parsedToken = parseJWTToType(tokens.id_token);\n // it might be preferable to throw here\n if (!parsedToken.sub) return null;\n\n // set the user ID from the token sub\n const userWithAdditionalTokenFields = {\n ...(parsedToken as T),\n id: parsedToken.sub,\n };\n\n // Assumes all information is in the ID token\n // remove the token keys from the user object to stop it getting too large\n return omitKeys(\n [...JWT_PAYLOAD_KNOWN_CLAIM_KEYS, ...tokenKeys],\n userWithAdditionalTokenFields,\n ) as User<T>;\n}\n\nexport async function getUser<T extends UnknownObject = EmptyObject>(\n storage: AuthStorage,\n): Promise<User<T> | null> {\n const tokens = await retrieveTokens(storage);\n return getUserFromTokens<T>(tokens);\n}\n\nexport async function getTokens(\n storage: AuthStorage,\n): Promise<OAuthTokens | null> {\n const storageData = await retrieveTokens(storage);\n if (!storageData) return null;\n\n return {\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n}\n\n/**\n * Use the provided storage to clear all authentication cookies\n * @param storage\n */\nexport const clearAuthCookies = async (storage: AuthStorage) => {\n await clearTokens(storage);\n await clearUser(storage);\n await clearAuthServerSession(storage);\n};\n"]}
|
|
@@ -49,11 +49,11 @@ export declare function storeTokens(storage: AuthStorage, tokens: OIDCTokenRespo
|
|
|
49
49
|
* Refresh token is set with 400 day expiry
|
|
50
50
|
*/
|
|
51
51
|
export declare function storeServerTokens(storage: AuthStorage | CookieStorage, tokens: OIDCTokenResponseBody): Promise<void>;
|
|
52
|
-
export declare function clearTokens(storage: AuthStorage): Promise<void>;
|
|
52
|
+
export declare function clearTokens(storage: AuthStorage | CookieStorage): Promise<void>;
|
|
53
53
|
export declare function clearAuthServerSession(storage: AuthStorage): Promise<void>;
|
|
54
54
|
export declare function clearUser(storage: AuthStorage): Promise<void>;
|
|
55
55
|
export declare function retrieveTokens(storage: AuthStorage): Promise<Partial<OIDCTokenResponseBody> | null>;
|
|
56
|
-
export declare function
|
|
56
|
+
export declare function retrieveOidcSessionExpiredAtSeconds(storage: AuthStorage): Promise<number | null>;
|
|
57
57
|
export declare function validateOauth2Tokens(tokens: OIDCTokenResponseBody, jwksEndpoint: string, oauth2Client: OAuth2Client, issuer: string): Promise<ParsedTokens>;
|
|
58
58
|
/**
|
|
59
59
|
* Get backend endpoints with default values merged with custom configuration
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/util.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,YAAY,EACb,MAAM,YAAY,CAAC;AAMpB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAQlD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAG3D;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,EACpB,MAAM,GAAE,OAAO,GAAG,MAAe,GAChC,OAAO,CAAC,MAAM,CAAC,CAajB;AAED,wBAAsB,yBAAyB,CAC7C,WAAW,EAAE,MAAM,EACnB,iBAAiB,GAAE,OAAO,CAAC,SAAS,CAAM,GACzC,OAAO,CAAC,SAAS,CAAC,CAMpB;AAED,wBAAsB,qBAAqB,CAAC,MAAM,EAAE;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;IAEvC,YAAY,CAAC,EAAE,YAAY,CAAC;CAC7B,GAAG,OAAO,CAAC,GAAG,CAAC,CAiCf;AAED,wBAAsB,sBAAsB,CAAC,MAAM,EAAE;IACnD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC;CACxC,GAAG,OAAO,CAAC,GAAG,CAAC,CAcf;AAED,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,GACnB,YAAY,CAId;AAED,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,YAAY,EAAE,YAAY,GAAG,IAAI,EACjC,YAAY,EAAE,YAAY,EAC1B,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,EACpB,YAAY,CAAC,EAAE,MAAM,kCA8CtB;AACD;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,WACnB,qBAAqB,KAC5B;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,iBAAiB,EAAE,MAAM,CAAA;CAiCpD,CAAC;AAEF,wBAAsB,uBAAuB,CAC3C,OAAO,EAAE,WAAW,GAAG,aAAa,EACpC,MAAM,EAAE,qBAAqB,iBAS9B;AAED,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,qBAAqB,iBAkB9B;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,WAAW,GAAG,aAAa,EACpC,MAAM,EAAE,qBAAqB,iBAyD9B;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,
|
|
1
|
+
{"version":3,"file":"util.d.ts","sourceRoot":"","sources":["../../../src/shared/lib/util.ts"],"names":[],"mappings":"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"}
|
package/dist/shared/lib/util.js
CHANGED
|
@@ -265,12 +265,12 @@ export async function retrieveTokens(storage) {
|
|
|
265
265
|
: undefined, // Convert string to number
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
|
-
export async function
|
|
269
|
-
const
|
|
270
|
-
if (!
|
|
268
|
+
export async function retrieveOidcSessionExpiredAtSeconds(storage) {
|
|
269
|
+
const valueSeconds = await storage.get(OAuthTokenTypes.OIDC_SESSION_EXPIRES_AT);
|
|
270
|
+
if (!valueSeconds) {
|
|
271
271
|
return null;
|
|
272
272
|
}
|
|
273
|
-
const expiresAt = Number(
|
|
273
|
+
const expiresAt = Number(valueSeconds);
|
|
274
274
|
return isNaN(expiresAt) ? null : expiresAt;
|
|
275
275
|
}
|
|
276
276
|
// Single JWKS instance that persists for the lifetime of the SDK session
|