@civic/auth 0.8.3-beta.1 → 0.9.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +3 -3
  3. package/dist/constants.d.ts +2 -1
  4. package/dist/constants.d.ts.map +1 -1
  5. package/dist/constants.js +3 -1
  6. package/dist/constants.js.map +1 -1
  7. package/dist/nextjs/config.d.ts +3 -0
  8. package/dist/nextjs/config.d.ts.map +1 -1
  9. package/dist/nextjs/config.js +3 -0
  10. package/dist/nextjs/config.js.map +1 -1
  11. package/dist/nextjs/providers/NextAuthProvider.d.ts.map +1 -1
  12. package/dist/nextjs/providers/NextAuthProvider.js +1 -1
  13. package/dist/nextjs/providers/NextAuthProvider.js.map +1 -1
  14. package/dist/reactjs/core/GlobalAuthManager.d.ts +1 -0
  15. package/dist/reactjs/core/GlobalAuthManager.d.ts.map +1 -1
  16. package/dist/reactjs/core/GlobalAuthManager.js +5 -2
  17. package/dist/reactjs/core/GlobalAuthManager.js.map +1 -1
  18. package/dist/reactjs/providers/CivicAuthContext.d.ts.map +1 -1
  19. package/dist/reactjs/providers/CivicAuthContext.js +2 -1
  20. package/dist/reactjs/providers/CivicAuthContext.js.map +1 -1
  21. package/dist/reactjs/providers/CivicAuthProvider.d.ts +1 -0
  22. package/dist/reactjs/providers/CivicAuthProvider.d.ts.map +1 -1
  23. package/dist/reactjs/providers/CivicAuthProvider.js +3 -1
  24. package/dist/reactjs/providers/CivicAuthProvider.js.map +1 -1
  25. package/dist/server/ServerAuthenticationResolver.d.ts.map +1 -1
  26. package/dist/server/ServerAuthenticationResolver.js +4 -0
  27. package/dist/server/ServerAuthenticationResolver.js.map +1 -1
  28. package/dist/server/config.d.ts +11 -3
  29. package/dist/server/config.d.ts.map +1 -1
  30. package/dist/server/config.js.map +1 -1
  31. package/dist/server/login.d.ts.map +1 -1
  32. package/dist/server/login.js +5 -0
  33. package/dist/server/login.js.map +1 -1
  34. package/dist/server/logout.d.ts.map +1 -1
  35. package/dist/server/logout.js +5 -0
  36. package/dist/server/logout.js.map +1 -1
  37. package/dist/server/session.d.ts.map +1 -1
  38. package/dist/server/session.js +4 -0
  39. package/dist/server/session.js.map +1 -1
  40. package/dist/services/AuthenticationService.d.ts +8 -2
  41. package/dist/services/AuthenticationService.d.ts.map +1 -1
  42. package/dist/services/AuthenticationService.js +20 -6
  43. package/dist/services/AuthenticationService.js.map +1 -1
  44. package/dist/shared/components/IFrameAndLoading.d.ts.map +1 -1
  45. package/dist/shared/components/IFrameAndLoading.js +1 -1
  46. package/dist/shared/components/IFrameAndLoading.js.map +1 -1
  47. package/dist/shared/hooks/useSignIn.d.ts.map +1 -1
  48. package/dist/shared/hooks/useSignIn.js +4 -3
  49. package/dist/shared/hooks/useSignIn.js.map +1 -1
  50. package/dist/shared/lib/AuthenticationRefresherImpl.d.ts.map +1 -1
  51. package/dist/shared/lib/AuthenticationRefresherImpl.js +4 -0
  52. package/dist/shared/lib/AuthenticationRefresherImpl.js.map +1 -1
  53. package/dist/shared/lib/iframeUtils.d.ts +1 -0
  54. package/dist/shared/lib/iframeUtils.d.ts.map +1 -1
  55. package/dist/shared/lib/iframeUtils.js +9 -0
  56. package/dist/shared/lib/iframeUtils.js.map +1 -1
  57. package/dist/shared/lib/types.d.ts +1 -0
  58. package/dist/shared/lib/types.d.ts.map +1 -1
  59. package/dist/shared/lib/types.js.map +1 -1
  60. package/dist/shared/providers/CivicAuthConfigContext.d.ts +2 -1
  61. package/dist/shared/providers/CivicAuthConfigContext.d.ts.map +1 -1
  62. package/dist/shared/providers/CivicAuthConfigContext.js +3 -1
  63. package/dist/shared/providers/CivicAuthConfigContext.js.map +1 -1
  64. package/dist/shared/version.d.ts +1 -1
  65. package/dist/shared/version.js +1 -1
  66. package/dist/shared/version.js.map +1 -1
  67. package/dist/vanillajs/auth/CivicAuth.d.ts +1 -0
  68. package/dist/vanillajs/auth/CivicAuth.d.ts.map +1 -1
  69. package/dist/vanillajs/auth/CivicAuth.js +50 -10
  70. package/dist/vanillajs/auth/CivicAuth.js.map +1 -1
  71. package/dist/vanillajs/auth/config/ConfigProcessor.d.ts.map +1 -1
  72. package/dist/vanillajs/auth/config/ConfigProcessor.js +2 -1
  73. package/dist/vanillajs/auth/config/ConfigProcessor.js.map +1 -1
  74. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts +10 -0
  75. package/dist/vanillajs/auth/handlers/IframeAuthHandler.d.ts.map +1 -1
  76. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js +24 -1
  77. package/dist/vanillajs/auth/handlers/IframeAuthHandler.js.map +1 -1
  78. package/dist/vanillajs/auth/handlers/MessageHandler.d.ts +2 -0
  79. package/dist/vanillajs/auth/handlers/MessageHandler.d.ts.map +1 -1
  80. package/dist/vanillajs/auth/handlers/MessageHandler.js +7 -0
  81. package/dist/vanillajs/auth/handlers/MessageHandler.js.map +1 -1
  82. package/dist/vanillajs/auth/types/AuthTypes.d.ts +36 -13
  83. package/dist/vanillajs/auth/types/AuthTypes.d.ts.map +1 -1
  84. package/dist/vanillajs/auth/types/AuthTypes.js +2 -1
  85. package/dist/vanillajs/auth/types/AuthTypes.js.map +1 -1
  86. package/dist/vanillajs/iframe/IframeManager.d.ts +4 -0
  87. package/dist/vanillajs/iframe/IframeManager.d.ts.map +1 -1
  88. package/dist/vanillajs/iframe/IframeManager.js +31 -13
  89. package/dist/vanillajs/iframe/IframeManager.js.map +1 -1
  90. package/dist/vanillajs/iframe/IframeResizer.d.ts +4 -1
  91. package/dist/vanillajs/iframe/IframeResizer.d.ts.map +1 -1
  92. package/dist/vanillajs/iframe/IframeResizer.js +30 -1
  93. package/dist/vanillajs/iframe/IframeResizer.js.map +1 -1
  94. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthContext.js","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthContext.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n useMemo,\n useRef,\n} from \"react\";\nimport type { ReactNode } from \"react\";\nimport {\n CivicAuth,\n AuthEvent,\n type Session,\n type User,\n} from \"../../vanillajs/index.js\";\nimport { AuthenticationEvents } from \"../../vanillajs/auth/AuthenticationEvents.js\";\nimport type { DisplayMode, ForwardedTokens } from \"../../types.js\";\nimport { extractTokensFromSession } from \"../../vanillajs/utils/auth-utils.js\";\n\n// Event payload interfaces\ninterface SignInErrorEvent {\n detail: string;\n}\n\nexport type AuthStatusEnum =\n | \"authenticated\"\n | \"unauthenticated\"\n | \"authenticating\"\n | \"error\"\n | \"signing_out\";\n\nexport interface CivicAuthContextType {\n // Core auth instance\n auth: CivicAuth | null;\n\n // User and session state\n user: User | null;\n session: Session | null;\n\n // Auth state\n isLoading: boolean;\n authStatus: AuthStatusEnum;\n error: Error | null;\n\n // Tokens\n idToken?: string;\n accessToken?: string;\n refreshToken?: string;\n forwardedTokens?: ForwardedTokens;\n\n // Auth methods\n signIn: () => Promise<{ user: User }>;\n signOut: () => Promise<void>;\n\n // Preloading methods\n isAuthenticationPreloaded: () => boolean;\n setPreloadEnabled: (enabled: boolean) => void;\n getPreloadEnabled: () => boolean;\n\n // Config\n displayMode?: DisplayMode;\n}\n\nconst CivicAuthContext = createContext<CivicAuthContextType | null>(null);\n\nexport interface CivicAuthContextProviderProps {\n children: ReactNode;\n clientId: string;\n redirectUrl?: string;\n oauthServerBaseUrl?: string;\n scopes?: string[];\n displayMode?: DisplayMode;\n iframeDisplayMode?: \"modal\" | \"embedded\";\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n nonce?: string;\n authProcessTimeout?: number;\n preloadIframe?: boolean;\n}\n\nexport const CivicAuthContextProvider: React.FC<\n CivicAuthContextProviderProps\n> = ({\n children,\n clientId,\n redirectUrl,\n oauthServerBaseUrl = \"https://auth.civic.com/oauth/\",\n scopes = [\"openid\", \"profile\", \"email\", \"offline_access\"],\n displayMode = \"iframe\",\n iframeDisplayMode = \"modal\",\n onSignIn,\n onSignOut,\n nonce,\n authProcessTimeout = 120000,\n preloadIframe,\n}) => {\n const [auth, setAuth] = useState<CivicAuth | null>(null);\n const [user, setUser] = useState<User | null>(null);\n const [session, setSession] = useState<Session | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [authStatus, setAuthStatus] =\n useState<AuthStatusEnum>(\"unauthenticated\");\n const [error, setError] = useState<Error | null>(null);\n\n // Track initialization to prevent double-execution in React StrictMode\n const initializationRef = useRef<{\n isInitializing: boolean;\n isInitialized: boolean;\n }>({\n isInitializing: false,\n isInitialized: false,\n });\n\n useEffect(() => {\n let isMounted = true;\n\n // Prevent double initialization in React StrictMode\n if (\n initializationRef.current.isInitializing ||\n initializationRef.current.isInitialized\n ) {\n // `[CivicAuthContext] Skipping initialization ${initId} - already initializing/initialized`,\n\n return;\n }\n\n // Capture ref value at effect setup time for cleanup\n const initializationState = initializationRef.current;\n\n initializationRef.current.isInitializing = true;\n\n const refreshUserAndSession = async () => {\n if (!auth) return;\n\n try {\n const currentSession = await auth.getCurrentSession();\n const currentUser = await auth.getCurrentUser();\n\n if (isMounted) {\n setSession(currentSession);\n setUser(currentUser);\n }\n } catch (err) {\n if (isMounted) {\n const sessionError =\n err instanceof Error ? err : new Error(\"Failed to get session\");\n setError(sessionError);\n }\n }\n };\n\n const initializeAuth = async () => {\n try {\n const events = new AuthenticationEvents();\n\n // Set up event listeners\n events.on(AuthEvent.SIGN_IN_STARTED, () => {\n if (isMounted) {\n setIsLoading(true);\n setAuthStatus(\"authenticating\");\n setError(null);\n }\n });\n\n events.on(AuthEvent.SIGN_IN_COMPLETE, () => {\n if (isMounted) {\n setIsLoading(false);\n setAuthStatus(\"authenticated\");\n setError(null);\n onSignIn?.();\n }\n });\n\n events.on(AuthEvent.SIGN_IN_ERROR, (event?: SignInErrorEvent) => {\n if (isMounted) {\n setIsLoading(false);\n setAuthStatus(\"error\");\n const errorDetail = event?.detail || \"Authentication failed\";\n const authError = new Error(errorDetail);\n setError(authError);\n onSignIn?.(authError);\n }\n });\n\n events.on(AuthEvent.SIGN_OUT_STARTED, () => {\n if (isMounted) {\n setIsLoading(true);\n setAuthStatus(\"signing_out\");\n setError(null);\n }\n });\n\n events.on(AuthEvent.SIGN_OUT_COMPLETE, () => {\n if (isMounted) {\n setIsLoading(false);\n setAuthStatus(\"unauthenticated\");\n setUser(null);\n setSession(null);\n setError(null);\n onSignOut?.();\n }\n });\n\n events.on(AuthEvent.USER_SESSION_CHANGED, () => {\n if (isMounted) {\n refreshUserAndSession();\n }\n });\n\n const authInstance = await CivicAuth.create({\n clientId,\n redirectUrl:\n redirectUrl ||\n `${window.location.origin}${window.location.pathname}`,\n oauthServerBaseUrl,\n scopes,\n displayMode,\n iframeDisplayMode,\n nonce,\n authProcessTimeout,\n preloadIframe,\n events,\n });\n\n if (isMounted) {\n setAuth(authInstance);\n\n // Mark initialization as complete\n initializationRef.current.isInitializing = false;\n initializationRef.current.isInitialized = true;\n\n // Check initial auth state\n const isAuthenticated = await authInstance.isAuthenticated();\n if (isAuthenticated) {\n setAuthStatus(\"authenticated\");\n await refreshUserAndSession();\n } else {\n setAuthStatus(\"unauthenticated\");\n\n // Note: Preloading is now handled automatically by CivicAuth based on config.preloadIframe\n }\n\n // Mark initialization as complete\n setIsLoading(false);\n }\n } catch (err) {\n console.error(err);\n if (isMounted) {\n const initError =\n err instanceof Error ? err : new Error(\"Failed to initialize auth\");\n setError(initError);\n setAuthStatus(\"error\");\n setIsLoading(false); // Stop loading even on error\n\n // Mark initialization as failed\n initializationRef.current.isInitializing = false;\n // Don't mark as initialized on error so it can be retried\n }\n }\n };\n\n initializeAuth();\n\n return () => {\n isMounted = false;\n\n // Reset initialization guards to allow remount to reinitialize\n // This is necessary for React StrictMode compatibility\n if (initializationState.isInitializing) {\n initializationState.isInitializing = false;\n initializationState.isInitialized = false;\n }\n\n if (auth) {\n auth.destroy();\n }\n };\n // Refresh user and session when auth instance changes\n /*\n * Intentionally omitting dependencies to prevent infinite loops.\n * Adding auth, onSignIn, onSignOut, and scopes to the dependency array would cause\n * the effect to re-run whenever these values change, which could lead to unnecessary\n * re-renders and potential infinite loops since the effect updates state that might\n * trigger re-renders of parent components.\n *\n * IMPORTANT: redirectUrl is intentionally omitted to prevent re-initialization\n * during OAuth callback when URL parameters change, which would cause\n * \"invalid_grant\" errors due to authorization code reuse.\n */\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n clientId,\n oauthServerBaseUrl,\n displayMode,\n iframeDisplayMode,\n nonce,\n authProcessTimeout,\n preloadIframe,\n ]);\n\n // This is on load to get the user and session\n useEffect(() => {\n if (auth && authStatus === \"authenticated\") {\n const refreshUserAndSession = async () => {\n try {\n const currentSession = await auth.getCurrentSession();\n const currentUser = await auth.getCurrentUser();\n setSession(currentSession);\n setUser(currentUser);\n } catch (err) {\n const sessionError =\n err instanceof Error ? err : new Error(\"Failed to get session\");\n setError(sessionError);\n }\n };\n\n refreshUserAndSession();\n }\n }, [auth, authStatus]);\n\n const signIn = useCallback(async () => {\n if (!auth) {\n // If auth is still loading, provide a more helpful error\n if (isLoading) {\n throw new Error(\"Authentication is still initializing, please wait...\");\n }\n throw new Error(\"Auth not initialized\");\n }\n\n try {\n const { user } = await auth.startAuthentication();\n\n // Refresh user and session after successful authentication\n const currentSession = await auth.getCurrentSession();\n\n setSession(currentSession);\n setUser(user ?? null);\n\n // Ensure we have a user to return\n if (!user) {\n throw new Error(\"Authentication succeeded but no user was returned\");\n }\n\n // Return the user object\n return { user };\n } catch (err) {\n const signInError =\n err instanceof Error ? err : new Error(\"Sign in failed\");\n setError(signInError);\n throw signInError;\n }\n }, [auth, isLoading]);\n\n const signOut = useCallback(async () => {\n if (!auth) {\n // If auth is still loading, provide a more helpful error\n if (isLoading) {\n throw new Error(\"Authentication is still initializing, please wait...\");\n }\n throw new Error(\"Auth not initialized\");\n }\n\n try {\n await auth.logout();\n setUser(null);\n setSession(null);\n } catch (err) {\n const signOutError =\n err instanceof Error ? err : new Error(\"Sign out failed\");\n setError(signOutError);\n throw signOutError;\n }\n }, [auth, isLoading]);\n\n const isAuthenticationPreloaded = useCallback(() => {\n return auth?.isAuthenticationPreloaded() ?? false;\n }, [auth]);\n\n const setPreloadEnabled = useCallback(\n (enabled: boolean) => {\n if (!auth) {\n throw new Error(\"Auth not initialized\");\n }\n auth.setPreloadEnabled(enabled);\n },\n [auth],\n );\n\n const getPreloadEnabled = useCallback(() => {\n return auth?.getPreloadEnabled() ?? true;\n }, [auth]);\n\n // Extract tokens from session\n const idToken = session?.idToken;\n const accessToken = session?.accessToken;\n const refreshToken = session?.refreshToken;\n\n // Extract forwardedTokens from session's ID token\n const forwardedTokens = useMemo(() => {\n if (!session) return undefined;\n const tokens = extractTokensFromSession(session);\n return tokens.forwardedTokens;\n }, [session]);\n\n const contextValue: CivicAuthContextType = useMemo(\n () => ({\n auth,\n user,\n session,\n isLoading,\n authStatus,\n error,\n idToken,\n accessToken,\n refreshToken,\n forwardedTokens,\n signIn,\n signOut,\n isAuthenticationPreloaded,\n setPreloadEnabled,\n getPreloadEnabled,\n displayMode,\n }),\n [\n auth,\n user,\n session,\n isLoading,\n authStatus,\n error,\n idToken,\n accessToken,\n refreshToken,\n forwardedTokens,\n signIn,\n signOut,\n isAuthenticationPreloaded,\n setPreloadEnabled,\n getPreloadEnabled,\n displayMode,\n ],\n );\n\n return (\n <CivicAuthContext.Provider value={contextValue}>\n {children}\n </CivicAuthContext.Provider>\n );\n};\n\nexport const useCivicAuthContext = (): CivicAuthContextType => {\n const context = useContext(CivicAuthContext);\n if (!context) {\n throw new Error(\n \"useCivicAuthContext must be used within a CivicAuthContextProvider\",\n );\n }\n return context;\n};\n\nexport { CivicAuthContext };\n"]}
1
+ {"version":3,"file":"CivicAuthContext.js","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthContext.tsx"],"names":[],"mappings":"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","sourcesContent":["\"use client\";\nimport React, {\n createContext,\n useContext,\n useEffect,\n useState,\n useCallback,\n useMemo,\n useRef,\n} from \"react\";\nimport type { ReactNode } from \"react\";\nimport {\n CivicAuth,\n AuthEvent,\n type Session,\n type User,\n} from \"../../vanillajs/index.js\";\nimport { AuthenticationEvents } from \"../../vanillajs/auth/AuthenticationEvents.js\";\nimport type { DisplayMode, ForwardedTokens } from \"../../types.js\";\nimport { extractTokensFromSession } from \"../../vanillajs/utils/auth-utils.js\";\nimport { DEFAULT_AUTH_PROCESS_TIMEOUT } from \"../../vanillajs/auth/types/AuthTypes.js\";\n\n// Event payload interfaces\ninterface SignInErrorEvent {\n detail: string;\n}\n\nexport type AuthStatusEnum =\n | \"authenticated\"\n | \"unauthenticated\"\n | \"authenticating\"\n | \"error\"\n | \"signing_out\";\n\nexport interface CivicAuthContextType {\n // Core auth instance\n auth: CivicAuth | null;\n\n // User and session state\n user: User | null;\n session: Session | null;\n\n // Auth state\n isLoading: boolean;\n authStatus: AuthStatusEnum;\n error: Error | null;\n\n // Tokens\n idToken?: string;\n accessToken?: string;\n refreshToken?: string;\n forwardedTokens?: ForwardedTokens;\n\n // Auth methods\n signIn: () => Promise<{ user: User }>;\n signOut: () => Promise<void>;\n\n // Preloading methods\n isAuthenticationPreloaded: () => boolean;\n setPreloadEnabled: (enabled: boolean) => void;\n getPreloadEnabled: () => boolean;\n\n // Config\n displayMode?: DisplayMode;\n}\n\nconst CivicAuthContext = createContext<CivicAuthContextType | null>(null);\n\nexport interface CivicAuthContextProviderProps {\n children: ReactNode;\n clientId: string;\n redirectUrl?: string;\n oauthServerBaseUrl?: string;\n scopes?: string[];\n displayMode?: DisplayMode;\n iframeDisplayMode?: \"modal\" | \"embedded\";\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n nonce?: string;\n authProcessTimeout?: number;\n preloadIframe?: boolean;\n}\n\nexport const CivicAuthContextProvider: React.FC<\n CivicAuthContextProviderProps\n> = ({\n children,\n clientId,\n redirectUrl,\n oauthServerBaseUrl = \"https://auth.civic.com/oauth/\",\n scopes = [\"openid\", \"profile\", \"email\", \"offline_access\"],\n displayMode = \"iframe\",\n iframeDisplayMode = \"modal\",\n onSignIn,\n onSignOut,\n nonce,\n authProcessTimeout = DEFAULT_AUTH_PROCESS_TIMEOUT,\n preloadIframe,\n}) => {\n const [auth, setAuth] = useState<CivicAuth | null>(null);\n const [user, setUser] = useState<User | null>(null);\n const [session, setSession] = useState<Session | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [authStatus, setAuthStatus] =\n useState<AuthStatusEnum>(\"unauthenticated\");\n const [error, setError] = useState<Error | null>(null);\n\n // Track initialization to prevent double-execution in React StrictMode\n const initializationRef = useRef<{\n isInitializing: boolean;\n isInitialized: boolean;\n }>({\n isInitializing: false,\n isInitialized: false,\n });\n\n useEffect(() => {\n let isMounted = true;\n\n // Prevent double initialization in React StrictMode\n if (\n initializationRef.current.isInitializing ||\n initializationRef.current.isInitialized\n ) {\n // `[CivicAuthContext] Skipping initialization ${initId} - already initializing/initialized`,\n\n return;\n }\n\n // Capture ref value at effect setup time for cleanup\n const initializationState = initializationRef.current;\n\n initializationRef.current.isInitializing = true;\n\n const refreshUserAndSession = async () => {\n if (!auth) return;\n\n try {\n const currentSession = await auth.getCurrentSession();\n const currentUser = await auth.getCurrentUser();\n\n if (isMounted) {\n setSession(currentSession);\n setUser(currentUser);\n }\n } catch (err) {\n if (isMounted) {\n const sessionError =\n err instanceof Error ? err : new Error(\"Failed to get session\");\n setError(sessionError);\n }\n }\n };\n\n const initializeAuth = async () => {\n try {\n const events = new AuthenticationEvents();\n\n // Set up event listeners\n events.on(AuthEvent.SIGN_IN_STARTED, () => {\n if (isMounted) {\n setIsLoading(true);\n setAuthStatus(\"authenticating\");\n setError(null);\n }\n });\n\n events.on(AuthEvent.SIGN_IN_COMPLETE, () => {\n if (isMounted) {\n setIsLoading(false);\n setAuthStatus(\"authenticated\");\n setError(null);\n onSignIn?.();\n }\n });\n\n events.on(AuthEvent.SIGN_IN_ERROR, (event?: SignInErrorEvent) => {\n if (isMounted) {\n setIsLoading(false);\n setAuthStatus(\"error\");\n const errorDetail = event?.detail || \"Authentication failed\";\n const authError = new Error(errorDetail);\n setError(authError);\n onSignIn?.(authError);\n }\n });\n\n events.on(AuthEvent.SIGN_OUT_STARTED, () => {\n if (isMounted) {\n setIsLoading(true);\n setAuthStatus(\"signing_out\");\n setError(null);\n }\n });\n\n events.on(AuthEvent.SIGN_OUT_COMPLETE, () => {\n if (isMounted) {\n setIsLoading(false);\n setAuthStatus(\"unauthenticated\");\n setUser(null);\n setSession(null);\n setError(null);\n onSignOut?.();\n }\n });\n\n events.on(AuthEvent.USER_SESSION_CHANGED, () => {\n if (isMounted) {\n refreshUserAndSession();\n }\n });\n\n const authInstance = await CivicAuth.create({\n clientId,\n redirectUrl:\n redirectUrl ||\n `${window.location.origin}${window.location.pathname}`,\n oauthServerBaseUrl,\n scopes,\n displayMode,\n iframeDisplayMode,\n nonce,\n authProcessTimeout,\n preloadIframe,\n events,\n });\n\n if (isMounted) {\n setAuth(authInstance);\n\n // Mark initialization as complete\n initializationRef.current.isInitializing = false;\n initializationRef.current.isInitialized = true;\n\n // Check initial auth state\n const isAuthenticated = await authInstance.isAuthenticated();\n if (isAuthenticated) {\n setAuthStatus(\"authenticated\");\n await refreshUserAndSession();\n } else {\n setAuthStatus(\"unauthenticated\");\n\n // Note: Preloading is now handled automatically by CivicAuth based on config.preloadIframe\n }\n\n // Mark initialization as complete\n setIsLoading(false);\n }\n } catch (err) {\n console.error(err);\n if (isMounted) {\n const initError =\n err instanceof Error ? err : new Error(\"Failed to initialize auth\");\n setError(initError);\n setAuthStatus(\"error\");\n setIsLoading(false); // Stop loading even on error\n\n // Mark initialization as failed\n initializationRef.current.isInitializing = false;\n // Don't mark as initialized on error so it can be retried\n }\n }\n };\n\n initializeAuth();\n\n return () => {\n isMounted = false;\n\n // Reset initialization guards to allow remount to reinitialize\n // This is necessary for React StrictMode compatibility\n if (initializationState.isInitializing) {\n initializationState.isInitializing = false;\n initializationState.isInitialized = false;\n }\n\n if (auth) {\n auth.destroy();\n }\n };\n // Refresh user and session when auth instance changes\n /*\n * Intentionally omitting dependencies to prevent infinite loops.\n * Adding auth, onSignIn, onSignOut, and scopes to the dependency array would cause\n * the effect to re-run whenever these values change, which could lead to unnecessary\n * re-renders and potential infinite loops since the effect updates state that might\n * trigger re-renders of parent components.\n *\n * IMPORTANT: redirectUrl is intentionally omitted to prevent re-initialization\n * during OAuth callback when URL parameters change, which would cause\n * \"invalid_grant\" errors due to authorization code reuse.\n */\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [\n clientId,\n oauthServerBaseUrl,\n displayMode,\n iframeDisplayMode,\n nonce,\n authProcessTimeout,\n preloadIframe,\n ]);\n\n // This is on load to get the user and session\n useEffect(() => {\n if (auth && authStatus === \"authenticated\") {\n const refreshUserAndSession = async () => {\n try {\n const currentSession = await auth.getCurrentSession();\n const currentUser = await auth.getCurrentUser();\n setSession(currentSession);\n setUser(currentUser);\n } catch (err) {\n const sessionError =\n err instanceof Error ? err : new Error(\"Failed to get session\");\n setError(sessionError);\n }\n };\n\n refreshUserAndSession();\n }\n }, [auth, authStatus]);\n\n const signIn = useCallback(async () => {\n if (!auth) {\n // If auth is still loading, provide a more helpful error\n if (isLoading) {\n throw new Error(\"Authentication is still initializing, please wait...\");\n }\n throw new Error(\"Auth not initialized\");\n }\n\n try {\n const { user } = await auth.startAuthentication();\n\n // Refresh user and session after successful authentication\n const currentSession = await auth.getCurrentSession();\n\n setSession(currentSession);\n setUser(user ?? null);\n\n // Ensure we have a user to return\n if (!user) {\n throw new Error(\"Authentication succeeded but no user was returned\");\n }\n\n // Return the user object\n return { user };\n } catch (err) {\n const signInError =\n err instanceof Error ? err : new Error(\"Sign in failed\");\n setError(signInError);\n throw signInError;\n }\n }, [auth, isLoading]);\n\n const signOut = useCallback(async () => {\n if (!auth) {\n // If auth is still loading, provide a more helpful error\n if (isLoading) {\n throw new Error(\"Authentication is still initializing, please wait...\");\n }\n throw new Error(\"Auth not initialized\");\n }\n\n try {\n await auth.logout();\n setUser(null);\n setSession(null);\n } catch (err) {\n const signOutError =\n err instanceof Error ? err : new Error(\"Sign out failed\");\n setError(signOutError);\n throw signOutError;\n }\n }, [auth, isLoading]);\n\n const isAuthenticationPreloaded = useCallback(() => {\n return auth?.isAuthenticationPreloaded() ?? false;\n }, [auth]);\n\n const setPreloadEnabled = useCallback(\n (enabled: boolean) => {\n if (!auth) {\n throw new Error(\"Auth not initialized\");\n }\n auth.setPreloadEnabled(enabled);\n },\n [auth],\n );\n\n const getPreloadEnabled = useCallback(() => {\n return auth?.getPreloadEnabled() ?? true;\n }, [auth]);\n\n // Extract tokens from session\n const idToken = session?.idToken;\n const accessToken = session?.accessToken;\n const refreshToken = session?.refreshToken;\n\n // Extract forwardedTokens from session's ID token\n const forwardedTokens = useMemo(() => {\n if (!session) return undefined;\n const tokens = extractTokensFromSession(session);\n return tokens.forwardedTokens;\n }, [session]);\n\n const contextValue: CivicAuthContextType = useMemo(\n () => ({\n auth,\n user,\n session,\n isLoading,\n authStatus,\n error,\n idToken,\n accessToken,\n refreshToken,\n forwardedTokens,\n signIn,\n signOut,\n isAuthenticationPreloaded,\n setPreloadEnabled,\n getPreloadEnabled,\n displayMode,\n }),\n [\n auth,\n user,\n session,\n isLoading,\n authStatus,\n error,\n idToken,\n accessToken,\n refreshToken,\n forwardedTokens,\n signIn,\n signOut,\n isAuthenticationPreloaded,\n setPreloadEnabled,\n getPreloadEnabled,\n displayMode,\n ],\n );\n\n return (\n <CivicAuthContext.Provider value={contextValue}>\n {children}\n </CivicAuthContext.Provider>\n );\n};\n\nexport const useCivicAuthContext = (): CivicAuthContextType => {\n const context = useContext(CivicAuthContext);\n if (!context) {\n throw new Error(\n \"useCivicAuthContext must be used within a CivicAuthContextProvider\",\n );\n }\n return context;\n};\n\nexport { CivicAuthContext };\n"]}
@@ -18,6 +18,7 @@ export interface CivicAuthProviderProps {
18
18
  authProcessTimeout?: number;
19
19
  preloadIframe?: boolean;
20
20
  logging?: LoggingConfig;
21
+ autoRedirect?: boolean;
21
22
  }
22
23
  declare const CivicAuthProvider: React.FC<CivicAuthProviderProps>;
23
24
  export { CivicAuthProvider };
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAKzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAkEvD,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"CivicAuthProvider.d.ts","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoB,MAAM,OAAO,CAAC;AAKzC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAC9C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qCAAqC,CAAC;AAEzE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAClC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,KAAK,KAAK,IAAI,CAAC;IACnC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,QAAA,MAAM,iBAAiB,EAAE,KAAK,CAAC,EAAE,CAAC,sBAAsB,CAqEvD,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC"}
@@ -2,7 +2,7 @@
2
2
  import { Fragment as _Fragment, jsx as _jsx } from "@emotion/react/jsx-runtime";
3
3
  import React, { useEffect } from "react";
4
4
  import { GlobalAuthManager, } from "../core/GlobalAuthManager.js";
5
- const CivicAuthProvider = ({ children, clientId, redirectUrl, config, scopes, displayMode = "iframe", iframeMode = "modal", onSignIn, onSignOut, nonce, logoutRedirectUrl, authProcessTimeout, preloadIframe, logging, }) => {
5
+ const CivicAuthProvider = ({ children, clientId, redirectUrl, config, scopes, displayMode = "iframe", iframeMode = "modal", onSignIn, onSignOut, nonce, logoutRedirectUrl, authProcessTimeout, preloadIframe, logging, autoRedirect = true, }) => {
6
6
  // Initialize GlobalAuthManager with the provider config
7
7
  useEffect(() => {
8
8
  const globalConfig = {
@@ -21,6 +21,7 @@ const CivicAuthProvider = ({ children, clientId, redirectUrl, config, scopes, di
21
21
  onSignIn,
22
22
  onSignOut,
23
23
  logging,
24
+ autoRedirect,
24
25
  framework: "reactjs",
25
26
  };
26
27
  const manager = GlobalAuthManager.getInstance();
@@ -47,6 +48,7 @@ const CivicAuthProvider = ({ children, clientId, redirectUrl, config, scopes, di
47
48
  onSignIn,
48
49
  onSignOut,
49
50
  logging,
51
+ autoRedirect,
50
52
  ]);
51
53
  // Just render children - no context provider needed
52
54
  return _jsx(_Fragment, { children: children });
@@ -1 +1 @@
1
- {"version":3,"file":"CivicAuthProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EACL,iBAAiB,GAElB,MAAM,8BAA8B,CAAC;AAuBtC,MAAM,iBAAiB,GAAqC,CAAC,EAC3D,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,MAAM,EACN,MAAM,EACN,WAAW,GAAG,QAAQ,EACtB,UAAU,GAAG,OAAO,EACpB,QAAQ,EACR,SAAS,EACT,KAAK,EACL,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,OAAO,GACR,EAAE,EAAE;IACH,wDAAwD;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAqB;YACrC,QAAQ;YACR,WAAW;YACX,MAAM,EAAE;gBACN,WAAW,EAAE,MAAM,EAAE,WAAW;aACjC;YACD,MAAM;YACN,WAAW;YACX,UAAU;YACV,KAAK;YACL,iBAAiB;YACjB,kBAAkB;YAClB,aAAa;YACb,QAAQ;YACR,SAAS;YACT,OAAO;YACP,SAAS,EAAE,SAAS;SACrB,CAAC;QAEF,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,EAAE,CAAC;QAEhD,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;YAChC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,KAAK,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC,CAAC;QAEF,cAAc,EAAE,CAAC;IACnB,CAAC,EAAE;QACD,QAAQ;QACR,WAAW;QACX,MAAM,EAAE,WAAW;QACnB,MAAM;QACN,WAAW;QACX,UAAU;QACV,KAAK;QACL,iBAAiB;QACjB,kBAAkB;QAClB,aAAa;QACb,QAAQ;QACR,SAAS;QACT,OAAO;KACR,CAAC,CAAC;IAEH,oDAAoD;IACpD,OAAO,4BAAG,QAAQ,GAAI,CAAC;AACzB,CAAC,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["\"use client\";\nimport React, { useEffect } from \"react\";\nimport {\n GlobalAuthManager,\n type GlobalAuthConfig,\n} from \"../core/GlobalAuthManager.js\";\nimport type { DisplayMode } from \"@/types.js\";\nimport type { LoggingConfig } from \"@/vanillajs/auth/types/AuthTypes.js\";\n\nexport interface CivicAuthProviderProps {\n children: React.ReactNode;\n clientId: string;\n redirectUrl?: string;\n config?: {\n oauthServer?: string;\n };\n scopes?: string[];\n displayMode?: DisplayMode;\n iframeMode?: \"modal\" | \"embedded\";\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n nonce?: string;\n logoutRedirectUrl?: string;\n authProcessTimeout?: number;\n preloadIframe?: boolean;\n logging?: LoggingConfig;\n}\n\nconst CivicAuthProvider: React.FC<CivicAuthProviderProps> = ({\n children,\n clientId,\n redirectUrl,\n config,\n scopes,\n displayMode = \"iframe\",\n iframeMode = \"modal\",\n onSignIn,\n onSignOut,\n nonce,\n logoutRedirectUrl,\n authProcessTimeout,\n preloadIframe,\n logging,\n}) => {\n // Initialize GlobalAuthManager with the provider config\n useEffect(() => {\n const globalConfig: GlobalAuthConfig = {\n clientId,\n redirectUrl,\n config: {\n oauthServer: config?.oauthServer,\n },\n scopes,\n displayMode,\n iframeMode,\n nonce,\n logoutRedirectUrl,\n authProcessTimeout,\n preloadIframe,\n onSignIn,\n onSignOut,\n logging,\n framework: \"reactjs\",\n };\n\n const manager = GlobalAuthManager.getInstance();\n\n const initializeAuth = async () => {\n try {\n await manager.initialize(globalConfig);\n } catch (error) {\n console.error(\"Failed to initialize auth in CivicAuthProvider:\", error);\n }\n };\n\n initializeAuth();\n }, [\n clientId,\n redirectUrl,\n config?.oauthServer,\n scopes,\n displayMode,\n iframeMode,\n nonce,\n logoutRedirectUrl,\n authProcessTimeout,\n preloadIframe,\n onSignIn,\n onSignOut,\n logging,\n ]);\n\n // Just render children - no context provider needed\n return <>{children}</>;\n};\n\nexport { CivicAuthProvider };\n"]}
1
+ {"version":3,"file":"CivicAuthProvider.js","sourceRoot":"","sources":["../../../src/reactjs/providers/CivicAuthProvider.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AACb,OAAO,KAAK,EAAE,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACzC,OAAO,EACL,iBAAiB,GAElB,MAAM,8BAA8B,CAAC;AAwBtC,MAAM,iBAAiB,GAAqC,CAAC,EAC3D,QAAQ,EACR,QAAQ,EACR,WAAW,EACX,MAAM,EACN,MAAM,EACN,WAAW,GAAG,QAAQ,EACtB,UAAU,GAAG,OAAO,EACpB,QAAQ,EACR,SAAS,EACT,KAAK,EACL,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,OAAO,EACP,YAAY,GAAG,IAAI,GACpB,EAAE,EAAE;IACH,wDAAwD;IACxD,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,YAAY,GAAqB;YACrC,QAAQ;YACR,WAAW;YACX,MAAM,EAAE;gBACN,WAAW,EAAE,MAAM,EAAE,WAAW;aACjC;YACD,MAAM;YACN,WAAW;YACX,UAAU;YACV,KAAK;YACL,iBAAiB;YACjB,kBAAkB;YAClB,aAAa;YACb,QAAQ;YACR,SAAS;YACT,OAAO;YACP,YAAY;YACZ,SAAS,EAAE,SAAS;SACrB,CAAC;QAEF,MAAM,OAAO,GAAG,iBAAiB,CAAC,WAAW,EAAE,CAAC;QAEhD,MAAM,cAAc,GAAG,KAAK,IAAI,EAAE;YAChC,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;YACzC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,KAAK,CAAC,iDAAiD,EAAE,KAAK,CAAC,CAAC;YAC1E,CAAC;QACH,CAAC,CAAC;QAEF,cAAc,EAAE,CAAC;IACnB,CAAC,EAAE;QACD,QAAQ;QACR,WAAW;QACX,MAAM,EAAE,WAAW;QACnB,MAAM;QACN,WAAW;QACX,UAAU;QACV,KAAK;QACL,iBAAiB;QACjB,kBAAkB;QAClB,aAAa;QACb,QAAQ;QACR,SAAS;QACT,OAAO;QACP,YAAY;KACb,CAAC,CAAC;IAEH,oDAAoD;IACpD,OAAO,4BAAG,QAAQ,GAAI,CAAC;AACzB,CAAC,CAAC;AAEF,OAAO,EAAE,iBAAiB,EAAE,CAAC","sourcesContent":["\"use client\";\nimport React, { useEffect } from \"react\";\nimport {\n GlobalAuthManager,\n type GlobalAuthConfig,\n} from \"../core/GlobalAuthManager.js\";\nimport type { DisplayMode } from \"@/types.js\";\nimport type { LoggingConfig } from \"@/vanillajs/auth/types/AuthTypes.js\";\n\nexport interface CivicAuthProviderProps {\n children: React.ReactNode;\n clientId: string;\n redirectUrl?: string;\n config?: {\n oauthServer?: string;\n };\n scopes?: string[];\n displayMode?: DisplayMode;\n iframeMode?: \"modal\" | \"embedded\";\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n nonce?: string;\n logoutRedirectUrl?: string;\n authProcessTimeout?: number;\n preloadIframe?: boolean;\n logging?: LoggingConfig;\n autoRedirect?: boolean;\n}\n\nconst CivicAuthProvider: React.FC<CivicAuthProviderProps> = ({\n children,\n clientId,\n redirectUrl,\n config,\n scopes,\n displayMode = \"iframe\",\n iframeMode = \"modal\",\n onSignIn,\n onSignOut,\n nonce,\n logoutRedirectUrl,\n authProcessTimeout,\n preloadIframe,\n logging,\n autoRedirect = true,\n}) => {\n // Initialize GlobalAuthManager with the provider config\n useEffect(() => {\n const globalConfig: GlobalAuthConfig = {\n clientId,\n redirectUrl,\n config: {\n oauthServer: config?.oauthServer,\n },\n scopes,\n displayMode,\n iframeMode,\n nonce,\n logoutRedirectUrl,\n authProcessTimeout,\n preloadIframe,\n onSignIn,\n onSignOut,\n logging,\n autoRedirect,\n framework: \"reactjs\",\n };\n\n const manager = GlobalAuthManager.getInstance();\n\n const initializeAuth = async () => {\n try {\n await manager.initialize(globalConfig);\n } catch (error) {\n console.error(\"Failed to initialize auth in CivicAuthProvider:\", error);\n }\n };\n\n initializeAuth();\n }, [\n clientId,\n redirectUrl,\n config?.oauthServer,\n scopes,\n displayMode,\n iframeMode,\n nonce,\n logoutRedirectUrl,\n authProcessTimeout,\n preloadIframe,\n onSignIn,\n onSignOut,\n logging,\n autoRedirect,\n ]);\n\n // Just render children - no context provider needed\n return <>{children}</>;\n};\n\nexport { CivicAuthProvider };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ServerAuthenticationResolver.d.ts","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAUrD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,qBAAqB,CAAC;AAOhF,qBAAa,4BAA6B,YAAW,sBAAsB;IAMvE,QAAQ,CAAC,UAAU,EAAE,UAAU;IAC/B,QAAQ,CAAC,OAAO,EAAE,WAAW;IAC7B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IAPjD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO;IAeP;;;;OAIG;IACG,gBAAgB,CACpB,WAAW,EAAE,WAAW,GAAG,IAAI,GAC9B,OAAO,CAAC,WAAW,CAAC;IA+DvB;;;OAGG;IACG,uBAAuB,CAAC,WAAW,UAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAmDvE,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAkBrB,aAAa,CACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,CAAC;IA4B3B,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc7C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;WAOxC,KAAK,CAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GACrC,OAAO,CAAC,sBAAsB,CAAC;CAUnC"}
1
+ {"version":3,"file":"ServerAuthenticationResolver.d.ts","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,qBAAqB,EACrB,WAAW,EACZ,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAUrD,OAAO,KAAK,EAAE,sBAAsB,EAAgB,MAAM,qBAAqB,CAAC;AAOhF,qBAAa,4BAA6B,YAAW,sBAAsB;IAMvE,QAAQ,CAAC,UAAU,EAAE,UAAU;IAC/B,QAAQ,CAAC,OAAO,EAAE,WAAW;IAC7B,QAAQ,CAAC,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC;IAPjD,OAAO,CAAC,YAAY,CAAsB;IAC1C,OAAO,CAAC,YAAY,CAA2B;IAC/C,OAAO,CAAC,SAAS,CAAwB;IAEzC,OAAO;IAeP;;;;OAIG;IACG,gBAAgB,CACpB,WAAW,EAAE,WAAW,GAAG,IAAI,GAC9B,OAAO,CAAC,WAAW,CAAC;IA+DvB;;;OAGG;IACG,uBAAuB,CAAC,WAAW,UAAO,GAAG,OAAO,CAAC,WAAW,CAAC;IAmDvE,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAuBrB,aAAa,CACjB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,CAAC;IA4B3B,cAAc,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAc7C,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;WAOxC,KAAK,CAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,WAAW,EACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GACrC,OAAO,CAAC,sBAAsB,CAAC;CAUnC"}
@@ -125,6 +125,10 @@ export class ServerAuthenticationResolver {
125
125
  return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;
126
126
  }
127
127
  async init() {
128
+ // Ensure clientId is present for OAuth operations
129
+ if (!this.authConfig.clientId) {
130
+ throw new Error("clientId is required for OAuth server operations");
131
+ }
128
132
  // resolve oauth config
129
133
  this.endpoints = await getEndpointsWithOverrides(this.oauthServer, this.endpointOverrides);
130
134
  this.oauth2client = new OAuth2Client(this.authConfig.clientId, this.endpoints.auth, this.endpoints.token, {
@@ -1 +1 @@
1
- {"version":3,"file":"ServerAuthenticationResolver.js","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport type {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeServerTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport type { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { loggers } from \"@/lib/logger.js\";\n\nconst logger = loggers.services.validation;\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer | null;\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n readonly authConfig: AuthConfig,\n readonly storage: AuthStorage,\n readonly endpointOverrides?: Partial<Endpoints>,\n ) {\n // Determine if PKCE should be used based on config\n // Default to true\n const usePkce = authConfig.pkce !== false;\n\n // Only create PKCE producer if we're using PKCE\n this.pkceProducer = usePkce\n ? new GenericPublicClientPKCEProducer(storage)\n : null;\n }\n\n /**\n * Attempts to refresh tokens if a refresh token is available\n * @param sessionData Current session data\n * @returns Updated session data\n */\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n logger.debug(\"tryRefreshTokens\", { sessionData });\n // If there's a refresh token, attempt to refresh tokens\n if (sessionData?.refreshToken) {\n try {\n // Only attempt refresh if we have necessary components\n if (!this.oauth2client || !this.endpoints?.jwks) {\n await this.init();\n }\n\n if (!this.oauth2client || !this.endpoints?.jwks) {\n throw new Error(\n \"Failed to initialize OAuth client for token refresh\",\n );\n }\n\n // Use the oauth2client to refresh the access token\n const refreshOptions: Record<string, string> = {};\n if (this.authConfig.clientSecret) {\n refreshOptions.credentials = this.authConfig.clientSecret;\n refreshOptions.authenticateWith = \"request_body\";\n }\n\n const tokenResponseBody = (await this.oauth2client.refreshAccessToken(\n sessionData.refreshToken,\n refreshOptions,\n )) as OIDCTokenResponseBody;\n\n if (!tokenResponseBody) {\n throw new Error(\"Failed to get token response from refresh\");\n }\n\n // Validate the refreshed tokens\n await validateOauth2Tokens(\n tokenResponseBody,\n this.endpoints.jwks,\n this.oauth2client,\n this.oauthServer,\n );\n\n // Store the refreshed tokens\n await storeServerTokens(this.storage, tokenResponseBody);\n\n // Construct a refreshed session with the new tokens\n return {\n authenticated: true,\n idToken: tokenResponseBody.id_token,\n accessToken: tokenResponseBody.access_token,\n refreshToken: tokenResponseBody.refresh_token,\n oidcSessionExpiresAt: tokenResponseBody.oidc_session_expires_at,\n };\n } catch (error) {\n logger.warn(\"Failed to refresh tokens\", error);\n await clearTokens(this.storage);\n await clearUser(this.storage);\n return { ...sessionData, authenticated: false };\n }\n }\n\n // No refresh token available\n return { ...sessionData, authenticated: false };\n }\n\n /**\n * returns The session data if the session is valid, otherwise an unauthenticated session\n * @returns {Promise<SessionData>}\n */\n async validateExistingSession(autoRefresh = true): Promise<SessionData> {\n // TODO: investigate a more peformant way to validate a server session\n // other than using JWKS and JWT verification which is what validateOauth2Tokens uses\n const sessionData = await this.getSessionData();\n\n // If we don't have an ID token, try to refresh if we have a refresh token\n // Access token is no longer required for authentication\n if (!sessionData?.idToken) {\n if (autoRefresh) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n }\n return { ...sessionData, authenticated: false };\n }\n\n // Initialize if needed\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"JWKS endpoint not found\");\n }\n\n try {\n // Validate existing tokens - access token validation happens only if it exists\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken, // May be undefined\n id_token: sessionData.idToken, // Always required\n refresh_token: sessionData.refreshToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.endpoints.jwks,\n this.oauth2client!,\n this.oauthServer,\n );\n return sessionData;\n } catch (error) {\n logger.warn(\"Error validating tokens\", { error, autoRefresh });\n if (autoRefresh) {\n // If token validation fails, try to refresh tokens\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n }\n return { ...sessionData, authenticated: false };\n }\n }\n\n get oauthServer(): string {\n return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n\n // Check if we're using PKCE and validate code verifier if needed\n if (this.pkceProducer) {\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n }\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n this.authConfig.clientSecret,\n );\n\n await storeServerTokens(this.storage, tokens);\n // the code verifier should be single-use, so we delete it if using PKCE\n if (this.pkceProducer) {\n await this.storage.delete(CodeVerifier.COOKIE_NAME);\n }\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token, // User is authenticated if they have an ID token\n idToken: storageData.id_token,\n accessToken: storageData.access_token, // Optional\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints.endsession;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationResolver> {\n const resolver = new ServerAuthenticationResolver(\n authConfig,\n storage,\n endpointOverrides,\n );\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
1
+ {"version":3,"file":"ServerAuthenticationResolver.js","sourceRoot":"","sources":["../../src/server/ServerAuthenticationResolver.ts"],"names":[],"mappings":"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","sourcesContent":["import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport type {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport type { AuthConfig } from \"@/server/config.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeServerTokens,\n validateOauth2Tokens,\n} from \"@/shared/lib/util.js\";\nimport type { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\nimport { DEFAULT_AUTH_SERVER } from \"@/constants.js\";\nimport { CodeVerifier } from \"@/shared/lib/types.js\";\nimport { loggers } from \"@/lib/logger.js\";\n\nconst logger = loggers.services.validation;\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer | null;\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n readonly authConfig: AuthConfig,\n readonly storage: AuthStorage,\n readonly endpointOverrides?: Partial<Endpoints>,\n ) {\n // Determine if PKCE should be used based on config\n // Default to true\n const usePkce = authConfig.pkce !== false;\n\n // Only create PKCE producer if we're using PKCE\n this.pkceProducer = usePkce\n ? new GenericPublicClientPKCEProducer(storage)\n : null;\n }\n\n /**\n * Attempts to refresh tokens if a refresh token is available\n * @param sessionData Current session data\n * @returns Updated session data\n */\n async tryRefreshTokens(\n sessionData: SessionData | null,\n ): Promise<SessionData> {\n logger.debug(\"tryRefreshTokens\", { sessionData });\n // If there's a refresh token, attempt to refresh tokens\n if (sessionData?.refreshToken) {\n try {\n // Only attempt refresh if we have necessary components\n if (!this.oauth2client || !this.endpoints?.jwks) {\n await this.init();\n }\n\n if (!this.oauth2client || !this.endpoints?.jwks) {\n throw new Error(\n \"Failed to initialize OAuth client for token refresh\",\n );\n }\n\n // Use the oauth2client to refresh the access token\n const refreshOptions: Record<string, string> = {};\n if (this.authConfig.clientSecret) {\n refreshOptions.credentials = this.authConfig.clientSecret;\n refreshOptions.authenticateWith = \"request_body\";\n }\n\n const tokenResponseBody = (await this.oauth2client.refreshAccessToken(\n sessionData.refreshToken,\n refreshOptions,\n )) as OIDCTokenResponseBody;\n\n if (!tokenResponseBody) {\n throw new Error(\"Failed to get token response from refresh\");\n }\n\n // Validate the refreshed tokens\n await validateOauth2Tokens(\n tokenResponseBody,\n this.endpoints.jwks,\n this.oauth2client,\n this.oauthServer,\n );\n\n // Store the refreshed tokens\n await storeServerTokens(this.storage, tokenResponseBody);\n\n // Construct a refreshed session with the new tokens\n return {\n authenticated: true,\n idToken: tokenResponseBody.id_token,\n accessToken: tokenResponseBody.access_token,\n refreshToken: tokenResponseBody.refresh_token,\n oidcSessionExpiresAt: tokenResponseBody.oidc_session_expires_at,\n };\n } catch (error) {\n logger.warn(\"Failed to refresh tokens\", error);\n await clearTokens(this.storage);\n await clearUser(this.storage);\n return { ...sessionData, authenticated: false };\n }\n }\n\n // No refresh token available\n return { ...sessionData, authenticated: false };\n }\n\n /**\n * returns The session data if the session is valid, otherwise an unauthenticated session\n * @returns {Promise<SessionData>}\n */\n async validateExistingSession(autoRefresh = true): Promise<SessionData> {\n // TODO: investigate a more peformant way to validate a server session\n // other than using JWKS and JWT verification which is what validateOauth2Tokens uses\n const sessionData = await this.getSessionData();\n\n // If we don't have an ID token, try to refresh if we have a refresh token\n // Access token is no longer required for authentication\n if (!sessionData?.idToken) {\n if (autoRefresh) {\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n }\n return { ...sessionData, authenticated: false };\n }\n\n // Initialize if needed\n if (!this.endpoints?.jwks || !this.oauth2client) await this.init();\n\n if (!this.endpoints?.jwks) {\n throw new Error(\"JWKS endpoint not found\");\n }\n\n try {\n // Validate existing tokens - access token validation happens only if it exists\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken, // May be undefined\n id_token: sessionData.idToken, // Always required\n refresh_token: sessionData.refreshToken,\n oidc_session_expires_at: sessionData.oidcSessionExpiresAt,\n },\n this.endpoints.jwks,\n this.oauth2client!,\n this.oauthServer,\n );\n return sessionData;\n } catch (error) {\n logger.warn(\"Error validating tokens\", { error, autoRefresh });\n if (autoRefresh) {\n // If token validation fails, try to refresh tokens\n const refreshedSessionData = await this.tryRefreshTokens(sessionData);\n if (refreshedSessionData.authenticated) {\n return refreshedSessionData;\n }\n }\n return { ...sessionData, authenticated: false };\n }\n }\n\n get oauthServer(): string {\n return this.authConfig.oauthServer || DEFAULT_AUTH_SERVER;\n }\n\n async init(): Promise<this> {\n // Ensure clientId is present for OAuth operations\n if (!this.authConfig.clientId) {\n throw new Error(\"clientId is required for OAuth server operations\");\n }\n\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.oauthServer,\n this.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.authConfig.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.authConfig.redirectUrl,\n },\n );\n\n return this;\n }\n\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n\n // Check if we're using PKCE and validate code verifier if needed\n if (this.pkceProducer) {\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\n }\n\n // exchange auth code for tokens\n const tokens = await exchangeTokens(\n code,\n state,\n this.pkceProducer,\n this.oauth2client!, // clean up types here to avoid the ! operator\n this.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n this.authConfig.clientSecret,\n );\n\n await storeServerTokens(this.storage, tokens);\n // the code verifier should be single-use, so we delete it if using PKCE\n if (this.pkceProducer) {\n await this.storage.delete(CodeVerifier.COOKIE_NAME);\n }\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = await retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token, // User is authenticated if they have an ID token\n idToken: storageData.id_token,\n accessToken: storageData.access_token, // Optional\n refreshToken: storageData.refresh_token,\n oidcSessionExpiresAt: storageData.oidc_session_expires_at,\n };\n }\n\n async getEndSessionEndpoint(): Promise<string | null> {\n if (!this.endpoints) {\n return null;\n }\n return this.endpoints.endsession;\n }\n\n static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<AuthenticationResolver> {\n const resolver = new ServerAuthenticationResolver(\n authConfig,\n storage,\n endpointOverrides,\n );\n await resolver.init();\n\n return resolver;\n }\n}\n"]}
@@ -12,7 +12,6 @@ export interface BackendEndpoints {
12
12
  user?: string;
13
13
  }
14
14
  export type AuthConfig = {
15
- clientId: string;
16
15
  clientSecret?: string;
17
16
  pkce?: boolean;
18
17
  redirectUrl: string;
@@ -21,7 +20,6 @@ export type AuthConfig = {
21
20
  refreshUrl?: string;
22
21
  endpointOverrides?: Partial<Endpoints> | undefined;
23
22
  postLogoutRedirectUrl?: string;
24
- loginUrl?: string;
25
23
  /**
26
24
  * Custom backend endpoints configuration for backend integration
27
25
  * Only used when loginUrl is provided. Allows overriding default endpoints.
@@ -56,5 +54,15 @@ export type AuthConfig = {
56
54
  * Useful for testing environments like Cypress where iframe detection may interfere with expected redirects.
57
55
  */
58
56
  disableIframeDetection?: boolean;
59
- };
57
+ } & ({
58
+ /** OAuth client ID - required for standard OAuth flow */
59
+ clientId: string;
60
+ /** Custom login URL for backend integration - optional */
61
+ loginUrl?: string;
62
+ } | {
63
+ /** OAuth client ID - optional when using backend integration */
64
+ clientId?: string;
65
+ /** Custom login URL for backend integration - required when clientId is not provided */
66
+ loginUrl: string;
67
+ });
60
68
  //# sourceMappingURL=config.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;IACnD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;QACrC,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF;;OAEG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C;;;GAGG;AACH,MAAM,WAAW,gBAAgB;IAC/B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oDAAoD;IACpD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GAAG;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,OAAO,CAAC,SAAS,CAAC,GAAG,SAAS,CAAC;IACnD,qBAAqB,CAAC,EAAE,MAAM,CAAC;IAC/B;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;OAEG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC;QACrC,WAAW,CAAC,EAAE,OAAO,CAAC;QACtB,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;QAC1B,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF;;OAEG;IACH,MAAM,CAAC,EAAE;QACP,OAAO,CAAC,EAAE,OAAO,CAAC;KACnB,CAAC;IACF;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,GAAG,CACA;IACE,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,GACD;IACE,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC;CAClB,CACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"","sourcesContent":["import type { Endpoints } from \"@/types.ts\";\n\n/**\n * Configuration for backend authentication endpoints\n * Allows customization of API endpoints when using backend integration (loginUrl)\n */\nexport interface BackendEndpoints {\n /** Endpoint for token refresh (default: \"/auth/refresh\") */\n refresh?: string;\n /** Endpoint for logout (default: \"/auth/logout\") */\n logout?: string;\n /** Endpoint for user info and session validation (default: \"/auth/user\") */\n user?: string;\n}\n\nexport type AuthConfig = {\n clientId: string;\n clientSecret?: string; // Optional client secret for confidential clients\n pkce?: boolean; // Optional PKCE flag, defaults to true if not specified\n redirectUrl: string;\n oauthServer?: string;\n challengeUrl?: string;\n refreshUrl?: string;\n endpointOverrides?: Partial<Endpoints> | undefined;\n postLogoutRedirectUrl?: string;\n loginUrl?: string;\n /**\n * Custom backend endpoints configuration for backend integration\n * Only used when loginUrl is provided. Allows overriding default endpoints.\n */\n backendEndpoints?: BackendEndpoints;\n /**\n * Optional URL to redirect frontend clients back to after successful authentication.\n * When provided, the backend will automatically redirect SPA clients to this URL\n * instead of traditional server-side redirects. Useful for backend + frontend integration.\n * Example: \"http://localhost:5173\" or \"https://your-spa.com\"\n */\n loginSuccessUrl?: string;\n /**\n * Optional CORS configuration for authentication endpoints\n */\n cors?: {\n origin?: string | string[] | boolean;\n credentials?: boolean;\n optionsSuccessStatus?: number;\n allowedHeaders?: string[];\n exposedHeaders?: string[];\n };\n /**\n * Optional logger configuration for authentication middleware\n */\n logger?: {\n enabled?: boolean; // Defaults to true if not specified\n };\n /**\n * Optional flag to disable iframe detection in handleCallback.\n * When true, callbacks will always attempt to redirect instead of returning HTML content for iframes.\n * Useful for testing environments like Cypress where iframe detection may interfere with expected redirects.\n */\n disableIframeDetection?: boolean;\n};\n"]}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/server/config.ts"],"names":[],"mappings":"","sourcesContent":["import type { Endpoints } from \"@/types.ts\";\n\n/**\n * Configuration for backend authentication endpoints\n * Allows customization of API endpoints when using backend integration (loginUrl)\n */\nexport interface BackendEndpoints {\n /** Endpoint for token refresh (default: \"/auth/refresh\") */\n refresh?: string;\n /** Endpoint for logout (default: \"/auth/logout\") */\n logout?: string;\n /** Endpoint for user info and session validation (default: \"/auth/user\") */\n user?: string;\n}\n\nexport type AuthConfig = {\n clientSecret?: string; // Optional client secret for confidential clients\n pkce?: boolean; // Optional PKCE flag, defaults to true if not specified\n redirectUrl: string;\n oauthServer?: string;\n challengeUrl?: string;\n refreshUrl?: string;\n endpointOverrides?: Partial<Endpoints> | undefined;\n postLogoutRedirectUrl?: string;\n /**\n * Custom backend endpoints configuration for backend integration\n * Only used when loginUrl is provided. Allows overriding default endpoints.\n */\n backendEndpoints?: BackendEndpoints;\n /**\n * Optional URL to redirect frontend clients back to after successful authentication.\n * When provided, the backend will automatically redirect SPA clients to this URL\n * instead of traditional server-side redirects. Useful for backend + frontend integration.\n * Example: \"http://localhost:5173\" or \"https://your-spa.com\"\n */\n loginSuccessUrl?: string;\n /**\n * Optional CORS configuration for authentication endpoints\n */\n cors?: {\n origin?: string | string[] | boolean;\n credentials?: boolean;\n optionsSuccessStatus?: number;\n allowedHeaders?: string[];\n exposedHeaders?: string[];\n };\n /**\n * Optional logger configuration for authentication middleware\n */\n logger?: {\n enabled?: boolean; // Defaults to true if not specified\n };\n /**\n * Optional flag to disable iframe detection in handleCallback.\n * When true, callbacks will always attempt to redirect instead of returning HTML content for iframes.\n * Useful for testing environments like Cypress where iframe detection may interfere with expected redirects.\n */\n disableIframeDetection?: boolean;\n} & (\n | {\n /** OAuth client ID - required for standard OAuth flow */\n clientId: string;\n /** Custom login URL for backend integration - optional */\n loginUrl?: string;\n }\n | {\n /** OAuth client ID - optional when using backend integration */\n clientId?: string;\n /** Custom login URL for backend integration - required when clientId is not provided */\n loginUrl: string;\n }\n);\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/server/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,qBAAqB,EACrB,aAAa,EACd,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAEvE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,GAAG,cAAc,CAAC,CAAC,GAAG;IACnE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,EACH,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,GAAG,CAAC,CAsCd"}
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/server/login.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,qBAAqB,EACrB,aAAa,EACd,MAAM,YAAY,CAAC;AAKpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAGrD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,qBAAqB,CAAC,CAWhC;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,OAAO,CAAC,CAEvE;AAED,wBAAsB,aAAa,CACjC,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,aAAa,CAAC,GAClD,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,GAAG,MAAM,GAAG,cAAc,CAAC,CAAC,GAAG;IACnE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,EACH,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,GAAG,CAAC,CA4Cd"}
@@ -44,8 +44,13 @@ export async function buildLoginUrl(config, storage) {
44
44
  const usePkce = config.pkce !== false;
45
45
  // Only create PKCE producer if we're using PKCE and have storage
46
46
  const pkceProducer = usePkce && storage ? new GenericPublicClientPKCEProducer(storage) : null;
47
+ // Ensure clientId is present for OAuth operations
48
+ if (!config.clientId) {
49
+ throw new Error("clientId is required for OAuth login operations");
50
+ }
47
51
  const authInitiator = new GenericAuthenticationInitiator({
48
52
  ...config,
53
+ clientId: config.clientId,
49
54
  state,
50
55
  scopes,
51
56
  oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,
@@ -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;AAY/C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAY,EACZ,KAAa,EACb,OAAoB,EACpB,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,MAAM,aAAa,GAAG,IAAI,8BAA8B,CAAC;QACvD,GAAG,MAAM;QACT,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\";\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: AuthStorage,\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 const authInitiator = new GenericAuthenticationInitiator({\n ...config,\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"]}
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;AAY/C;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,IAAY,EACZ,KAAa,EACb,OAAoB,EACpB,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\";\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: AuthStorage,\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"]}
@@ -1 +1 @@
1
- {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/server/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,uBAAuB,CAAC,GAC5D,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,GAAG;IACzC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,EACH,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,GAAG,CAAC,CAkBd"}
1
+ {"version":3,"file":"logout.d.ts","sourceRoot":"","sources":["../../src/server/logout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAM9C,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,IAAI,CAAC,UAAU,EAAE,UAAU,GAAG,uBAAuB,CAAC,GAC5D,OAAO,CAAC,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAC,GAAG;IACzC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,EACH,OAAO,EAAE,WAAW,GACnB,OAAO,CAAC,GAAG,CAAC,CAwBd"}
@@ -3,12 +3,17 @@ import { GenericPublicClientPKCEProducer } from "../services/PKCE.js";
3
3
  import { GenericAuthenticationInitiator } from "../services/AuthenticationService.js";
4
4
  import { OAuthTokenTypes } from "../shared/lib/types.js";
5
5
  export async function buildLogoutRedirectUrl(config, storage) {
6
+ // Ensure clientId is present for OAuth operations
7
+ if (!config.clientId) {
8
+ throw new Error("clientId is required for OAuth logout operations");
9
+ }
6
10
  // generate a random state if not provided
7
11
  const state = config.state ?? Math.random().toString(36).substring(2);
8
12
  const scopes = config.scopes ?? DEFAULT_SCOPES;
9
13
  const pkceProducer = new GenericPublicClientPKCEProducer(storage);
10
14
  const authInitiator = new GenericAuthenticationInitiator({
11
15
  ...config,
16
+ clientId: config.clientId,
12
17
  state,
13
18
  scopes,
14
19
  oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,
@@ -1 +1 @@
1
- {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/server/logout.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAIG,EACH,OAAoB;IAEpB,0CAA0C;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,cAAc,CAAC;IAC/C,MAAM,YAAY,GAAG,IAAI,+BAA+B,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,aAAa,GAAG,IAAI,8BAA8B,CAAC;QACvD,GAAG,MAAM;QACT,KAAK;QACL,MAAM;QACN,WAAW,EAAE,MAAM,CAAC,WAAW,IAAI,mBAAmB;QACtD,YAAY,EAAE,YAAY;QAC1B,WAAW,EAAE,MAAM,CAAC,qBAAqB,IAAI,GAAG;KACjD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5D,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE9D,OAAO,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC","sourcesContent":["import type { AuthConfig } from \"@/server/config.js\";\nimport type { AuthStorage } from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from \"@/constants.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { GenericAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { OAuthTokenTypes } from \"@/shared/lib/types.js\";\n\nexport async function buildLogoutRedirectUrl(\n config: Pick<AuthConfig, \"clientId\" | \"postLogoutRedirectUrl\"> &\n Partial<Pick<AuthConfig, \"oauthServer\">> & {\n scopes?: string[];\n state?: string;\n },\n storage: AuthStorage,\n): Promise<URL> {\n // generate a random state if not provided\n const state = config.state ?? Math.random().toString(36).substring(2);\n const scopes = config.scopes ?? DEFAULT_SCOPES;\n const pkceProducer = new GenericPublicClientPKCEProducer(storage);\n const authInitiator = new GenericAuthenticationInitiator({\n ...config,\n state,\n scopes,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n pkceConsumer: pkceProducer,\n redirectUrl: config.postLogoutRedirectUrl || \"/\",\n });\n\n const idToken = await storage.get(OAuthTokenTypes.ID_TOKEN);\n if (!idToken) throw new Error(\"No id_token found in storage\");\n\n return authInitiator.signOut(idToken);\n}\n"]}
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/server/logout.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,oBAAoB,CAAC;AACrE,OAAO,EAAE,8BAA8B,EAAE,MAAM,qCAAqC,CAAC;AACrF,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,MAIG,EACH,OAAoB;IAEpB,kDAAkD;IAClD,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;IACtE,CAAC;IAED,0CAA0C;IAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,cAAc,CAAC;IAC/C,MAAM,YAAY,GAAG,IAAI,+BAA+B,CAAC,OAAO,CAAC,CAAC;IAClE,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,YAAY,EAAE,YAAY;QAC1B,WAAW,EAAE,MAAM,CAAC,qBAAqB,IAAI,GAAG;KACjD,CAAC,CAAC;IAEH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC5D,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;IAE9D,OAAO,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC","sourcesContent":["import type { AuthConfig } from \"@/server/config.js\";\nimport type { AuthStorage } from \"@/types.js\";\nimport { DEFAULT_AUTH_SERVER, DEFAULT_SCOPES } from \"@/constants.js\";\nimport { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { GenericAuthenticationInitiator } from \"@/services/AuthenticationService.js\";\nimport { OAuthTokenTypes } from \"@/shared/lib/types.js\";\n\nexport async function buildLogoutRedirectUrl(\n config: Pick<AuthConfig, \"clientId\" | \"postLogoutRedirectUrl\"> &\n Partial<Pick<AuthConfig, \"oauthServer\">> & {\n scopes?: string[];\n state?: string;\n },\n storage: AuthStorage,\n): Promise<URL> {\n // Ensure clientId is present for OAuth operations\n if (!config.clientId) {\n throw new Error(\"clientId is required for OAuth logout operations\");\n }\n\n // generate a random state if not provided\n const state = config.state ?? Math.random().toString(36).substring(2);\n const scopes = config.scopes ?? DEFAULT_SCOPES;\n const pkceProducer = new GenericPublicClientPKCEProducer(storage);\n const authInitiator = new GenericAuthenticationInitiator({\n ...config,\n clientId: config.clientId,\n state,\n scopes,\n oauthServer: config.oauthServer ?? DEFAULT_AUTH_SERVER,\n pkceConsumer: pkceProducer,\n redirectUrl: config.postLogoutRedirectUrl || \"/\",\n });\n\n const idToken = await storage.get(OAuthTokenTypes.ID_TOKEN);\n if (!idToken) throw new Error(\"No id_token found in storage\");\n\n return authInitiator.signOut(idToken);\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAE3B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAgBrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;QAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,qBAAqB,CAAC;CAC5B,CAAC;AAwCF;;;GAGG;AACH,qBAAa,SAAS;IAGlB,QAAQ,CAAC,OAAO,EAAE,WAAW;IAC7B,QAAQ,CAAC,UAAU,EAAE,UAAU;IAHjC,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAQ;gBAEzC,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,UAAU;IAGjC,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,eAAe,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAaxD;;;OAGG;IACG,OAAO,CACX,CAAC,SAAS,aAAa,GAAG,WAAW,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAkB5B;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAoB9C;;;;;OAKG;IACG,sBAAsB,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,CAAC;IAIjC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAMpC;;;;OAIG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE;QAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,GAAG,CAAC;IAchB;;;;OAIG;IACG,sBAAsB,CAAC,OAAO,CAAC,EAAE;QACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,GAAG,CAAC;IAyChB;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAI5D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACG,cAAc,CAClB,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,oBAAoB,EAC1C,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,GACA,OAAO,CAAC;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;SAAE,CAAC;KAC7D,CAAC;IAyFF;;OAEG;IACH,OAAO,CAAC,4BAA4B;CA0DrC"}
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/server/session.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,IAAI,EACT,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAE3B,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAgBrD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAIlE,MAAM,MAAM,qBAAqB,GAAG;IAClC,OAAO,EAAE;QACP,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC;QAC7C,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;KAC3B,CAAC;CACH,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,qBAAqB,CAAC;CAC5B,CAAC;AAwCF;;;GAGG;AACH,qBAAa,SAAS;IAGlB,QAAQ,CAAC,OAAO,EAAE,WAAW;IAC7B,QAAQ,CAAC,UAAU,EAAE,UAAU;IAHjC,aAAa,EAAE,sBAAsB,GAAG,IAAI,CAAQ;gBAEzC,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,UAAU;IAGjC,IAAI,WAAW,IAAI,MAAM,CAExB;IAEK,eAAe,IAAI,OAAO,CAAC,sBAAsB,CAAC;IAaxD;;;OAGG;IACG,OAAO,CACX,CAAC,SAAS,aAAa,GAAG,WAAW,KAClC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAkB5B;;;OAGG;IACG,SAAS,IAAI,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAoB9C;;;;;OAKG;IACG,sBAAsB,CAC1B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,qBAAqB,CAAC;IAIjC;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAMpC;;;;OAIG;IACG,aAAa,CAAC,OAAO,CAAC,EAAE;QAC5B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,GAAG,CAAC;IAchB;;;;OAIG;IACG,sBAAsB,CAAC,OAAO,CAAC,EAAE;QACrC,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;QAClB,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,GAAG,OAAO,CAAC,GAAG,CAAC;IA8ChB;;;OAGG;IACG,aAAa,IAAI,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC;IAI5D;;OAEG;IACG,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAIlC;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACG,cAAc,CAClB,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,oBAAoB,EAC1C,OAAO,CAAC,EAAE;QACR,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,WAAW,CAAC,EAAE,OAAO,CAAC;KACvB,GACA,OAAO,CAAC;QACT,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,GAAG;YAAE,OAAO,EAAE,OAAO,CAAC;YAAC,IAAI,CAAC,EAAE,IAAI,GAAG,IAAI,CAAA;SAAE,CAAC;KAC7D,CAAC;IAyFF;;OAEG;IACH,OAAO,CAAC,4BAA4B;CA0DrC"}
@@ -150,6 +150,10 @@ export class CivicAuth {
150
150
  // since for logout we just need the raw ID token, not validated tokens
151
151
  const tokens = await getTokensFromShared(this.storage);
152
152
  if (tokens?.idToken) {
153
+ // Ensure clientId is present for OAuth operations
154
+ if (!this.authConfig.clientId) {
155
+ throw new Error("clientId is required for OAuth logout operations");
156
+ }
153
157
  // We have access to the ID token from HTTP-only cookies
154
158
  // Build the logout URL manually using the shared utility
155
159
  const logoutUrl = await generateOauthLogoutUrl({
@@ -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 { 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 } from \"@/lib/oauth.js\";\nimport { decodeJwt, type JWTPayload } from \"jose\";\nimport { generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\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};\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 * 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 // For backend flows with HTTP-only cookies, try to get tokens directly\n // For logout, we don't need valid/authenticated tokens - just the ID token to build logout URL\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 // 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 * 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 // First, resolve the OAuth code and create session\n const tokens = await this.resolveOAuthAccessCode(code, state);\n\n // Extract user info directly from tokens\n const user = getUserFromTokens(tokens);\n\n const frontendUrl = options?.frontendUrl || 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 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 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(user);\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 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(user: User): string {\n const escapedUser = JSON.stringify(user).replace(/'/g, \"\\\\'\");\n const clientId = this.authConfig.clientId;\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 <div style=\"text-align: center; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\">\n <p>Authentication successful! Completing login...</p>\n </div>\n \n <!-- Success signal for SignalObserver -->\n <div id=\"civic-auth-success-signal\" style=\"display: none;\" data-user-info='${escapedUser}'>\n Authentication successful!\n </div>\n \n <script> \n // Send postMessage to parent to resolve authentication promise\n if (window.parent && window.parent !== window) {\n console.log('📤 Sending auth success postMessage to parent');\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 </script>\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 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 { 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 } from \"@/lib/oauth.js\";\nimport { decodeJwt, type JWTPayload } from \"jose\";\nimport { generateOauthLogoutUrl } from \"@/shared/lib/util.js\";\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};\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 * 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 // For backend flows with HTTP-only cookies, try to get tokens directly\n // For logout, we don't need valid/authenticated tokens - just the ID token to build logout URL\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 * 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 // First, resolve the OAuth code and create session\n const tokens = await this.resolveOAuthAccessCode(code, state);\n\n // Extract user info directly from tokens\n const user = getUserFromTokens(tokens);\n\n const frontendUrl = options?.frontendUrl || 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 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 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(user);\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 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(user: User): string {\n const escapedUser = JSON.stringify(user).replace(/'/g, \"\\\\'\");\n const clientId = this.authConfig.clientId;\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 <div style=\"text-align: center; padding: 20px; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;\">\n <p>Authentication successful! Completing login...</p>\n </div>\n \n <!-- Success signal for SignalObserver -->\n <div id=\"civic-auth-success-signal\" style=\"display: none;\" data-user-info='${escapedUser}'>\n Authentication successful!\n </div>\n \n <script> \n // Send postMessage to parent to resolve authentication promise\n if (window.parent && window.parent !== window) {\n console.log('📤 Sending auth success postMessage to parent');\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 </script>\n </body>\n </html>\n `;\n }\n}\n"]}
@@ -19,6 +19,7 @@ export type BrowserAuthenticationInitiatorConfig = Omit<GenericAuthenticationIni
19
19
  basePath?: string;
20
20
  loginSuccessUrl?: string;
21
21
  framework?: FrameworkType;
22
+ autoRedirect?: boolean;
22
23
  };
23
24
  /**
24
25
  * An authentication initiator that works on a browser. Since this is just triggering
@@ -46,6 +47,7 @@ export declare class BrowserAuthenticationInitiator implements AuthenticationIni
46
47
  private postMessageHandler;
47
48
  protected config: BrowserAuthenticationInitiatorConfig;
48
49
  static browserCorsFailsSilentlyRedirectUrl: string;
50
+ private _iframeRef;
49
51
  setDisplayMode(displayMode: DisplayMode): void;
50
52
  get displayMode(): DisplayMode;
51
53
  get isServerTokenExchange(): boolean;
@@ -54,8 +56,12 @@ export declare class BrowserAuthenticationInitiator implements AuthenticationIni
54
56
  browserCorsFailsSilentlyRedirectUrl: string;
55
57
  constructor(config: typeof this.config, setDesignOptions?: (value: LoginAppDesignOptions) => void);
56
58
  handleLoginAppPopupFailed(redirectUrl: string): Promise<void>;
57
- handleBrowserCorsFailsSilently(redirectUrl: string): Promise<void>;
58
- handleUserInteractionBrowserCorsFailsSilently(): Promise<void>;
59
+ handleBrowserCorsFailsSilently(redirectUrl: string): Promise<{
60
+ isRedirecting: boolean;
61
+ } | undefined>;
62
+ handleUserInteractionBrowserCorsFailsSilently(): Promise<{
63
+ isRedirecting: boolean;
64
+ }>;
59
65
  handleLoginAppDesignUpdate(options: LoginAppDesignOptions): Promise<void>;
60
66
  getSignInUrl(): Promise<URL>;
61
67
  signIn(iframeRef: HTMLIFrameElement | null): Promise<URL>;