@civic/auth 0.0.1-beta.14 → 0.0.1-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-F2CKPLXX.js → chunk-CHY6AHA7.js} +4 -2
- package/dist/chunk-CHY6AHA7.js.map +1 -0
- package/dist/chunk-CRTRMMJ7.js.map +1 -1
- package/dist/{chunk-3Q3CWGPG.mjs → chunk-FBU2CKWK.mjs} +2 -2
- package/dist/{chunk-F55XKBNM.js → chunk-N4SAZYOX.js} +7 -7
- package/dist/{chunk-F55XKBNM.js.map → chunk-N4SAZYOX.js.map} +1 -1
- package/dist/{chunk-EDLPS3AK.mjs → chunk-RKQDQJOM.mjs} +3 -1
- package/dist/chunk-RKQDQJOM.mjs.map +1 -0
- package/dist/index.css +2 -6
- package/dist/index.css.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/nextjs.js +29 -24
- package/dist/nextjs.js.map +1 -1
- package/dist/nextjs.mjs +9 -4
- package/dist/nextjs.mjs.map +1 -1
- package/dist/react.js +34 -32
- package/dist/react.js.map +1 -1
- package/dist/react.mjs +11 -9
- package/dist/react.mjs.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +1 -1
- package/package.json +3 -3
- package/dist/chunk-EDLPS3AK.mjs.map +0 -1
- package/dist/chunk-F2CKPLXX.js.map +0 -1
- /package/dist/{chunk-3Q3CWGPG.mjs.map → chunk-FBU2CKWK.mjs.map} +0 -0
package/dist/react.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/react/hooks/useUser.tsx","../src/shared/UserProvider.tsx","../src/react/hooks/useAuth.tsx","../src/shared/AuthContext.tsx","../src/react/hooks/useToken.tsx","../src/react/providers/TokenProvider.tsx","../src/react/hooks/useSession.tsx","../src/react/providers/SessionProvider.tsx","../src/shared/AuthProvider.tsx","../src/react/components/CivicAuthIframeContainer.tsx","../src/react/components/LoadingIcon.tsx","../src/react/components/CloseIcon.tsx","../src/react/components/CivicAuthIframe.tsx","../src/config.ts","../src/react/providers/ConfigProvider.tsx","../src/shared/CivicAuthProvider.tsx","../src/react/providers/NextAuthProvider.tsx","../src/react/hooks/useUserCookie.ts","../src/lib/cookies.ts","../src/react/hooks/useConfig.tsx","../src/react/components/UserButton.tsx","../src/react/components/SignInButton.tsx","../src/react/components/SignOutButton.tsx","../src/react/components/NextLogOut.tsx"],"sourcesContent":["\"use client\";\nimport { useContext } from \"react\";\nimport { UserContext, UserContextType } from \"@/react/providers\";\n\nconst useUser = <\n T extends Record<string, unknown> = Record<string, never>,\n>(): UserContextType<T> => {\n const context = useContext(UserContext);\n\n if (!context) {\n throw new Error(\"useUser must be used within a UserProvider\");\n }\n\n return context as UserContextType<T>;\n};\n\nexport { useUser };\n","\"use client\";\nimport { createContext, ReactNode } from \"react\";\nimport { useQuery, UseQueryResult } from \"@tanstack/react-query\";\nimport { JWT } from \"oslo/jwt\";\nimport { AuthStorage, EmptyObject, User } from \"@/types\";\nimport { useAuth } from \"@/react/hooks/useAuth\";\nimport { useToken } from \"@/react/hooks/useToken\";\nimport { useSession } from \"@/react/hooks/useSession\";\nimport { AuthContextType } from \"@/shared/AuthContext\";\nimport { GenericUserSession } from \"@/shared/UserSession\";\n\ntype UserContextType<\n T extends Record<string, unknown> & JWT[\"payload\"] = Record<string, unknown> &\n JWT[\"payload\"],\n> = {\n user: User<T> | null;\n} & Omit<AuthContextType, \"isAuthenticated\">;\n\nconst UserContext = createContext<UserContextType | null>(null);\n\nconst UserProvider = <T extends EmptyObject>({\n children,\n storage,\n user: inputUser,\n signOut: inputSignOut,\n}: {\n children: ReactNode;\n storage: AuthStorage;\n user?: User<T> | null;\n signOut?: () => Promise<void>;\n}) => {\n const { isLoading: authLoading, error: authError } = useAuth();\n const session = useSession();\n const { accessToken } = useToken();\n const { signIn, signOut } = useAuth();\n\n const fetchUser = async (): Promise<User | null> => {\n if (!accessToken) {\n return null;\n }\n const userSession = new GenericUserSession(storage);\n return userSession.get();\n };\n\n const {\n data: user,\n isLoading: userLoading,\n error: userError,\n }: UseQueryResult<User<T> | null, Error> = useQuery({\n queryKey: [\"user\", session?.idToken],\n queryFn: fetchUser,\n enabled: !!session?.idToken, // Only run the query if we have an access token\n });\n\n const isLoading = authLoading || userLoading;\n const error = authError || userError;\n\n return (\n <UserContext.Provider\n value={{\n user: (inputUser || user) ?? null,\n isLoading,\n error,\n signIn,\n signOut: inputSignOut || signOut,\n }}\n >\n {children}\n </UserContext.Provider>\n );\n};\n\nexport type { UserContextType };\n\nexport { UserProvider, UserContext };\n","\"use client\";\nimport { useContext } from \"react\";\n\nimport { AuthContext } from \"@/shared/AuthContext.tsx\";\n\nconst useAuth = () => {\n const context = useContext(AuthContext);\n\n if (!context) {\n throw new Error(\"useAuth must be used within an AuthProvider\");\n }\n\n return context;\n};\n\nexport { useAuth };\n","import { createContext } from \"react\";\nimport { DisplayMode } from \"@/types.ts\";\n\nexport type AuthContextType = {\n signIn: (displayMode?: DisplayMode) => Promise<void>;\n isAuthenticated: boolean;\n isLoading: boolean;\n error: Error | null;\n signOut: () => Promise<void>;\n};\nexport const AuthContext = createContext<AuthContextType | null>(null);\n","\"use client\";\nimport { useContext } from \"react\";\nimport { TokenContext } from \"@/react/providers/TokenProvider\";\n\nconst useToken = () => {\n const context = useContext(TokenContext);\n\n if (!context) {\n throw new Error(\"useToken must be used within a TokenProvider\");\n }\n\n return context;\n};\n\nexport { useToken };\n","\"use client\";\nimport { createContext, ReactNode, useMemo } from \"react\";\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useAuth } from \"@/react/hooks/useAuth\";\nimport { useSession } from \"@/react/hooks/useSession\";\nimport { ForwardedTokens, IdToken } from \"@/types\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { convertForwardedTokenFormat } from \"@/lib/jwt.js\";\n\ntype TokenContextType = {\n accessToken: string | null;\n idToken: string | null;\n forwardedTokens: ForwardedTokens;\n refreshToken: () => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n};\n\nconst TokenContext = createContext<TokenContextType | undefined>(undefined);\n\nconst TokenProvider = ({ children }: { children: ReactNode }) => {\n const { isLoading, error: authError } = useAuth();\n const session = useSession();\n const queryClient = useQueryClient();\n\n const refreshTokenMutation = useMutation({\n mutationFn: async () => {\n // Implement token refresh logic here\n throw new Error(\"Method not implemented.\");\n },\n onSuccess: () => {\n // Invalidate and refetch queries that depend on the auth session\n queryClient.invalidateQueries({ queryKey: [\"session\"] });\n },\n });\n\n const decodeTokens = useMemo(() => {\n if (!session?.idToken) return null;\n\n const parsedJWT = parseJWT(session.idToken) as IdToken | null;\n\n if (!parsedJWT) return null;\n\n const { forwardedTokens } = parsedJWT.payload;\n\n return forwardedTokens\n ? convertForwardedTokenFormat(forwardedTokens)\n : null;\n }, [session?.idToken]);\n\n const value = useMemo(\n () => ({\n accessToken: session.accessToken || null,\n idToken: session.idToken || null,\n forwardedTokens: decodeTokens || {},\n refreshToken: refreshTokenMutation.mutateAsync,\n isLoading,\n error: (authError || refreshTokenMutation.error) as Error | null,\n }),\n [\n session.accessToken,\n session.idToken,\n decodeTokens,\n refreshTokenMutation.mutateAsync,\n refreshTokenMutation.error,\n isLoading,\n authError,\n ],\n );\n\n return (\n <TokenContext.Provider value={value}>{children}</TokenContext.Provider>\n );\n};\n\nexport type { TokenContextType };\nexport { TokenProvider, TokenContext };\n","\"use client\";\nimport { useContext } from \"react\";\nimport { SessionContext } from \"@/react/providers/SessionProvider\";\n\n// TokenProvider will use this internal context to access session\nconst useSession = () => {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error(\"useSession must be used within an SessionProvider\");\n }\n return context;\n};\n\nexport { useSession };\n","\"use client\";\nimport { SessionData } from \"@/types\";\nimport {\n createContext,\n Dispatch,\n ReactNode,\n RefObject,\n SetStateAction,\n} from \"react\";\n\nexport type SessionProviderOutput = SessionData & {\n iframeRef: RefObject<HTMLIFrameElement> | null;\n setAuthResponseUrl: Dispatch<SetStateAction<string | null>>;\n};\nconst defaultSession: SessionProviderOutput = {\n authenticated: false,\n idToken: undefined,\n accessToken: undefined,\n displayMode: \"iframe\",\n iframeRef: null,\n setAuthResponseUrl: () => {},\n};\n\n// Context for exposing session specifically to the TokenProvider\nconst SessionContext = createContext<SessionProviderOutput>(defaultSession);\n\ntype SessionContextType = {\n children: ReactNode;\n session?: SessionData | null;\n iframeRef: RefObject<HTMLIFrameElement> | null;\n setAuthResponseUrl: Dispatch<SetStateAction<string | null>>;\n};\n\nconst SessionProvider = ({\n children,\n session,\n iframeRef,\n setAuthResponseUrl,\n}: SessionContextType) => (\n <SessionContext.Provider\n value={{ ...(session || defaultSession), iframeRef, setAuthResponseUrl }}\n >\n {children}\n </SessionContext.Provider>\n);\n\nexport type { SessionContextType };\nexport { SessionProvider, SessionContext };\n","\"use client\";\nimport {\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { Config, DisplayMode } from \"@/types\";\nimport { CivicAuthIframeContainer } from \"@/react/components/CivicAuthIframeContainer\";\nimport { TokenProvider } from \"@/react/providers/TokenProvider\";\nimport { UserProvider } from \"@/shared/UserProvider\";\nimport { SessionProvider } from \"@/react/providers/SessionProvider\";\nimport { DEFAULT_SCOPES } from \"@/constants\";\nimport { authConfig } from \"@/config\";\nimport { LoadingIcon } from \"@/react/components/LoadingIcon\";\nimport { isWindowInIframe } from \"@/lib/windowUtil\";\nimport { AuthContext } from \"@/shared/AuthContext\";\nimport {\n BrowserAuthenticationInitiator,\n BrowserAuthenticationService,\n} from \"@/services/AuthenticationService\";\nimport { AuthenticationResolver, PKCEConsumer } from \"@/services/types\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE\";\nimport { generateState } from \"@/lib/oauth\";\nimport { LocalStorageAdapter } from \"@/browser/storage\";\nimport { ConfigProvider } from \"@/react/providers/ConfigProvider\";\nimport { getUser } from \"./session\";\nimport { GenericUserSession } from \"./UserSession\";\n\n// Global this object setup\nlet globalThisObject;\nif (typeof window !== \"undefined\") {\n globalThisObject = window;\n} else if (typeof global !== \"undefined\") {\n globalThisObject = global;\n} else {\n globalThisObject = Function(\"return this\")();\n}\nglobalThisObject.globalThis = globalThisObject;\n\nexport type AuthProviderProps = {\n children: ReactNode;\n clientId: string;\n redirectUrl?: string;\n nonce?: string;\n config?: Config;\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n pkceConsumer?: PKCEConsumer;\n modalIframe?: boolean;\n};\n\nfunction BlockDisplay({ children }: { children: ReactNode }) {\n return (\n <div className=\"cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-white\">\n <div className=\"cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-bg-white\">\n {children}\n </div>\n </div>\n );\n}\n\nconst AuthProvider = ({\n children,\n clientId,\n redirectUrl: inputRedirectUrl,\n config = authConfig,\n onSignIn,\n onSignOut,\n pkceConsumer,\n nonce,\n modalIframe = true,\n}: AuthProviderProps) => {\n const [iframeUrl, setIframeUrl] = useState<string | null>(null);\n const [currentUrl, setCurrentUrl] = useState<string | null>(null);\n const [isInIframe, setIsInIframe] = useState(false);\n const [authResponseUrl, setAuthResponseUrl] = useState<string | null>(null);\n const [tokenExchangeError, setTokenExchangeError] = useState<Error>();\n const [displayMode, setDisplayMode] = useState<DisplayMode>(\"iframe\");\n const [browserAuthenticationInitiator, setBrowserAuthenticationInitiator] =\n useState<BrowserAuthenticationInitiator | null>();\n const [showIFrame, setShowIFrame] = useState(false);\n const [isRedirecting, setIsRedirecting] = useState(false);\n const queryClient = useQueryClient();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n // TODO maybe we want to support or derive serverTokenExchange another way?\n const serverTokenExchange =\n pkceConsumer instanceof ConfidentialClientPKCEConsumer;\n // check if the current window is in an iframe with the iframe id, and set an isInIframe state\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n setCurrentUrl(globalThis.window.location.href);\n const isInIframeVal = isWindowInIframe(globalThis.window);\n setIsInIframe(isInIframeVal);\n }\n }, []);\n\n const redirectUrl = useMemo(\n () => (inputRedirectUrl || currentUrl || \"\").split(\"?\")[0],\n [currentUrl, inputRedirectUrl],\n );\n\n const [authService, setAuthService] = useState<AuthenticationResolver>();\n\n useEffect(() => {\n if (!currentUrl) return;\n BrowserAuthenticationService.build({\n clientId,\n redirectUrl,\n oauthServer: config.oauthServer,\n scopes: DEFAULT_SCOPES,\n displayMode,\n }).then(setAuthService);\n }, [currentUrl, clientId, redirectUrl, config, displayMode]);\n\n const {\n data: session,\n isLoading,\n error,\n } = useQuery({\n queryKey: [\n \"session\",\n authResponseUrl,\n iframeUrl,\n currentUrl,\n isInIframe,\n authService,\n ],\n queryFn: async () => {\n if (!authService) {\n return { authenticated: false };\n }\n const url = new URL(\n authResponseUrl\n ? authResponseUrl\n : globalThis.window.location.href || \"\",\n );\n\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n if (!serverTokenExchange && code && state && !isInIframe) {\n try {\n console.log(\"AuthProvider useQuery code\", {\n isInIframe,\n code,\n state,\n });\n await authService.tokenExchange(code, state);\n const clientStorage = new LocalStorageAdapter();\n const user = await getUser(clientStorage);\n if (!user) {\n throw new Error(\"Failed to get user info\");\n }\n\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(user);\n\n onSignIn?.(); // Call onSignIn without an error if successful\n return authService.getSessionData();\n } catch (error) {\n setTokenExchangeError(error as Error);\n onSignIn?.(\n error instanceof Error ? error : new Error(\"Failed to sign in\"),\n ); // Pass the error to onSignIn\n return { authenticated: false };\n }\n }\n // if we have existing tokens, then validate them and return the session data\n // otherwise check if we have a code in the url and exchange it for tokens\n // if we have neither, return undefined\n const existingSessionData = await authService.validateExistingSession();\n if (existingSessionData.authenticated) {\n return existingSessionData;\n }\n return existingSessionData;\n },\n });\n\n const signOutMutation = useMutation({\n mutationFn: async () => {\n // Implement signOut logic here\n const authInitiator = getAuthInitiator();\n authInitiator?.signOut();\n setIframeUrl(null);\n setShowIFrame(false);\n setAuthResponseUrl(null);\n onSignOut?.();\n },\n onSuccess: () => {\n queryClient.setQueryData(\n [\n \"session\",\n authResponseUrl,\n iframeUrl,\n currentUrl,\n isInIframe,\n authService,\n ],\n null,\n );\n },\n });\n\n const getAuthInitiator = useCallback(\n (overrideDisplayMode?: DisplayMode) => {\n const useDisplayMode = overrideDisplayMode || displayMode;\n if (!pkceConsumer) {\n return null;\n }\n return (\n browserAuthenticationInitiator ||\n new BrowserAuthenticationInitiator({\n pkceConsumer, // generate and retrieve the challenge client-side\n clientId,\n redirectUrl,\n state: generateState(useDisplayMode),\n scopes: DEFAULT_SCOPES,\n displayMode: useDisplayMode,\n oauthServer: config.oauthServer,\n // the endpoints to use for the login (if not obtained from the auth server\n endpointOverrides: config.endpoints,\n nonce,\n })\n );\n },\n [\n displayMode,\n browserAuthenticationInitiator,\n clientId,\n redirectUrl,\n config.oauthServer,\n config.endpoints,\n pkceConsumer,\n nonce,\n ],\n );\n\n const signIn = useCallback(\n async (overrideDisplayMode: DisplayMode = \"iframe\") => {\n setDisplayMode(overrideDisplayMode);\n const authInitiator = getAuthInitiator(overrideDisplayMode);\n setBrowserAuthenticationInitiator(authInitiator);\n if (overrideDisplayMode === \"iframe\") {\n setShowIFrame(true);\n } else if (overrideDisplayMode === \"redirect\") {\n setIsRedirecting(true);\n }\n authInitiator?.signIn(iframeRef.current);\n },\n [getAuthInitiator],\n );\n const isAuthenticated = useMemo(\n () => (session ? session.authenticated : false),\n [session],\n );\n\n const {\n data: autoSignIn,\n isLoading: autoSignInLoading,\n error: autoSignInError,\n } = useQuery({\n queryKey: [\"autoSignIn\", modalIframe, redirectUrl, isAuthenticated],\n queryFn: async () => {\n if (\n !modalIframe &&\n redirectUrl &&\n !isAuthenticated &&\n iframeRef.current\n ) {\n signIn(\"iframe\");\n }\n return true;\n },\n refetchOnWindowFocus: false,\n });\n\n const value = useMemo(\n () => ({\n isLoading,\n error: error as Error | null,\n signOut: async () => {\n await signOutMutation.mutateAsync();\n },\n isAuthenticated,\n signIn,\n }),\n [isLoading, error, signOutMutation, isAuthenticated, signIn],\n );\n return (\n <AuthContext.Provider value={value}>\n <ConfigProvider\n config={config}\n redirectUrl={redirectUrl}\n modalIframe={modalIframe}\n serverTokenExchange={serverTokenExchange}\n >\n <SessionProvider\n session={session}\n setAuthResponseUrl={setAuthResponseUrl}\n iframeRef={iframeRef}\n >\n <TokenProvider>\n \n {modalIframe && !isInIframe && !session?.authenticated && (\n <div\n style={\n showIFrame ? { display: \"block\" } : { display: \"none\" }\n }\n >\n <CivicAuthIframeContainer\n onClose={() => setShowIFrame(false)}\n />\n </div>\n )}\n {modalIframe && (isInIframe || isRedirecting || isLoading) && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n {(tokenExchangeError || error) && (\n <BlockDisplay>\n <div>\n Error: {(tokenExchangeError || (error as Error)).message}\n </div>\n </BlockDisplay>\n )}\n {children}\n </TokenProvider>\n </SessionProvider>\n </ConfigProvider>\n </AuthContext.Provider>\n );\n};\n\nexport { AuthProvider };\n","\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { LoadingIcon } from \"@/react/components/LoadingIcon\";\nimport { CloseIcon } from \"@/react/components/CloseIcon\";\nimport { CivicAuthIframe } from \"@/react/components/CivicAuthIframe\";\nimport { useAuth, useConfig, useSession } from \"@/react/hooks\";\nimport React from \"react\";\n\ntype CivicAuthIframeContainerProps = {\n onClose?: () => void;\n closeOnRedirect?: boolean;\n};\n\nfunction NoChrome({\n children,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return <>{children}</>;\n}\n\nfunction IframeChrome({\n children,\n onClose,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return (\n <div\n className=\"cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-neutral-950 cac-bg-opacity-50\"\n onClick={onClose}\n >\n <div\n className=\"cac-relative cac-rounded-3xl cac-bg-white cac-p-6 cac-shadow-lg\"\n onClick={(e) => e.stopPropagation()}\n >\n <button\n className=\"cac-absolute cac-right-4 cac-top-4 cac-flex cac-cursor-pointer cac-items-center cac-justify-center cac-border-none cac-bg-transparent cac-p-1 cac-text-neutral-400\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n\n {children}\n </div>\n </div>\n );\n}\nconst CivicAuthIframeContainer = ({\n onClose,\n closeOnRedirect = true,\n}: CivicAuthIframeContainerProps) => {\n const [isLoading, setIsLoading] = useState(true);\n const { isLoading: isAuthLoading } = useAuth();\n const config = useConfig();\n const { setAuthResponseUrl, iframeRef } = useSession();\n const processIframeUrl = useCallback(() => {\n if (iframeRef && iframeRef.current && iframeRef.current.contentWindow) {\n try {\n const iframeUrl = iframeRef.current.contentWindow.location.href;\n // we know that oauth has finished when the iframe redirects to our redirectUrl\n if (iframeUrl.startsWith(config.redirectUrl)) {\n // we still want to show the spinner during redirect\n setIsLoading(true);\n const iframeBody =\n iframeRef.current.contentWindow.document.body.innerHTML;\n\n // If we're doing a server token exchange, we need to call the server a second time\n // using a fetch so that we're on the same domain and cookies can be sent and read\n // The server will use the presence of the code_verifier cookie to determine whether to do a token exchange or not.\n // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,\n // and we'll do the exchange request from here, which will include the cookies.\n if (iframeBody.includes(\"sameDomainCodeExchangeRequired\")) {\n console.log(\n \"sameDomainCodeExchangeRequired, calling callback URL again...\",\n );\n const params = new URL(iframeUrl).searchParams;\n fetch(`${config.redirectUrl}?${params.toString()}`);\n } else {\n // if we're doing token-exchange in the client, we can just set the authResponseUrl\n // to be handled by the auth provider\n setAuthResponseUrl(iframeUrl);\n }\n\n if (closeOnRedirect) onClose?.();\n return true; // Successfully processed the URL\n }\n } catch {\n // If we get here, the iframe hasn't redirected to our origin yet\n console.log(\"Waiting for redirect...\");\n }\n }\n return false; // Haven't processed the URL yet\n }, [\n closeOnRedirect,\n config.redirectUrl,\n iframeRef,\n onClose,\n setAuthResponseUrl,\n ]);\n\n const intervalId = useRef<NodeJS.Timeout>();\n\n const handleEscape = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose?.();\n }\n },\n [onClose],\n );\n\n // handle Escape\n useEffect(() => {\n window.addEventListener(\"keydown\", handleEscape);\n\n return () => window.removeEventListener(\"keydown\", handleEscape);\n });\n\n const handleIframeLoad = () => {\n setIsLoading(false);\n console.log(\"handleIframeLoad\");\n if (processIframeUrl() && intervalId.current) {\n clearInterval(intervalId.current);\n }\n };\n const showLoadingIcon =\n isLoading || isAuthLoading || !iframeRef?.current?.getAttribute(\"src\");\n\n const WrapperComponent = config.modalIframe ? IframeChrome : NoChrome;\n\n console.log(\"CivicAuthIframeContainer showLoadingIcon\", showLoadingIcon);\n return (\n <WrapperComponent onClose={onClose}>\n {showLoadingIcon && (\n <div className=\"cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-rounded-3xl cac-bg-neutral-100\">\n <LoadingIcon />\n </div>\n )}\n\n <CivicAuthIframe ref={iframeRef} onLoad={handleIframeLoad} />\n </WrapperComponent>\n );\n};\n\nexport type { CivicAuthIframeContainerProps };\n\nexport { CivicAuthIframeContainer };\n","const LoadingIcon = () => (\n <div role=\"status\">\n <svg\n aria-hidden=\"true\"\n className=\"cac-inline cac-h-8 cac-w-8 cac-animate-spin cac-fill-neutral-600 cac-text-neutral-200 dark:cac-fill-neutral-300 dark:cac-text-neutral-600\"\n viewBox=\"0 0 100 101\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z\"\n fill=\"currentFill\"\n />\n </svg>\n <span className=\"cac-sr-only\">Loading...</span>\n </div>\n);\n\nexport { LoadingIcon };\n","const CloseIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"lucide lucide-x\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n);\n\nexport { CloseIcon };\n","\"use client\";\nimport { IFRAME_ID } from \"@/constants\";\nimport { forwardRef } from \"react\";\n\ntype CivicAuthIframeProps = {\n onLoad?: () => void;\n};\n\nconst CivicAuthIframe = forwardRef<HTMLIFrameElement, CivicAuthIframeProps>(\n ({ onLoad }, ref) => {\n return (\n <iframe\n id={IFRAME_ID}\n ref={ref}\n className=\"cac-h-96 cac-w-80 cac-border-none\"\n onLoad={onLoad}\n />\n );\n },\n);\n\nCivicAuthIframe.displayName = \"CivicAuthIframe\";\n\nexport type { CivicAuthIframeProps };\n\nexport { CivicAuthIframe };\n","import { Config } from \"@/types\";\n\nexport const authConfig: Config = {\n // TODO change this to the production URL once we're out of beta\n oauthServer: \"https://auth-dev.civic.com/oauth/\",\n};\n","\"use client\";\nimport { authConfig } from \"@/config\";\nimport { Config } from \"@/types\";\nimport { createContext, ReactNode } from \"react\";\n\nexport type ConfigProviderOutput = {\n config: Config;\n redirectUrl: string;\n modalIframe: boolean;\n serverTokenExchange: boolean;\n};\nconst defaultConfig: ConfigProviderOutput = {\n config: authConfig,\n redirectUrl: \"\",\n modalIframe: true,\n serverTokenExchange: false,\n};\n// Context for exposing Config specifically to the TokenProvider\nconst ConfigContext = createContext<ConfigProviderOutput>(defaultConfig);\n\ntype ConfigContextType = {\n children: ReactNode;\n config: Config;\n redirectUrl: string;\n modalIframe?: boolean;\n serverTokenExchange: boolean;\n};\n\nconst ConfigProvider = ({\n children,\n config,\n redirectUrl,\n modalIframe,\n serverTokenExchange,\n}: ConfigContextType) => (\n <ConfigContext.Provider\n value={{\n config,\n redirectUrl,\n modalIframe: !!modalIframe,\n serverTokenExchange,\n }}\n >\n {children}\n </ConfigContext.Provider>\n);\n\nexport type { ConfigContextType };\nexport { ConfigProvider, ConfigContext };\n","\"use client\";\nimport { AuthProvider, AuthProviderProps } from \"./AuthProvider\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\n\n// adding the styles import here to be added to the bundle\nimport \"@civic/auth/styles.css\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE\";\nimport { UserProvider } from \"./UserProvider\";\nimport { LocalStorageAdapter } from \"@/browser/storage\";\n\nconst queryClient = new QueryClient();\n\ntype CivicAuthProviderProps = Omit<AuthProviderProps, \"pkceConsumer\">;\n\nconst CivicAuthProvider = ({ children, ...props }: CivicAuthProviderProps) => {\n return (\n <QueryClientProvider client={queryClient}>\n <AuthProvider\n {...props}\n pkceConsumer={new BrowserPublicClientPKCEProducer()}\n >\n <UserProvider storage={new LocalStorageAdapter()}>\n {children}\n </UserProvider>\n </AuthProvider>\n </QueryClientProvider>\n );\n};\n\nexport { CivicAuthProvider, type CivicAuthProviderProps };\n","\"use client\";\n/**\n * A very small context provider for the user object - it takes the user object from the cookie and provides it to the app.\n */\nimport { useEffect, useState } from \"react\";\nimport { AuthProvider, AuthProviderProps } from \"@/shared/AuthProvider.js\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\n\n// adding the styles import here to be added to the bundle\nimport \"@civic/auth/styles.css\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE.js\";\nimport { NextjsClientStorage } from \"@/nextjs/cookies\";\nimport { UserProvider } from \"@/shared/UserProvider\";\nimport { useUserCookie } from \"../hooks\";\n\nconst queryClient = new QueryClient();\n\nexport type NextCivicAuthProviderProps = Omit<AuthProviderProps, \"clientId\">;\n\nexport const CivicNextAuthProvider = ({\n children,\n ...props\n}: NextCivicAuthProviderProps) => {\n const [redirectUrl, setRedirectUrl] = useState<string>(\"\");\n const { clientId, oauthServer, callbackUrl, challengeUrl, logoutUrl } =\n resolveAuthConfig();\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const currentUrl = globalThis.window.location.href;\n setRedirectUrl(resolveCallbackUrl(resolveAuthConfig(), currentUrl));\n }\n }, [callbackUrl]);\n const user = useUserCookie();\n\n const signOut = async (): Promise<void> => {\n await fetch(logoutUrl);\n return;\n };\n return (\n <QueryClientProvider client={queryClient}>\n <AuthProvider\n {...props}\n redirectUrl={redirectUrl}\n config={{ oauthServer }}\n clientId={clientId}\n pkceConsumer={new ConfidentialClientPKCEConsumer(challengeUrl)}\n >\n <UserProvider\n storage={new NextjsClientStorage()}\n user={user}\n signOut={signOut}\n >\n {children}\n </UserProvider>\n </AuthProvider>\n </QueryClientProvider>\n );\n};\n","\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { useRouter } from \"next/navigation.js\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { getCookieValue } from \"@/lib/cookies.js\";\n\nconst getUserFromCookie = () => {\n const userCookie = getCookieValue(\"user\", globalThis.window);\n return userCookie;\n};\n\nexport const useUserCookie = () => {\n const hasRunRef = useRef(false);\n const router = useRouter();\n\n const { data: user } = useQuery({\n queryKey: [\"user\"],\n queryFn: () => getUserFromCookie(),\n refetchInterval: 2000,\n refetchIntervalInBackground: true,\n enabled: !hasRunRef.current,\n refetchOnWindowFocus: true,\n });\n\n useEffect(() => {\n if (user) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n router.refresh();\n }\n } else {\n hasRunRef.current = false;\n }\n }, [user, router]);\n\n return user;\n};\n","const getCookieValue = (key: string, window: Window) => {\n const cookie = window.document.cookie;\n if (!cookie) return null;\n const cookies = cookie.split(\";\");\n for (const c of cookies) {\n const [name, value] = c.trim().split(\"=\");\n if (value && name === key) {\n try {\n return JSON.parse(decodeURIComponent(value));\n } catch (e) {\n console.log(\"Error parsing cookie value\", e);\n return value;\n }\n }\n }\n return null;\n};\nexport { getCookieValue };\n","\"use client\";\nimport { useContext } from \"react\";\nimport { ConfigContext } from \"@/react/providers/ConfigProvider\";\n\n// TokenProvider will use this internal context to access Config\nconst useConfig = () => {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error(\"useConfig must be used within an ConfigProvider\");\n }\n return context;\n};\n\nexport { useConfig };\n","\"use client\";\nimport { useUser } from \"@/react/hooks\";\nimport { DisplayMode } from \"@/types\";\nimport { cn } from \"@/utils\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nconst ChevronDown = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"lucide lucide-chevron-down\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n);\n\nconst ChevronUp = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"lucide lucide-chevron-up\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n);\n\nconst UserButton = ({\n displayMode,\n className,\n}: {\n displayMode?: DisplayMode;\n className?: string;\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const { user, signIn, signOut } = useUser();\n\n const handleClickOutside = useCallback((event: MouseEvent) => {\n const target = event.target as HTMLElement;\n\n if (!target.closest(\"#civic-dropdown-container\")) {\n setIsOpen(false);\n }\n }, []);\n\n const handleSignOut = useCallback(async () => {\n signOut();\n\n setIsOpen(false);\n }, [signOut]);\n\n const handleSignIn = useCallback(async () => {\n await signIn(displayMode);\n\n setIsOpen(false);\n }, [signIn, displayMode]);\n\n const handleEscape = useCallback((event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n }\n }, []);\n\n useEffect(() => {\n if (isOpen) {\n window.addEventListener(\"click\", handleClickOutside);\n\n window.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n window.removeEventListener(\"click\", handleClickOutside);\n\n window.removeEventListener(\"keydown\", handleEscape);\n };\n }, [handleClickOutside, handleEscape, isOpen]);\n\n if (user) {\n return (\n <div className=\"cac-relative\" id=\"civic-dropdown-container\">\n <button\n className={cn(\n \"cac-flex cac-w-full cac-items-center cac-justify-between cac-gap-2 cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-text-neutral-500 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={() => setIsOpen((isOpen) => !isOpen)}\n >\n {user?.picture ? (\n <span className=\"cac-relative cac-flex cac-h-10 cac-w-10 cac-shrink-0 cac-gap-2 cac-overflow-hidden cac-rounded-full\">\n <img\n className=\"cac-h-full cac-w-full cac-object-cover\"\n src={user.picture}\n alt={user?.name || user?.email}\n />\n </span>\n ) : (\n <div />\n )}\n\n <span>{user?.name || user?.email}</span>\n\n {isOpen ? <ChevronUp /> : <ChevronDown />}\n </button>\n <div\n className={\n isOpen\n ? \"cac-absolute cac-right-0 cac-mt-2 cac-w-full cac-rounded-lg cac-bg-white cac-py-2 cac-text-neutral-500 cac-shadow-xl\"\n : \"cac-hidden\"\n }\n >\n <ul>\n <li>\n <button\n className=\"cac-block cac-w-full cac-px-4 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\"\n onClick={handleSignOut}\n >\n Logout\n </button>\n </li>\n </ul>\n </div>\n </div>\n );\n }\n\n return (\n <button\n data-testid=\"sign-in-button\"\n className={cn(\n \"cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={handleSignIn}\n >\n Sign in\n </button>\n );\n};\n\nexport { UserButton };\n","\"use client\";\nimport { cn } from \"@/utils\";\nimport { DisplayMode } from \"@/types\";\nimport { useUser } from \"@/react/hooks\";\n\nconst SignInButton = ({\n displayMode,\n className,\n}: {\n displayMode?: DisplayMode;\n className?: string;\n}) => {\n const { signIn } = useUser();\n\n return (\n <button\n data-testid=\"sign-in-button\"\n className={cn(\n \"cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={() => signIn(displayMode)}\n >\n Sign In\n </button>\n );\n};\n\nexport { SignInButton };\n","\"use client\";\nimport { cn } from \"@/utils\";\nimport { useUser } from \"@/react/hooks\";\n\nconst SignOutButton = ({ className }: { className?: string }) => {\n const { signOut } = useUser();\n\n return (\n <button\n className={cn(\n \"cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={() => signOut()}\n >\n Sign Out\n </button>\n );\n};\n\nexport { SignOutButton };\n","/**\n * Trigger a backend API that logs the user out and then redirects to the homepage (TODO parameterize the redirect)\n */\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport React, { ReactNode } from \"react\";\n\nconst NextLogOut = ({ children }: { children: ReactNode }) => {\n const config = resolveAuthConfig();\n const logoutUrl = `${config.logoutUrl}`;\n\n return <a href={logoutUrl}>{children}</a>;\n};\n\nexport { NextLogOut };\n"],"mappings":"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","names":["useContext","createContext","useContext","createContext","useContext","createContext","createContext","useContext","jsx","createContext","queryClient","useContext","jsx","createContext","useCallback","useEffect","useMemo","useRef","useState","useMutation","useQuery","useQueryClient","jsx","jsx","jsxs","jsx","jsx","jsxs","createContext","jsx","jsx","jsxs","useState","queryClient","useQueryClient","useRef","useEffect","useMemo","useQuery","error","useMutation","useCallback","jsx","useEffect","useState","QueryClient","QueryClientProvider","jsx","queryClient","QueryClient","useState","useEffect","QueryClientProvider","useContext","useEffect","useRef","useQuery","window","useRef","useQuery","useEffect","useContext","useContext","useCallback","useEffect","useState","jsx","jsxs","useState","useCallback","useEffect","isOpen","jsx","jsx","jsx"]}
|
|
1
|
+
{"version":3,"sources":["../src/react/hooks/useUser.tsx","../src/shared/UserProvider.tsx","../src/react/hooks/useAuth.tsx","../src/shared/AuthContext.tsx","../src/react/hooks/useToken.tsx","../src/react/providers/TokenProvider.tsx","../src/react/hooks/useSession.tsx","../src/react/providers/SessionProvider.tsx","../src/shared/AuthProvider.tsx","../src/react/components/CivicAuthIframeContainer.tsx","../src/react/components/LoadingIcon.tsx","../src/react/components/CloseIcon.tsx","../src/react/components/CivicAuthIframe.tsx","../src/config.ts","../src/react/providers/ConfigProvider.tsx","../src/shared/CivicAuthProvider.tsx","../src/react/providers/NextAuthProvider.tsx","../src/react/hooks/useUserCookie.ts","../src/lib/cookies.ts","../src/react/hooks/useConfig.tsx","../src/react/components/UserButton.tsx","../src/react/components/SignInButton.tsx","../src/react/components/SignOutButton.tsx","../src/react/components/NextLogOut.tsx"],"sourcesContent":["\"use client\";\nimport { useContext } from \"react\";\nimport { UserContext, UserContextType } from \"@/react/providers\";\n\nconst useUser = <\n T extends Record<string, unknown> = Record<string, never>,\n>(): UserContextType<T> => {\n const context = useContext(UserContext);\n\n if (!context) {\n throw new Error(\"useUser must be used within a UserProvider\");\n }\n\n return context as UserContextType<T>;\n};\n\nexport { useUser };\n","\"use client\";\nimport { createContext, ReactNode } from \"react\";\nimport { useQuery, UseQueryResult } from \"@tanstack/react-query\";\nimport { JWT } from \"oslo/jwt\";\nimport { AuthStorage, EmptyObject, User } from \"@/types\";\nimport { useAuth } from \"@/react/hooks/useAuth\";\nimport { useToken } from \"@/react/hooks/useToken\";\nimport { useSession } from \"@/react/hooks/useSession\";\nimport { AuthContextType } from \"@/shared/AuthContext\";\nimport { GenericUserSession } from \"@/shared/UserSession\";\n\ntype UserContextType<\n T extends Record<string, unknown> & JWT[\"payload\"] = Record<string, unknown> &\n JWT[\"payload\"],\n> = {\n user: User<T> | null;\n} & Omit<AuthContextType, \"isAuthenticated\">;\n\nconst UserContext = createContext<UserContextType | null>(null);\n\nconst UserProvider = <T extends EmptyObject>({\n children,\n storage,\n user: inputUser,\n signOut: inputSignOut,\n}: {\n children: ReactNode;\n storage: AuthStorage;\n user?: User<T> | null;\n signOut?: () => Promise<void>;\n}) => {\n const { isLoading: authLoading, error: authError } = useAuth();\n const session = useSession();\n const { accessToken } = useToken();\n const { signIn, signOut } = useAuth();\n\n const fetchUser = async (): Promise<User | null> => {\n if (!accessToken) {\n return null;\n }\n const userSession = new GenericUserSession(storage);\n return userSession.get();\n };\n\n const {\n data: user,\n isLoading: userLoading,\n error: userError,\n }: UseQueryResult<User<T> | null, Error> = useQuery({\n queryKey: [\"user\", session?.idToken],\n queryFn: fetchUser,\n enabled: !!session?.idToken, // Only run the query if we have an access token\n });\n\n const isLoading = authLoading || userLoading;\n const error = authError || userError;\n\n return (\n <UserContext.Provider\n value={{\n user: (inputUser || user) ?? null,\n isLoading,\n error,\n signIn,\n signOut: inputSignOut || signOut,\n }}\n >\n {children}\n </UserContext.Provider>\n );\n};\n\nexport type { UserContextType };\n\nexport { UserProvider, UserContext };\n","\"use client\";\nimport { useContext } from \"react\";\n\nimport { AuthContext } from \"@/shared/AuthContext.tsx\";\n\nconst useAuth = () => {\n const context = useContext(AuthContext);\n\n if (!context) {\n throw new Error(\"useAuth must be used within an AuthProvider\");\n }\n\n return context;\n};\n\nexport { useAuth };\n","import { createContext } from \"react\";\nimport { DisplayMode } from \"@/types.ts\";\n\nexport type AuthContextType = {\n signIn: (displayMode?: DisplayMode) => Promise<void>;\n isAuthenticated: boolean;\n isLoading: boolean;\n error: Error | null;\n signOut: () => Promise<void>;\n};\nexport const AuthContext = createContext<AuthContextType | null>(null);\n","\"use client\";\nimport { useContext } from \"react\";\nimport { TokenContext } from \"@/react/providers/TokenProvider\";\n\nconst useToken = () => {\n const context = useContext(TokenContext);\n\n if (!context) {\n throw new Error(\"useToken must be used within a TokenProvider\");\n }\n\n return context;\n};\n\nexport { useToken };\n","\"use client\";\nimport { createContext, ReactNode, useMemo } from \"react\";\nimport { useMutation, useQueryClient } from \"@tanstack/react-query\";\nimport { useAuth } from \"@/react/hooks/useAuth\";\nimport { useSession } from \"@/react/hooks/useSession\";\nimport { ForwardedTokens, IdToken } from \"@/types\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { convertForwardedTokenFormat } from \"@/lib/jwt.js\";\n\ntype TokenContextType = {\n accessToken: string | null;\n idToken: string | null;\n forwardedTokens: ForwardedTokens;\n refreshToken: () => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n};\n\nconst TokenContext = createContext<TokenContextType | undefined>(undefined);\n\nconst TokenProvider = ({ children }: { children: ReactNode }) => {\n const { isLoading, error: authError } = useAuth();\n const session = useSession();\n const queryClient = useQueryClient();\n\n const refreshTokenMutation = useMutation({\n mutationFn: async () => {\n // Implement token refresh logic here\n throw new Error(\"Method not implemented.\");\n },\n onSuccess: () => {\n // Invalidate and refetch queries that depend on the auth session\n queryClient.invalidateQueries({ queryKey: [\"session\"] });\n },\n });\n\n const decodeTokens = useMemo(() => {\n if (!session?.idToken) return null;\n\n const parsedJWT = parseJWT(session.idToken) as IdToken | null;\n\n if (!parsedJWT) return null;\n\n const { forwardedTokens } = parsedJWT.payload;\n\n return forwardedTokens\n ? convertForwardedTokenFormat(forwardedTokens)\n : null;\n }, [session?.idToken]);\n\n const value = useMemo(\n () => ({\n accessToken: session.accessToken || null,\n idToken: session.idToken || null,\n forwardedTokens: decodeTokens || {},\n refreshToken: refreshTokenMutation.mutateAsync,\n isLoading,\n error: (authError || refreshTokenMutation.error) as Error | null,\n }),\n [\n session.accessToken,\n session.idToken,\n decodeTokens,\n refreshTokenMutation.mutateAsync,\n refreshTokenMutation.error,\n isLoading,\n authError,\n ],\n );\n\n return (\n <TokenContext.Provider value={value}>{children}</TokenContext.Provider>\n );\n};\n\nexport type { TokenContextType };\nexport { TokenProvider, TokenContext };\n","\"use client\";\nimport { useContext } from \"react\";\nimport { SessionContext } from \"@/react/providers/SessionProvider\";\n\n// TokenProvider will use this internal context to access session\nconst useSession = () => {\n const context = useContext(SessionContext);\n if (!context) {\n throw new Error(\"useSession must be used within an SessionProvider\");\n }\n return context;\n};\n\nexport { useSession };\n","\"use client\";\nimport { SessionData } from \"@/types\";\nimport {\n createContext,\n Dispatch,\n ReactNode,\n RefObject,\n SetStateAction,\n} from \"react\";\n\nexport type SessionProviderOutput = SessionData & {\n iframeRef: RefObject<HTMLIFrameElement> | null;\n setAuthResponseUrl: Dispatch<SetStateAction<string | null>>;\n};\nconst defaultSession: SessionProviderOutput = {\n authenticated: false,\n idToken: undefined,\n accessToken: undefined,\n displayMode: \"iframe\",\n iframeRef: null,\n setAuthResponseUrl: () => {},\n};\n\n// Context for exposing session specifically to the TokenProvider\nconst SessionContext = createContext<SessionProviderOutput>(defaultSession);\n\ntype SessionContextType = {\n children: ReactNode;\n session?: SessionData | null;\n iframeRef: RefObject<HTMLIFrameElement> | null;\n setAuthResponseUrl: Dispatch<SetStateAction<string | null>>;\n};\n\nconst SessionProvider = ({\n children,\n session,\n iframeRef,\n setAuthResponseUrl,\n}: SessionContextType) => (\n <SessionContext.Provider\n value={{ ...(session || defaultSession), iframeRef, setAuthResponseUrl }}\n >\n {children}\n </SessionContext.Provider>\n);\n\nexport type { SessionContextType };\nexport { SessionProvider, SessionContext };\n","\"use client\";\nimport {\n ReactNode,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport { useMutation, useQuery, useQueryClient } from \"@tanstack/react-query\";\nimport { Config, DisplayMode } from \"@/types\";\nimport { CivicAuthIframeContainer } from \"@/react/components/CivicAuthIframeContainer\";\nimport { TokenProvider } from \"@/react/providers/TokenProvider\";\nimport { SessionProvider } from \"@/react/providers/SessionProvider\";\nimport { DEFAULT_SCOPES } from \"@/constants\";\nimport { authConfig } from \"@/config\";\nimport { LoadingIcon } from \"@/react/components/LoadingIcon\";\nimport { isWindowInIframe } from \"@/lib/windowUtil\";\nimport { AuthContext } from \"@/shared/AuthContext\";\nimport {\n BrowserAuthenticationInitiator,\n BrowserAuthenticationService,\n} from \"@/services/AuthenticationService\";\nimport { AuthenticationResolver, PKCEConsumer } from \"@/services/types\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE\";\nimport { generateState } from \"@/lib/oauth\";\nimport { LocalStorageAdapter } from \"@/browser/storage\";\nimport { ConfigProvider } from \"@/react/providers/ConfigProvider\";\nimport { getUser } from \"./session\";\nimport { GenericUserSession } from \"./UserSession\";\n\n// Global this object setup\nlet globalThisObject;\nif (typeof window !== \"undefined\") {\n globalThisObject = window;\n} else if (typeof global !== \"undefined\") {\n globalThisObject = global;\n} else {\n globalThisObject = Function(\"return this\")();\n}\nglobalThisObject.globalThis = globalThisObject;\n\nexport type AuthProviderProps = {\n children: ReactNode;\n clientId: string;\n redirectUrl?: string;\n nonce?: string;\n config?: Config;\n onSignIn?: (error?: Error) => void;\n onSignOut?: () => void;\n pkceConsumer?: PKCEConsumer;\n modalIframe?: boolean;\n};\n\nfunction BlockDisplay({ children }: { children: ReactNode }) {\n return (\n <div className=\"cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-white\">\n <div className=\"cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-bg-white\">\n {children}\n </div>\n </div>\n );\n}\n\nconst AuthProvider = ({\n children,\n clientId,\n redirectUrl: inputRedirectUrl,\n config = authConfig,\n onSignIn,\n onSignOut,\n pkceConsumer,\n nonce,\n modalIframe = true,\n}: AuthProviderProps) => {\n const [iframeUrl, setIframeUrl] = useState<string | null>(null);\n const [currentUrl, setCurrentUrl] = useState<string | null>(null);\n const [isInIframe, setIsInIframe] = useState(false);\n const [authResponseUrl, setAuthResponseUrl] = useState<string | null>(null);\n const [tokenExchangeError, setTokenExchangeError] = useState<Error>();\n const [displayMode, setDisplayMode] = useState<DisplayMode>(\"iframe\");\n const [browserAuthenticationInitiator, setBrowserAuthenticationInitiator] =\n useState<BrowserAuthenticationInitiator | null>();\n const [showIFrame, setShowIFrame] = useState(false);\n const [isRedirecting, setIsRedirecting] = useState(false);\n const queryClient = useQueryClient();\n const iframeRef = useRef<HTMLIFrameElement>(null);\n\n // TODO maybe we want to support or derive serverTokenExchange another way?\n const serverTokenExchange =\n pkceConsumer instanceof ConfidentialClientPKCEConsumer;\n // check if the current window is in an iframe with the iframe id, and set an isInIframe state\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n setCurrentUrl(globalThis.window.location.href);\n const isInIframeVal = isWindowInIframe(globalThis.window);\n setIsInIframe(isInIframeVal);\n }\n }, []);\n\n const redirectUrl = useMemo(\n () => (inputRedirectUrl || currentUrl || \"\").split(\"?\")[0],\n [currentUrl, inputRedirectUrl],\n );\n\n const [authService, setAuthService] = useState<AuthenticationResolver>();\n\n useEffect(() => {\n if (!currentUrl) return;\n BrowserAuthenticationService.build({\n clientId,\n redirectUrl,\n oauthServer: config.oauthServer,\n scopes: DEFAULT_SCOPES,\n displayMode,\n }).then(setAuthService);\n }, [currentUrl, clientId, redirectUrl, config, displayMode]);\n\n const {\n data: session,\n isLoading,\n error,\n } = useQuery({\n queryKey: [\n \"session\",\n authResponseUrl,\n iframeUrl,\n currentUrl,\n isInIframe,\n authService,\n ],\n queryFn: async () => {\n if (!authService) {\n return { authenticated: false };\n }\n const url = new URL(\n authResponseUrl\n ? authResponseUrl\n : globalThis.window.location.href || \"\",\n );\n\n const code = url.searchParams.get(\"code\");\n const state = url.searchParams.get(\"state\");\n if (!serverTokenExchange && code && state && !isInIframe) {\n try {\n console.log(\"AuthProvider useQuery code\", {\n isInIframe,\n code,\n state,\n });\n await authService.tokenExchange(code, state);\n const clientStorage = new LocalStorageAdapter();\n const user = await getUser(clientStorage);\n if (!user) {\n throw new Error(\"Failed to get user info\");\n }\n\n const userSession = new GenericUserSession(clientStorage);\n userSession.set(user);\n\n onSignIn?.(); // Call onSignIn without an error if successful\n return authService.getSessionData();\n } catch (error) {\n setTokenExchangeError(error as Error);\n onSignIn?.(\n error instanceof Error ? error : new Error(\"Failed to sign in\"),\n ); // Pass the error to onSignIn\n return { authenticated: false };\n }\n }\n // if we have existing tokens, then validate them and return the session data\n // otherwise check if we have a code in the url and exchange it for tokens\n // if we have neither, return undefined\n const existingSessionData = await authService.validateExistingSession();\n if (existingSessionData.authenticated) {\n return existingSessionData;\n }\n return existingSessionData;\n },\n });\n\n const signOutMutation = useMutation({\n mutationFn: async () => {\n // Implement signOut logic here\n const authInitiator = getAuthInitiator();\n authInitiator?.signOut();\n setIframeUrl(null);\n setShowIFrame(false);\n setAuthResponseUrl(null);\n onSignOut?.();\n },\n onSuccess: () => {\n queryClient.setQueryData(\n [\n \"session\",\n authResponseUrl,\n iframeUrl,\n currentUrl,\n isInIframe,\n authService,\n ],\n null,\n );\n },\n });\n\n const getAuthInitiator = useCallback(\n (overrideDisplayMode?: DisplayMode) => {\n const useDisplayMode = overrideDisplayMode || displayMode;\n if (!pkceConsumer) {\n return null;\n }\n return (\n browserAuthenticationInitiator ||\n new BrowserAuthenticationInitiator({\n pkceConsumer, // generate and retrieve the challenge client-side\n clientId,\n redirectUrl,\n state: generateState(useDisplayMode),\n scopes: DEFAULT_SCOPES,\n displayMode: useDisplayMode,\n oauthServer: config.oauthServer,\n // the endpoints to use for the login (if not obtained from the auth server\n endpointOverrides: config.endpoints,\n nonce,\n })\n );\n },\n [\n displayMode,\n browserAuthenticationInitiator,\n clientId,\n redirectUrl,\n config.oauthServer,\n config.endpoints,\n pkceConsumer,\n nonce,\n ],\n );\n\n const signIn = useCallback(\n async (overrideDisplayMode: DisplayMode = \"iframe\") => {\n setDisplayMode(overrideDisplayMode);\n const authInitiator = getAuthInitiator(overrideDisplayMode);\n setBrowserAuthenticationInitiator(authInitiator);\n if (overrideDisplayMode === \"iframe\") {\n setShowIFrame(true);\n } else if (overrideDisplayMode === \"redirect\") {\n setIsRedirecting(true);\n }\n authInitiator?.signIn(iframeRef.current);\n },\n [getAuthInitiator],\n );\n const isAuthenticated = useMemo(\n () => (session ? session.authenticated : false),\n [session],\n );\n\n const {\n data: autoSignIn,\n isLoading: autoSignInLoading,\n error: autoSignInError,\n } = useQuery({\n queryKey: [\"autoSignIn\", modalIframe, redirectUrl, isAuthenticated],\n queryFn: async () => {\n if (\n !modalIframe &&\n redirectUrl &&\n !isAuthenticated &&\n iframeRef.current\n ) {\n signIn(\"iframe\");\n }\n return true;\n },\n refetchOnWindowFocus: false,\n });\n\n const value = useMemo(\n () => ({\n isLoading,\n error: error as Error | null,\n signOut: async () => {\n await signOutMutation.mutateAsync();\n },\n isAuthenticated,\n signIn,\n }),\n [isLoading, error, signOutMutation, isAuthenticated, signIn],\n );\n return (\n <AuthContext.Provider value={value}>\n <ConfigProvider\n config={config}\n redirectUrl={redirectUrl}\n modalIframe={modalIframe}\n serverTokenExchange={serverTokenExchange}\n >\n <SessionProvider\n session={session}\n setAuthResponseUrl={setAuthResponseUrl}\n iframeRef={iframeRef}\n >\n <TokenProvider>\n {modalIframe && !isInIframe && !session?.authenticated && (\n <div\n style={showIFrame ? { display: \"block\" } : { display: \"none\" }}\n >\n <CivicAuthIframeContainer\n onClose={() => setShowIFrame(false)}\n />\n </div>\n )}\n {modalIframe && (isInIframe || isRedirecting || isLoading) && (\n <BlockDisplay>\n <LoadingIcon />\n </BlockDisplay>\n )}\n {(tokenExchangeError || error) && (\n <BlockDisplay>\n <div>\n Error: {(tokenExchangeError || (error as Error)).message}\n </div>\n </BlockDisplay>\n )}\n {children}\n </TokenProvider>\n </SessionProvider>\n </ConfigProvider>\n </AuthContext.Provider>\n );\n};\n\nexport { AuthProvider };\n","\"use client\";\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport { LoadingIcon } from \"@/react/components/LoadingIcon\";\nimport { CloseIcon } from \"@/react/components/CloseIcon\";\nimport { CivicAuthIframe } from \"@/react/components/CivicAuthIframe\";\nimport { useAuth, useConfig, useSession } from \"@/react/hooks\";\nimport React from \"react\";\nimport { TOKEN_EXCHANGE_TRIGGER_TEXT } from \"@/constants\";\n\ntype CivicAuthIframeContainerProps = {\n onClose?: () => void;\n closeOnRedirect?: boolean;\n};\n\nfunction NoChrome({\n children,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return <div className=\"cac-relative\">{children}</div>;\n}\n\nfunction IframeChrome({\n children,\n onClose,\n}: {\n children: React.ReactNode;\n onClose?: () => void;\n}) {\n return (\n <div\n className=\"cac-absolute cac-left-0 cac-top-0 cac-z-50 cac-flex cac-h-screen cac-w-screen cac-items-center cac-justify-center cac-bg-neutral-950 cac-bg-opacity-50\"\n onClick={onClose}\n >\n <div\n className=\"cac-relative cac-rounded-3xl cac-bg-white cac-p-6 cac-shadow-lg\"\n onClick={(e) => e.stopPropagation()}\n >\n <button\n className=\"cac-absolute cac-right-4 cac-top-4 cac-flex cac-cursor-pointer cac-items-center cac-justify-center cac-border-none cac-bg-transparent cac-p-1 cac-text-neutral-400\"\n onClick={onClose}\n >\n <CloseIcon />\n </button>\n\n {children}\n </div>\n </div>\n );\n}\nconst CivicAuthIframeContainer = ({\n onClose,\n closeOnRedirect = true,\n}: CivicAuthIframeContainerProps) => {\n const [isLoading, setIsLoading] = useState(true);\n const { isLoading: isAuthLoading } = useAuth();\n const config = useConfig();\n const { setAuthResponseUrl, iframeRef } = useSession();\n const processIframeUrl = useCallback(() => {\n if (iframeRef && iframeRef.current && iframeRef.current.contentWindow) {\n try {\n const iframeUrl = iframeRef.current.contentWindow.location.href;\n // we know that oauth has finished when the iframe redirects to our redirectUrl\n if (iframeUrl.startsWith(config.redirectUrl)) {\n // we still want to show the spinner during redirect\n setIsLoading(true);\n const iframeBody =\n iframeRef.current.contentWindow.document.body.innerHTML;\n\n // If we're doing a server token exchange, we need to call the server a second time\n // using a fetch so that we're on the same domain and cookies can be sent and read\n // The server will use the presence of the code_verifier cookie to determine whether to do a token exchange or not.\n // On the initial (3rd party) redirect from the auth server, the cookie won't be sent, so the server-side callback route will just render a blank page,\n // and we'll do the exchange request from here, which will include the cookies.\n if (iframeBody.includes(TOKEN_EXCHANGE_TRIGGER_TEXT)) {\n console.log(\n `${TOKEN_EXCHANGE_TRIGGER_TEXT}, calling callback URL again...`,\n );\n const params = new URL(iframeUrl).searchParams;\n fetch(`${config.redirectUrl}?${params.toString()}`);\n } else {\n // if we're doing token-exchange in the client, we can just set the authResponseUrl\n // to be handled by the auth provider\n setAuthResponseUrl(iframeUrl);\n }\n\n if (closeOnRedirect) onClose?.();\n return true; // Successfully processed the URL\n }\n } catch {\n // If we get here, the iframe hasn't redirected to our origin yet\n console.log(\"Waiting for redirect...\");\n }\n }\n return false; // Haven't processed the URL yet\n }, [\n closeOnRedirect,\n config.redirectUrl,\n iframeRef,\n onClose,\n setAuthResponseUrl,\n ]);\n\n const intervalId = useRef<NodeJS.Timeout>();\n\n const handleEscape = useCallback(\n (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n onClose?.();\n }\n },\n [onClose],\n );\n\n // handle Escape\n useEffect(() => {\n window.addEventListener(\"keydown\", handleEscape);\n\n return () => window.removeEventListener(\"keydown\", handleEscape);\n });\n\n const handleIframeLoad = () => {\n setIsLoading(false);\n console.log(\"handleIframeLoad\");\n if (processIframeUrl() && intervalId.current) {\n clearInterval(intervalId.current);\n }\n };\n const showLoadingIcon =\n isLoading || isAuthLoading || !iframeRef?.current?.getAttribute(\"src\");\n\n const WrapperComponent = config.modalIframe ? IframeChrome : NoChrome;\n\n return (\n <WrapperComponent onClose={onClose}>\n {showLoadingIcon && (\n <div className=\"cac-absolute cac-inset-0 cac-flex cac-items-center cac-justify-center cac-rounded-3xl cac-bg-white\">\n <LoadingIcon />\n </div>\n )}\n\n <CivicAuthIframe ref={iframeRef} onLoad={handleIframeLoad} />\n </WrapperComponent>\n );\n};\n\nexport type { CivicAuthIframeContainerProps };\n\nexport { CivicAuthIframeContainer };\n","const LoadingIcon = () => (\n <div role=\"status\">\n <svg\n aria-hidden=\"true\"\n className=\"cac-inline cac-h-8 cac-w-8 cac-animate-spin cac-fill-neutral-600 cac-text-neutral-200 dark:cac-fill-neutral-300 dark:cac-text-neutral-600\"\n viewBox=\"0 0 100 101\"\n fill=\"none\"\n xmlns=\"http://www.w3.org/2000/svg\"\n >\n <path\n d=\"M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z\"\n fill=\"currentColor\"\n />\n <path\n d=\"M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z\"\n fill=\"currentFill\"\n />\n </svg>\n <span className=\"cac-sr-only\">Loading...</span>\n </div>\n);\n\nexport { LoadingIcon };\n","const CloseIcon = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"lucide lucide-x\"\n >\n <path d=\"M18 6 6 18\" />\n <path d=\"m6 6 12 12\" />\n </svg>\n);\n\nexport { CloseIcon };\n","\"use client\";\nimport { IFRAME_ID } from \"@/constants\";\nimport { forwardRef } from \"react\";\n\ntype CivicAuthIframeProps = {\n onLoad?: () => void;\n};\n\nconst CivicAuthIframe = forwardRef<HTMLIFrameElement, CivicAuthIframeProps>(\n ({ onLoad }, ref) => {\n return (\n <iframe\n id={IFRAME_ID}\n ref={ref}\n className=\"cac-h-[26rem] cac-w-80 cac-border-none\"\n onLoad={onLoad}\n />\n );\n },\n);\n\nCivicAuthIframe.displayName = \"CivicAuthIframe\";\n\nexport type { CivicAuthIframeProps };\n\nexport { CivicAuthIframe };\n","import { Config } from \"@/types\";\n\nexport const authConfig: Config = {\n // TODO change this to the production URL once we're out of beta\n oauthServer: \"https://auth-dev.civic.com/oauth/\",\n};\n","\"use client\";\nimport { authConfig } from \"@/config\";\nimport { Config } from \"@/types\";\nimport { createContext, ReactNode } from \"react\";\n\nexport type ConfigProviderOutput = {\n config: Config;\n redirectUrl: string;\n modalIframe: boolean;\n serverTokenExchange: boolean;\n};\nconst defaultConfig: ConfigProviderOutput = {\n config: authConfig,\n redirectUrl: \"\",\n modalIframe: true,\n serverTokenExchange: false,\n};\n// Context for exposing Config specifically to the TokenProvider\nconst ConfigContext = createContext<ConfigProviderOutput>(defaultConfig);\n\ntype ConfigContextType = {\n children: ReactNode;\n config: Config;\n redirectUrl: string;\n modalIframe?: boolean;\n serverTokenExchange: boolean;\n};\n\nconst ConfigProvider = ({\n children,\n config,\n redirectUrl,\n modalIframe,\n serverTokenExchange,\n}: ConfigContextType) => (\n <ConfigContext.Provider\n value={{\n config,\n redirectUrl,\n modalIframe: !!modalIframe,\n serverTokenExchange,\n }}\n >\n {children}\n </ConfigContext.Provider>\n);\n\nexport type { ConfigContextType };\nexport { ConfigProvider, ConfigContext };\n","\"use client\";\nimport { AuthProvider, AuthProviderProps } from \"./AuthProvider\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\n\n// adding the styles import here to be added to the bundle\nimport \"@civic/auth/styles.css\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE\";\nimport { UserProvider } from \"./UserProvider\";\nimport { LocalStorageAdapter } from \"@/browser/storage\";\n\nconst queryClient = new QueryClient();\n\ntype CivicAuthProviderProps = Omit<AuthProviderProps, \"pkceConsumer\">;\n\nconst CivicAuthProvider = ({ children, ...props }: CivicAuthProviderProps) => {\n return (\n <QueryClientProvider client={queryClient}>\n <AuthProvider\n {...props}\n pkceConsumer={new BrowserPublicClientPKCEProducer()}\n >\n <UserProvider storage={new LocalStorageAdapter()}>\n {children}\n </UserProvider>\n </AuthProvider>\n </QueryClientProvider>\n );\n};\n\nexport { CivicAuthProvider, type CivicAuthProviderProps };\n","\"use client\";\n/**\n * A very small context provider for the user object - it takes the user object from the cookie and provides it to the app.\n */\nimport { useEffect, useState } from \"react\";\nimport { AuthProvider, AuthProviderProps } from \"@/shared/AuthProvider.js\";\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport { resolveCallbackUrl } from \"@/nextjs/utils.js\";\n\n// adding the styles import here to be added to the bundle\nimport \"@civic/auth/styles.css\";\nimport { ConfidentialClientPKCEConsumer } from \"@/services/PKCE.js\";\nimport { NextjsClientStorage } from \"@/nextjs/cookies\";\nimport { UserProvider } from \"@/shared/UserProvider\";\nimport { useUserCookie } from \"../hooks\";\n\nconst queryClient = new QueryClient();\n\nexport type NextCivicAuthProviderProps = Omit<AuthProviderProps, \"clientId\">;\n\nexport const CivicNextAuthProvider = ({\n children,\n ...props\n}: NextCivicAuthProviderProps) => {\n const [redirectUrl, setRedirectUrl] = useState<string>(\"\");\n const { clientId, oauthServer, callbackUrl, challengeUrl, logoutUrl } =\n resolveAuthConfig();\n\n useEffect(() => {\n if (typeof globalThis.window !== \"undefined\") {\n const currentUrl = globalThis.window.location.href;\n setRedirectUrl(resolveCallbackUrl(resolveAuthConfig(), currentUrl));\n }\n }, [callbackUrl]);\n const user = useUserCookie();\n\n const signOut = async (): Promise<void> => {\n await fetch(logoutUrl);\n props.onSignOut?.();\n return;\n };\n return (\n <QueryClientProvider client={queryClient}>\n <AuthProvider\n {...props}\n redirectUrl={redirectUrl}\n config={{ oauthServer }}\n clientId={clientId}\n pkceConsumer={new ConfidentialClientPKCEConsumer(challengeUrl)}\n >\n <UserProvider\n storage={new NextjsClientStorage()}\n user={user}\n signOut={signOut}\n >\n {children}\n </UserProvider>\n </AuthProvider>\n </QueryClientProvider>\n );\n};\n","\"use client\";\nimport { useEffect, useRef } from \"react\";\nimport { useRouter } from \"next/navigation.js\";\nimport { useQuery } from \"@tanstack/react-query\";\nimport { getCookieValue } from \"@/lib/cookies.js\";\n\nconst getUserFromCookie = () => {\n const userCookie = getCookieValue(\"user\", globalThis.window);\n return userCookie;\n};\n\nexport const useUserCookie = () => {\n const hasRunRef = useRef(false);\n const router = useRouter();\n\n const { data: user } = useQuery({\n queryKey: [\"user\"],\n queryFn: () => getUserFromCookie(),\n refetchInterval: 2000,\n refetchIntervalInBackground: true,\n enabled: !hasRunRef.current,\n refetchOnWindowFocus: true,\n });\n\n useEffect(() => {\n if (user) {\n if (!hasRunRef.current) {\n hasRunRef.current = true;\n router.refresh();\n }\n } else {\n hasRunRef.current = false;\n }\n }, [user, router]);\n\n return user;\n};\n","const getCookieValue = (key: string, window: Window) => {\n const cookie = window.document.cookie;\n if (!cookie) return null;\n const cookies = cookie.split(\";\");\n for (const c of cookies) {\n const [name, value] = c.trim().split(\"=\");\n if (value && name === key) {\n try {\n return JSON.parse(decodeURIComponent(value));\n } catch (e) {\n console.log(\"Error parsing cookie value\", e);\n return value;\n }\n }\n }\n return null;\n};\nexport { getCookieValue };\n","\"use client\";\nimport { useContext } from \"react\";\nimport { ConfigContext } from \"@/react/providers/ConfigProvider\";\n\n// TokenProvider will use this internal context to access Config\nconst useConfig = () => {\n const context = useContext(ConfigContext);\n if (!context) {\n throw new Error(\"useConfig must be used within an ConfigProvider\");\n }\n return context;\n};\n\nexport { useConfig };\n","\"use client\";\nimport { useUser } from \"@/react/hooks\";\nimport { DisplayMode } from \"@/types\";\nimport { cn } from \"@/utils\";\nimport { useCallback, useEffect, useState } from \"react\";\n\nconst ChevronDown = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"lucide lucide-chevron-down\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n);\n\nconst ChevronUp = () => (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n width=\"24\"\n height=\"24\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className=\"lucide lucide-chevron-up\"\n >\n <path d=\"m18 15-6-6-6 6\" />\n </svg>\n);\n\nconst UserButton = ({\n displayMode,\n className,\n}: {\n displayMode?: DisplayMode;\n className?: string;\n}) => {\n const [isOpen, setIsOpen] = useState(false);\n const { user, signIn, signOut } = useUser();\n\n const handleClickOutside = useCallback((event: MouseEvent) => {\n const target = event.target as HTMLElement;\n\n if (!target.closest(\"#civic-dropdown-container\")) {\n setIsOpen(false);\n }\n }, []);\n\n const handleSignOut = useCallback(async () => {\n signOut();\n\n setIsOpen(false);\n }, [signOut]);\n\n const handleSignIn = useCallback(async () => {\n await signIn(displayMode);\n\n setIsOpen(false);\n }, [signIn, displayMode]);\n\n const handleEscape = useCallback((event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n setIsOpen(false);\n }\n }, []);\n\n useEffect(() => {\n if (isOpen) {\n window.addEventListener(\"click\", handleClickOutside);\n\n window.addEventListener(\"keydown\", handleEscape);\n }\n\n return () => {\n window.removeEventListener(\"click\", handleClickOutside);\n\n window.removeEventListener(\"keydown\", handleEscape);\n };\n }, [handleClickOutside, handleEscape, isOpen]);\n\n if (user) {\n return (\n <div className=\"cac-relative\" id=\"civic-dropdown-container\">\n <button\n className={cn(\n \"cac-flex cac-w-full cac-items-center cac-justify-between cac-gap-2 cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-text-neutral-500 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={() => setIsOpen((isOpen) => !isOpen)}\n >\n {user?.picture ? (\n <span className=\"cac-relative cac-flex cac-h-10 cac-w-10 cac-shrink-0 cac-gap-2 cac-overflow-hidden cac-rounded-full\">\n <img\n className=\"cac-h-full cac-w-full cac-object-cover\"\n src={user.picture}\n alt={user?.name || user?.email}\n />\n </span>\n ) : (\n <div />\n )}\n\n <span>{user?.name || user?.email}</span>\n\n {isOpen ? <ChevronUp /> : <ChevronDown />}\n </button>\n <div\n className={\n isOpen\n ? \"cac-absolute cac-right-0 cac-mt-2 cac-w-full cac-rounded-lg cac-bg-white cac-py-2 cac-text-neutral-500 cac-shadow-xl\"\n : \"cac-hidden\"\n }\n >\n <ul>\n <li>\n <button\n className=\"cac-block cac-w-full cac-px-4 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\"\n onClick={handleSignOut}\n >\n Logout\n </button>\n </li>\n </ul>\n </div>\n </div>\n );\n }\n\n return (\n <button\n data-testid=\"sign-in-button\"\n className={cn(\n \"cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={handleSignIn}\n >\n Sign in\n </button>\n );\n};\n\nexport { UserButton };\n","\"use client\";\nimport { cn } from \"@/utils\";\nimport { DisplayMode } from \"@/types\";\nimport { useUser } from \"@/react/hooks\";\n\nconst SignInButton = ({\n displayMode,\n className,\n}: {\n displayMode?: DisplayMode;\n className?: string;\n}) => {\n const { signIn } = useUser();\n\n return (\n <button\n data-testid=\"sign-in-button\"\n className={cn(\n \"cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={() => signIn(displayMode)}\n >\n Sign In\n </button>\n );\n};\n\nexport { SignInButton };\n","\"use client\";\nimport { cn } from \"@/utils\";\nimport { useUser } from \"@/react/hooks\";\n\nconst SignOutButton = ({ className }: { className?: string }) => {\n const { signOut } = useUser();\n\n return (\n <button\n className={cn(\n \"cac-rounded-full cac-border cac-border-neutral-500 cac-px-3 cac-py-2 cac-transition-colors hover:cac-bg-neutral-200 hover:cac-bg-opacity-50\",\n className,\n )}\n onClick={() => signOut()}\n >\n Sign Out\n </button>\n );\n};\n\nexport { SignOutButton };\n","/**\n * Trigger a backend API that logs the user out and then redirects to the homepage (TODO parameterize the redirect)\n */\nimport { resolveAuthConfig } from \"@/nextjs/config.js\";\nimport React, { ReactNode } from \"react\";\n\nconst NextLogOut = ({ children }: { children: ReactNode }) => {\n const config = resolveAuthConfig();\n const logoutUrl = `${config.logoutUrl}`;\n\n return <a href={logoutUrl}>{children}</a>;\n};\n\nexport { NextLogOut };\n"],"mappings":"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","names":["useContext","createContext","useContext","createContext","useContext","createContext","createContext","useContext","jsx","createContext","queryClient","useContext","jsx","createContext","useCallback","useEffect","useMemo","useRef","useState","useMutation","useQuery","useQueryClient","jsx","jsx","jsxs","jsx","jsx","jsxs","createContext","jsx","jsx","jsxs","useState","queryClient","useQueryClient","useRef","useEffect","useMemo","useQuery","error","useMutation","useCallback","jsx","useEffect","useState","QueryClient","QueryClientProvider","jsx","queryClient","QueryClient","useState","useEffect","_a","QueryClientProvider","useContext","useEffect","useRef","useQuery","window","useRef","useQuery","useEffect","useContext","useContext","useCallback","useEffect","useState","jsx","jsxs","useState","useCallback","useEffect","isOpen","jsx","jsx","jsx"]}
|
package/dist/server.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
|
|
8
|
-
var
|
|
8
|
+
var _chunkCHY6AHA7js = require('./chunk-CHY6AHA7.js');
|
|
9
9
|
require('./chunk-CRTRMMJ7.js');
|
|
10
10
|
|
|
11
11
|
|
|
@@ -14,5 +14,5 @@ require('./chunk-CRTRMMJ7.js');
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
exports.CookieStorage =
|
|
17
|
+
exports.CookieStorage = _chunkCHY6AHA7js.CookieStorage; exports.buildLoginUrl = _chunkCHY6AHA7js.buildLoginUrl; exports.getUser = _chunkCHY6AHA7js.getUser; exports.isLoggedIn = _chunkCHY6AHA7js.isLoggedIn; exports.refreshTokens = _chunkCHY6AHA7js.refreshTokens; exports.resolveOAuthAccessCode = _chunkCHY6AHA7js.resolveOAuthAccessCode;
|
|
18
18
|
//# sourceMappingURL=server.js.map
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/
|
|
1
|
+
{"version":3,"sources":["/Users/pedroapfilho/dev/civic-auth/packages/civic-auth-client/dist/server.js"],"names":[],"mappings":"AAAA;AACE;AACA;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B,+BAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACA;AACF,+UAAC","file":"/Users/pedroapfilho/dev/civic-auth/packages/civic-auth-client/dist/server.js"}
|
package/dist/server.mjs
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@civic/auth",
|
|
3
|
-
"version": "0.0.1-beta.
|
|
3
|
+
"version": "0.0.1-beta.16",
|
|
4
4
|
"files": [
|
|
5
5
|
"dist"
|
|
6
6
|
],
|
|
@@ -84,13 +84,13 @@
|
|
|
84
84
|
"@repo/typescript-config": "0.0.0",
|
|
85
85
|
"@repo/eslint-config": "0.0.0"
|
|
86
86
|
},
|
|
87
|
-
"
|
|
87
|
+
"peerDependencies": {
|
|
88
88
|
"next": "^14"
|
|
89
89
|
},
|
|
90
90
|
"scripts": {
|
|
91
91
|
"build": "tsup",
|
|
92
92
|
"prepublish": "tsup",
|
|
93
|
-
"dev
|
|
93
|
+
"dev": "tsup --watch",
|
|
94
94
|
"test": "vitest",
|
|
95
95
|
"lint": "eslint \"src/**/*.ts*\"",
|
|
96
96
|
"lint:fix": "pnpm lint --fix",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/shared/storage.ts","../src/constants.ts","../src/shared/types.ts","../src/shared/util.ts","../src/lib/oauth.ts","../src/utils.ts","../src/lib/jwt.ts","../src/shared/UserSession.ts","../src/services/PKCE.ts","../src/browser/storage.ts","../src/services/AuthenticationService.ts","../src/lib/windowUtil.ts","../src/server/ServerAuthenticationResolver.ts","../src/server/login.ts","../src/shared/session.ts","../src/shared/GenericAuthenticationRefresher.ts","../src/server/refresh.ts"],"sourcesContent":["import { AuthStorage, SessionData, UnknownObject, User } from \"@/types.js\";\n\ntype SameSiteOption = \"strict\" | \"lax\" | \"none\";\n\nexport interface SessionStorage {\n get(): SessionData;\n getUser(): User<UnknownObject> | null;\n set(data: Partial<SessionData>): void;\n setUser(data: User<UnknownObject> | null): void;\n clear(): void;\n}\n\nexport type CookieStorageSettings = {\n httpOnly: boolean;\n secure: boolean;\n sameSite: SameSiteOption;\n expires: Date;\n path: string;\n};\n\nexport const DEFAULT_COOKIE_DURATION = 60 * 15; // 15 minutes\n\nexport abstract class CookieStorage implements AuthStorage {\n protected settings: CookieStorageSettings;\n protected constructor(settings: Partial<CookieStorageSettings> = {}) {\n this.settings = {\n httpOnly: settings.httpOnly ?? true,\n secure: settings.secure ?? true,\n // the callback request comes the auth server\n // 'lax' ensures the code_verifier cookie is sent with the request\n sameSite: settings.sameSite ?? \"lax\",\n expires:\n settings.expires ??\n new Date(Date.now() + 1000 * DEFAULT_COOKIE_DURATION),\n path: settings.path ?? \"/\",\n };\n }\n abstract get(key: string): string | null;\n abstract set(key: string, value: string): void;\n}\n","const DEFAULT_SCOPES = [\n \"openid\",\n \"profile\",\n \"email\",\n \"forwardedTokens\",\n \"offline_access\",\n];\nconst IFRAME_ID = \"civic-auth-iframe\";\n\nconst AUTH_SERVER = \"https://auth-dev.civic.com/oauth\";\n\nconst DEFAULT_OAUTH_GET_PARAMS = [\"code\", \"state\", \"iss\"];\n\nexport { DEFAULT_SCOPES, DEFAULT_OAUTH_GET_PARAMS, IFRAME_ID, AUTH_SERVER };\n","export enum OAuthTokens {\n ID_TOKEN = \"id_token\",\n ACCESS_TOKEN = \"access_token\",\n REFRESH_TOKEN = \"refresh_token\",\n}\n\nexport enum UserStorage {\n USER = \"user\",\n}\n","// Utility functions shared by auth server and client integrations\n// Typically these functions should be used inside AuthenticationInitiator and AuthenticationResolver implementations\n\nimport {\n AuthStorage,\n Endpoints,\n JWTPayload,\n OIDCTokenResponseBody,\n ParsedTokens,\n} from \"@/types.js\";\nimport { OAuthTokens } from \"./types\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { getIssuerVariations, getOauthEndpoints } from \"@/lib/oauth.js\";\nimport * as jose from \"jose\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.js\";\nimport { GenericUserSession } from \"./UserSession\";\n\n/**\n * Given a PKCE code verifier, derive the code challenge using SHA\n */\nexport async function deriveCodeChallenge(\n codeVerifier: string,\n method: \"Plain\" | \"S256\" = \"S256\",\n): Promise<string> {\n if (method === \"Plain\") {\n console.warn(\"Using insecure plain code challenge method\");\n return codeVerifier;\n }\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport async function getEndpointsWithOverrides(\n oauthServer: string,\n endpointOverrides: Partial<Endpoints> = {},\n) {\n const endpoints = await getOauthEndpoints(oauthServer);\n return {\n ...endpoints,\n ...endpointOverrides,\n };\n}\n\nexport async function generateOauthLoginUrl(config: {\n clientId: string;\n scopes: string[];\n state: string;\n redirectUrl: string;\n oauthServer: string;\n nonce?: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n const challenge = await config.pkceConsumer.getCodeChallenge();\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state: config.state,\n scopes: config.scopes,\n });\n // The OAuth2 client supports PKCE, but does not allow passing in a code challenge from some other source\n // It only allows passing in a code verifier which it then hashes itself.\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n if (config.nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", config.nonce);\n }\n // Required by the auth server for offline_access scope\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n\n console.log(\"Generated OAuth URL\", oAuthUrl.toString());\n return oAuthUrl;\n}\n\nexport async function generateOauthLogoutUrl(config: {\n clientId: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n // TODO\n return new URL(\"http://localhost\");\n}\n\nexport function buildOauth2Client(\n clientId: string,\n redirectUri: string,\n endpoints: Endpoints,\n): OAuth2Client {\n return new OAuth2Client(clientId, endpoints.auth, endpoints.token, {\n redirectURI: redirectUri,\n });\n}\n\nexport async function exchangeTokens(\n code: string,\n state: string,\n pkceProducer: PKCEProducer,\n oauth2Client: OAuth2Client,\n oauthServer: string,\n endpoints: Endpoints,\n) {\n const codeVerifier = await pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in state\");\n\n const tokens =\n await oauth2Client.validateAuthorizationCode<OIDCTokenResponseBody>(code, {\n codeVerifier,\n });\n\n // Validate relevant tokens\n try {\n await validateOauth2Tokens(tokens, endpoints, oauth2Client, oauthServer);\n } catch (error) {\n console.error(\"tokenExchange error\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n\n return tokens;\n}\n\nexport function storeTokens(\n storage: AuthStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // store tokens in storage ( TODO we should probably store them against the state to allow multiple logins )\n storage.set(OAuthTokens.ID_TOKEN, tokens.id_token);\n storage.set(OAuthTokens.ACCESS_TOKEN, tokens.access_token);\n if (tokens.refresh_token)\n storage.set(OAuthTokens.REFRESH_TOKEN, tokens.refresh_token);\n}\n\nexport function clearTokens(storage: AuthStorage) {\n Object.values(OAuthTokens).forEach((cookie) => {\n storage.set(cookie, \"\");\n });\n}\nexport function clearUser(storage: AuthStorage) {\n const userSession = new GenericUserSession(storage);\n userSession.set(null);\n}\n\nexport function retrieveTokens(\n storage: AuthStorage,\n): OIDCTokenResponseBody | null {\n const idToken = storage.get(OAuthTokens.ID_TOKEN);\n const accessToken = storage.get(OAuthTokens.ACCESS_TOKEN);\n const refreshToken = storage.get(OAuthTokens.REFRESH_TOKEN);\n\n if (!idToken || !accessToken) return null;\n\n return {\n id_token: idToken,\n access_token: accessToken,\n refresh_token: refreshToken ?? undefined,\n };\n}\n\nexport async function validateOauth2Tokens(\n tokens: OIDCTokenResponseBody,\n endpoints: Endpoints,\n oauth2Client: OAuth2Client,\n issuer: string,\n): Promise<ParsedTokens> {\n const JWKS = jose.createRemoteJWKSet(new URL(endpoints.jwks));\n\n // validate the ID token\n const idTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.id_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n audience: oauth2Client.clientId,\n },\n );\n\n // validate the access token\n const accessTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.access_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n },\n );\n\n return withoutUndefined({\n id_token: idTokenResponse.payload,\n access_token: accessTokenResponse.payload,\n refresh_token: tokens.refresh_token,\n });\n}\n","import { DisplayMode, Endpoints, OpenIdConfiguration } from \"@/types\";\nimport { v4 as uuid } from \"uuid\";\n\nconst getIssuerVariations = (issuer: string): string[] => {\n const issuerWithoutSlash = issuer.endsWith(\"/\")\n ? issuer.slice(0, issuer.length - 1)\n : issuer;\n\n const issuerWithSlash = `${issuerWithoutSlash}/`;\n\n return [issuerWithoutSlash, issuerWithSlash];\n};\n\nconst addSlashIfNeeded = (url: string): string =>\n url.endsWith(\"/\") ? url : `${url}/`;\n\nconst getOauthEndpoints = async (oauthServer: string): Promise<Endpoints> => {\n const openIdConfigResponse = await fetch(\n `${addSlashIfNeeded(oauthServer)}.well-known/openid-configuration`,\n );\n const openIdConfig =\n (await openIdConfigResponse.json()) as OpenIdConfiguration;\n return {\n jwks: openIdConfig.jwks_uri,\n auth: openIdConfig.authorization_endpoint,\n token: openIdConfig.token_endpoint,\n userinfo: openIdConfig.userinfo_endpoint,\n };\n};\n\n/**\n * creates a state string for the OAuth2 flow, encoding the display mode too for future use\n * @param {DisplayMode} displayMode\n * @returns {string}\n */\nconst generateState = (displayMode: DisplayMode): string => {\n const jsonString = JSON.stringify({\n uuid: uuid(),\n displayMode,\n });\n return btoa(jsonString);\n};\n\n/**\n * parses the state string from the OAuth2 flow, decoding the display mode too\n * @param state\n * @param sessionDisplayMode\n * @returns { uuid: string, displayMode: DisplayMode }\n */\nconst displayModeFromState = (\n state: string,\n sessionDisplayMode: DisplayMode | undefined,\n): DisplayMode | undefined => {\n try {\n const jsonString = atob(state);\n return JSON.parse(jsonString).displayMode;\n } catch {\n console.error(\"Failed to parse displayMode from state:\", state);\n return sessionDisplayMode;\n }\n};\n\nexport {\n getIssuerVariations,\n getOauthEndpoints,\n displayModeFromState,\n generateState,\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Checks if a popup window is blocked by the browser.\n *\n * This function attempts to open a small popup window and then checks if it was successfully created.\n * If the popup is blocked by the browser, the function returns `true`. Otherwise, it returns `false`.\n *\n * @returns {boolean} - `true` if the popup is blocked, `false` otherwise.\n */\nconst isPopupBlocked = (): boolean => {\n // First we try to open a small popup window. It either returns a window object or null.\n const popup = window.open(\"\", \"\", \"width=1,height=1\");\n\n // If window.open() returns null, popup is definitely blocked\n if (!popup) {\n return true;\n }\n\n try {\n // Try to access a property of the popup to check if it's usable\n if (typeof popup.closed === \"undefined\") {\n throw new Error(\"Popup is blocked\");\n }\n } catch {\n // Accessing the popup's properties throws an error if the popup is blocked\n return true;\n }\n\n // Close the popup immediately if it was opened\n popup.close();\n return false;\n};\n\nconst cn = (...inputs: ClassValue[]) => {\n return twMerge(clsx(inputs));\n};\n\n// This type narrows T as far as it can by:\n// - removing all keys where the value is `undefined`\n// - making keys that are not undefined required\n// So, for example: given { a: string | undefined, b: string | undefined },\n// if you pass in { a: \"foo\" }, it returns an object of type: { a: string }\ntype WithoutUndefined<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K];\n};\nexport const withoutUndefined = <T extends { [K in keyof T]: unknown }>(\n obj: T,\n): WithoutUndefined<T> => {\n const result = {} as WithoutUndefined<T>;\n\n for (const key in obj) {\n if (obj[key] !== undefined) {\n // TypeScript needs assurance that key is a valid key in WithoutUndefined<T>\n // We use type assertion here\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (result as any)[key] = obj[key];\n }\n }\n\n return result;\n};\n\nexport { cn, isPopupBlocked };\n","import { ForwardedTokens, ForwardedTokensJWT } from \"@/types.js\";\n\nexport const convertForwardedTokenFormat = (\n inputTokens: ForwardedTokensJWT,\n): ForwardedTokens =>\n Object.fromEntries(\n Object.entries(inputTokens).map(([source, tokens]) => [\n source,\n {\n idToken: tokens?.id_token,\n accessToken: tokens?.access_token,\n refreshToken: tokens?.refresh_token,\n },\n ]),\n );\n","import { AuthStorage, ForwardedTokensJWT, User } from \"@/types\";\nimport { UserStorage } from \"./types\";\nimport { convertForwardedTokenFormat } from \"@/lib/jwt\";\n\nexport interface UserSession {\n get(): User | null;\n set(user: User): void;\n}\n\nexport class GenericUserSession implements UserSession {\n constructor(readonly storage: AuthStorage) {}\n\n get(): User | null {\n const user = this.storage.get(UserStorage.USER);\n return user ? JSON.parse(user) : null;\n }\n\n set(user: User | null): void {\n const forwardedTokens = user?.forwardedTokens\n ? convertForwardedTokenFormat(user?.forwardedTokens as ForwardedTokensJWT)\n : null;\n const value = user ? JSON.stringify({ ...user, forwardedTokens }) : \"\";\n this.storage.set(UserStorage.USER, value);\n }\n}\n","import { deriveCodeChallenge } from \"@/shared/util.js\";\nimport { generateCodeVerifier } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.ts\";\nimport { AuthStorage } from \"@/types\";\n\n/** A PKCE consumer that retrieves the challenge from a server endpoint */\nexport class ConfidentialClientPKCEConsumer implements PKCEConsumer {\n constructor(private pkceChallengeEndpoint: string) {}\n async getCodeChallenge(): Promise<string> {\n const response = await fetch(this.pkceChallengeEndpoint);\n const data = (await response.json()) as { challenge: string };\n return data.challenge;\n }\n}\n\n/** A PKCE Producer that can generate and store a code verifier, but is agnostic as to the storage location */\nexport class GenericPublicClientPKCEProducer implements PKCEProducer {\n constructor(private storage: AuthStorage) {}\n\n // if there is already a verifier, return it,\n // If not, create a new one and store it\n async getCodeChallenge(): Promise<string> {\n // let verifier = await this.getCodeVerifier();\n // if (!verifier) {\n const verifier = generateCodeVerifier();\n this.storage.set(\"code_verifier\", verifier);\n // }\n return deriveCodeChallenge(verifier);\n }\n // if there is already a verifier, return it,\n async getCodeVerifier(): Promise<string | null> {\n return this.storage.get(\"code_verifier\");\n }\n}\n\n/** A PKCE Producer that is expected to run on a browser, and does not need a backend */\nexport class BrowserPublicClientPKCEProducer extends GenericPublicClientPKCEProducer {\n constructor() {\n super(new LocalStorageAdapter());\n }\n}\n","import { AuthStorage } from \"@/types\";\n\nexport class LocalStorageAdapter implements AuthStorage {\n get(key: string): string {\n return localStorage.getItem(key) || \"\";\n }\n\n set(key: string, value: string): void {\n localStorage.setItem(key, value);\n }\n}\n","// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport {\n DisplayMode,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n} from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil\";\nimport { DEFAULT_OAUTH_GET_PARAMS } from \"@/constants\";\n\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n oauthServer: string;\n // the endpoints to use for the login (if not obtained from the auth server\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n // the nonce to use for the login\n nonce?: string;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n const url = await generateOauthLoginUrl(this.config);\n\n if (this.config.displayMode === \"iframe\") {\n if (!iframeRef)\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n iframeRef.setAttribute(\"src\", url.toString());\n }\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n if (this.config.displayMode === \"new_tab\") {\n window.open(url.toString(), \"_blank\");\n }\n return url;\n }\n\n async signOut(): Promise<URL> {\n const localStorage = new LocalStorageAdapter();\n clearTokens(localStorage);\n clearUser(localStorage);\n // TODO open the iframe or new tab etc: the logout URL is not currently\n // supported by on the oauth, so just clear state until then\n const url = await generateOauthLogoutUrl(this.config);\n return url;\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(): Promise<URL> {\n return generateOauthLogoutUrl(this.config);\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n super({\n ...config,\n state: generateState(config.displayMode),\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.config.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\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.config.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(new LocalStorageAdapter(), tokens);\n\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.close();\n } else if (parsedDisplayMode === \"redirect\") {\n // these are the default oAuth params that get added to the URL which we want to remove\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n }\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(new LocalStorageAdapter());\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n if (!this.endpoints || !this.oauth2client) await this.init();\n\n // this function will throw if any of the tokens are invalid\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken,\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n },\n this.endpoints!,\n this.oauth2client!,\n this.config.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n","const isWindowInIframe = (window: Window): boolean => {\n if (typeof window !== \"undefined\") {\n // use the window width to determine if we're in an iframe or not\n try {\n if (window?.frameElement?.id === \"civic-auth-iframe\") {\n return true;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_e) {\n // If we get an error, we're not in an iframe\n return false;\n }\n }\n return false;\n};\n\nconst removeParamsWithoutReload = (paramsToRemove: string[]) => {\n const url = new URL(window.location.href);\n paramsToRemove.forEach((param: string) => {\n url.searchParams.delete(param);\n });\n window.history.replaceState({}, \"\", url);\n};\n\nexport { isWindowInIframe, removeParamsWithoutReload };\n","import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { AuthConfig } from \"@/server/config.js\";\nimport {\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.js\";\nimport { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer;\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 this.pkceProducer = new GenericPublicClientPKCEProducer(storage);\n }\n validateExistingSession(): Promise<SessionData> {\n throw new Error(\"Method not implemented.\");\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.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 const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\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.authConfig.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(this.storage, tokens);\n\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\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","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { 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 { AuthConfig } from \"@/server/config.ts\";\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 ?? AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return authSessionService.tokenExchange(code, state);\n}\n\nexport function isLoggedIn(storage: AuthStorage): boolean {\n return !!storage.get(\"id_token\");\n}\n\nexport async function buildLoginUrl(\n config: Pick<AuthConfig, \"oauthServer\" | \"clientId\" | \"redirectUrl\"> & {\n scopes?: string[];\n state?: string;\n nonce?: 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 ?? AUTH_SERVER,\n // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session\n pkceConsumer: pkceProducer,\n });\n\n return authInitiator.signIn();\n}\n","import { retrieveTokens } from \"@/shared/util.js\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { AuthStorage, User } from \"@/types.js\";\n\nexport async function getUser(storage: AuthStorage): Promise<User | null> {\n const tokens = retrieveTokens(storage);\n if (!tokens) return null;\n\n // Assumes all information is in the ID token\n return (parseJWT(tokens.id_token)?.payload as User) ?? null;\n}\n","import { AuthenticationRefresher } from \"@/services/types.ts\";\nimport { AuthStorage, Endpoints, OIDCTokenResponseBody } from \"@/types\";\nimport {\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\nimport { OAuth2Client } from \"oslo/oauth2\";\n\nexport class GenericAuthenticationRefresher implements AuthenticationRefresher {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n private authConfig: AuthConfig,\n private storage: AuthStorage,\n private endpointOverrides?: Partial<Endpoints>,\n ) {}\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.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 static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<GenericAuthenticationRefresher> {\n const refresher = new GenericAuthenticationRefresher(\n authConfig,\n storage,\n endpointOverrides,\n );\n await refresher.init();\n\n return refresher;\n }\n\n async refreshTokens() {\n if (!this.oauth2client) await this.init();\n\n const tokens = retrieveTokens(this.storage);\n if (!tokens?.refresh_token) throw new Error(\"No refresh token available\");\n\n const oauth2Client = this.oauth2client!;\n const refreshedTokens =\n await oauth2Client.refreshAccessToken<OIDCTokenResponseBody>(\n tokens.refresh_token,\n );\n\n storeTokens(this.storage, refreshedTokens);\n\n return tokens;\n }\n}\n","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { AUTH_SERVER } from \"@/constants.js\";\nimport { GenericAuthenticationRefresher } from \"@/shared/GenericAuthenticationRefresher.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\n\n/**\n * Refresh the current set of OIDC tokens\n */\nexport async function refreshTokens(\n storage: AuthStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const refresher = await GenericAuthenticationRefresher.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return refresher.refreshTokens();\n}\n"],"mappings":";;;;;;;AAoBO,IAAM,0BAA0B,KAAK;AAErC,IAAe,gBAAf,MAAoD;AAAA,EAE/C,YAAY,WAA2C,CAAC,GAAG;AAxBvE;AAyBI,SAAK,WAAW;AAAA,MACd,WAAU,cAAS,aAAT,YAAqB;AAAA,MAC/B,SAAQ,cAAS,WAAT,YAAmB;AAAA;AAAA;AAAA,MAG3B,WAAU,cAAS,aAAT,YAAqB;AAAA,MAC/B,UACE,cAAS,YAAT,YACA,IAAI,KAAK,KAAK,IAAI,IAAI,MAAO,uBAAuB;AAAA,MACtD,OAAM,cAAS,SAAT,YAAiB;AAAA,IACzB;AAAA,EACF;AAGF;;;ACvCA,IAAM,iBAAiB;AAAA,EACrB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AACA,IAAM,YAAY;AAElB,IAAM,cAAc;AAEpB,IAAM,2BAA2B,CAAC,QAAQ,SAAS,KAAK;;;ACXjD,IAAK,cAAL,kBAAKA,iBAAL;AACL,EAAAA,aAAA,cAAW;AACX,EAAAA,aAAA,kBAAe;AACf,EAAAA,aAAA,mBAAgB;AAHN,SAAAA;AAAA,GAAA;;;ACWZ,SAAS,oBAAoB;;;ACV7B,SAAS,MAAM,YAAY;AAE3B,IAAM,sBAAsB,CAAC,WAA6B;AACxD,QAAM,qBAAqB,OAAO,SAAS,GAAG,IAC1C,OAAO,MAAM,GAAG,OAAO,SAAS,CAAC,IACjC;AAEJ,QAAM,kBAAkB,GAAG,kBAAkB;AAE7C,SAAO,CAAC,oBAAoB,eAAe;AAC7C;AAEA,IAAM,mBAAmB,CAAC,QACxB,IAAI,SAAS,GAAG,IAAI,MAAM,GAAG,GAAG;AAElC,IAAM,oBAAoB,CAAO,gBAA4C;AAC3E,QAAM,uBAAuB,MAAM;AAAA,IACjC,GAAG,iBAAiB,WAAW,CAAC;AAAA,EAClC;AACA,QAAM,eACH,MAAM,qBAAqB,KAAK;AACnC,SAAO;AAAA,IACL,MAAM,aAAa;AAAA,IACnB,MAAM,aAAa;AAAA,IACnB,OAAO,aAAa;AAAA,IACpB,UAAU,aAAa;AAAA,EACzB;AACF;AAOA,IAAM,gBAAgB,CAAC,gBAAqC;AAC1D,QAAM,aAAa,KAAK,UAAU;AAAA,IAChC,MAAM,KAAK;AAAA,IACX;AAAA,EACF,CAAC;AACD,SAAO,KAAK,UAAU;AACxB;AAQA,IAAM,uBAAuB,CAC3B,OACA,uBAC4B;AAC5B,MAAI;AACF,UAAM,aAAa,KAAK,KAAK;AAC7B,WAAO,KAAK,MAAM,UAAU,EAAE;AAAA,EAChC,SAAQ;AACN,YAAQ,MAAM,2CAA2C,KAAK;AAC9D,WAAO;AAAA,EACT;AACF;;;AD/CA,YAAY,UAAU;;;AEbtB,SAAS,YAA6B;AACtC,SAAS,eAAe;AAkCxB,IAAM,KAAK,IAAI,WAAyB;AACtC,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;AAUO,IAAM,mBAAmB,CAC9B,QACwB;AACxB,QAAM,SAAS,CAAC;AAEhB,aAAW,OAAO,KAAK;AACrB,QAAI,IAAI,GAAG,MAAM,QAAW;AAI1B,MAAC,OAAe,GAAG,IAAI,IAAI,GAAG;AAAA,IAChC;AAAA,EACF;AAEA,SAAO;AACT;;;AC5DO,IAAM,8BAA8B,CACzC,gBAEA,OAAO;AAAA,EACL,OAAO,QAAQ,WAAW,EAAE,IAAI,CAAC,CAAC,QAAQ,MAAM,MAAM;AAAA,IACpD;AAAA,IACA;AAAA,MACE,SAAS,iCAAQ;AAAA,MACjB,aAAa,iCAAQ;AAAA,MACrB,cAAc,iCAAQ;AAAA,IACxB;AAAA,EACF,CAAC;AACH;;;ACLK,IAAM,qBAAN,MAAgD;AAAA,EACrD,YAAqB,SAAsB;AAAtB;AAAA,EAAuB;AAAA,EAE5C,MAAmB;AACjB,UAAM,OAAO,KAAK,QAAQ,qBAAoB;AAC9C,WAAO,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,EACnC;AAAA,EAEA,IAAI,MAAyB;AAC3B,UAAM,mBAAkB,6BAAM,mBAC1B,4BAA4B,6BAAM,eAAqC,IACvE;AACJ,UAAM,QAAQ,OAAO,KAAK,UAAU,iCAAK,OAAL,EAAW,gBAAgB,EAAC,IAAI;AACpE,SAAK,QAAQ,uBAAsB,KAAK;AAAA,EAC1C;AACF;;;AJHA,SAAsB,oBACpB,cACA,SAA2B,QACV;AAAA;AACjB,QAAI,WAAW,SAAS;AACtB,cAAQ,KAAK,4CAA4C;AACzD,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,IAAI,YAAY;AAChC,UAAM,OAAO,QAAQ,OAAO,YAAY;AACxC,UAAM,SAAS,MAAM,OAAO,OAAO,OAAO,WAAW,IAAI;AACzD,WAAO,KAAK,OAAO,aAAa,GAAG,IAAI,WAAW,MAAM,CAAC,CAAC,EACvD,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,GAAG,EAClB,QAAQ,OAAO,EAAE;AAAA,EACtB;AAAA;AAEA,SAAsB,0BACpB,IAEA;AAAA,6CAFA,aACA,oBAAwC,CAAC,GACzC;AACA,UAAM,YAAY,MAAM,kBAAkB,WAAW;AACrD,WAAO,kCACF,YACA;AAAA,EAEP;AAAA;AAEA,SAAsB,sBAAsB,QAU3B;AAAA;AACf,UAAM,YAAY,MAAM;AAAA,MACtB,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AACA,UAAM,eAAe;AAAA,MACnB,OAAO;AAAA,MACP,OAAO;AAAA,MACP;AAAA,IACF;AACA,UAAM,YAAY,MAAM,OAAO,aAAa,iBAAiB;AAC7D,UAAM,WAAW,MAAM,aAAa,uBAAuB;AAAA,MACzD,OAAO,OAAO;AAAA,MACd,QAAQ,OAAO;AAAA,IACjB,CAAC;AAGD,aAAS,aAAa,OAAO,kBAAkB,SAAS;AACxD,aAAS,aAAa,OAAO,yBAAyB,MAAM;AAC5D,QAAI,OAAO,OAAO;AAEhB,eAAS,aAAa,OAAO,SAAS,OAAO,KAAK;AAAA,IACpD;AAEA,aAAS,aAAa,OAAO,UAAU,SAAS;AAEhD,YAAQ,IAAI,uBAAuB,SAAS,SAAS,CAAC;AACtD,WAAO;AAAA,EACT;AAAA;AAEA,SAAsB,uBAAuB,QAO5B;AAAA;AAEf,WAAO,IAAI,IAAI,kBAAkB;AAAA,EACnC;AAAA;AAEO,SAAS,kBACd,UACA,aACA,WACc;AACd,SAAO,IAAI,aAAa,UAAU,UAAU,MAAM,UAAU,OAAO;AAAA,IACjE,aAAa;AAAA,EACf,CAAC;AACH;AAEA,SAAsB,eACpB,MACA,OACA,cACA,cACA,aACA,WACA;AAAA;AACA,UAAM,eAAe,MAAM,aAAa,gBAAgB;AACxD,QAAI,CAAC,aAAc,OAAM,IAAI,MAAM,kCAAkC;AAErE,UAAM,SACJ,MAAM,aAAa,0BAAiD,MAAM;AAAA,MACxE;AAAA,IACF,CAAC;AAGH,QAAI;AACF,YAAM,qBAAqB,QAAQ,WAAW,cAAc,WAAW;AAAA,IACzE,SAAS,OAAO;AACd,cAAQ,MAAM,uBAAuB,EAAE,OAAO,OAAO,CAAC;AACtD,YAAM,IAAI;AAAA,QACR,kCAAmC,MAAgB,OAAO;AAAA,MAC5D;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAEO,SAAS,YACd,SACA,QACA;AAEA,UAAQ,+BAA0B,OAAO,QAAQ;AACjD,UAAQ,uCAA8B,OAAO,YAAY;AACzD,MAAI,OAAO;AACT,YAAQ,yCAA+B,OAAO,aAAa;AAC/D;AAEO,SAAS,YAAY,SAAsB;AAChD,SAAO,OAAO,WAAW,EAAE,QAAQ,CAAC,WAAW;AAC7C,YAAQ,IAAI,QAAQ,EAAE;AAAA,EACxB,CAAC;AACH;AACO,SAAS,UAAU,SAAsB;AAC9C,QAAM,cAAc,IAAI,mBAAmB,OAAO;AAClD,cAAY,IAAI,IAAI;AACtB;AAEO,SAAS,eACd,SAC8B;AAC9B,QAAM,UAAU,QAAQ,6BAAwB;AAChD,QAAM,cAAc,QAAQ,qCAA4B;AACxD,QAAM,eAAe,QAAQ,uCAA6B;AAE1D,MAAI,CAAC,WAAW,CAAC,YAAa,QAAO;AAErC,SAAO;AAAA,IACL,UAAU;AAAA,IACV,cAAc;AAAA,IACd,eAAe,sCAAgB;AAAA,EACjC;AACF;AAEA,SAAsB,qBACpB,QACA,WACA,cACA,QACuB;AAAA;AACvB,UAAM,OAAY,wBAAmB,IAAI,IAAI,UAAU,IAAI,CAAC;AAG5D,UAAM,kBAAkB,MAAW;AAAA,MACjC,OAAO;AAAA,MACP;AAAA,MACA;AAAA,QACE,QAAQ,oBAAoB,MAAM;AAAA,QAClC,UAAU,aAAa;AAAA,MACzB;AAAA,IACF;AAGA,UAAM,sBAAsB,MAAW;AAAA,MACrC,OAAO;AAAA,MACP;AAAA,MACA;AAAA,QACE,QAAQ,oBAAoB,MAAM;AAAA,MACpC;AAAA,IACF;AAEA,WAAO,iBAAiB;AAAA,MACtB,UAAU,gBAAgB;AAAA,MAC1B,cAAc,oBAAoB;AAAA,MAClC,eAAe,OAAO;AAAA,IACxB,CAAC;AAAA,EACH;AAAA;;;AKjNA,SAAS,4BAA4B;;;ACC9B,IAAM,sBAAN,MAAiD;AAAA,EACtD,IAAI,KAAqB;AACvB,WAAO,aAAa,QAAQ,GAAG,KAAK;AAAA,EACtC;AAAA,EAEA,IAAI,KAAa,OAAqB;AACpC,iBAAa,QAAQ,KAAK,KAAK;AAAA,EACjC;AACF;;;ADHO,IAAM,iCAAN,MAA6D;AAAA,EAClE,YAAoB,uBAA+B;AAA/B;AAAA,EAAgC;AAAA,EAC9C,mBAAoC;AAAA;AACxC,YAAM,WAAW,MAAM,MAAM,KAAK,qBAAqB;AACvD,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO,KAAK;AAAA,IACd;AAAA;AACF;AAGO,IAAM,kCAAN,MAA8D;AAAA,EACnE,YAAoB,SAAsB;AAAtB;AAAA,EAAuB;AAAA;AAAA;AAAA,EAIrC,mBAAoC;AAAA;AAGxC,YAAM,WAAW,qBAAqB;AACtC,WAAK,QAAQ,IAAI,iBAAiB,QAAQ;AAE1C,aAAO,oBAAoB,QAAQ;AAAA,IACrC;AAAA;AAAA;AAAA,EAEM,kBAA0C;AAAA;AAC9C,aAAO,KAAK,QAAQ,IAAI,eAAe;AAAA,IACzC;AAAA;AACF;AAGO,IAAM,kCAAN,cAA8C,gCAAgC;AAAA,EACnF,cAAc;AACZ,UAAM,IAAI,oBAAoB,CAAC;AAAA,EACjC;AACF;;;AEpBA,SAAS,gBAAAC,qBAAoB;;;ACrB7B,IAAM,mBAAmB,CAACC,YAA4B;AAAtD;AACE,MAAI,OAAOA,YAAW,aAAa;AAEjC,QAAI;AACF,YAAI,KAAAA,WAAA,gBAAAA,QAAQ,iBAAR,mBAAsB,QAAO,qBAAqB;AACpD,eAAO;AAAA,MACT;AAAA,IAEF,SAAS,IAAI;AAEX,aAAO;AAAA,IACT;AAAA,EACF;AACA,SAAO;AACT;AAEA,IAAM,4BAA4B,CAAC,mBAA6B;AAC9D,QAAM,MAAM,IAAI,IAAI,OAAO,SAAS,IAAI;AACxC,iBAAe,QAAQ,CAAC,UAAkB;AACxC,QAAI,aAAa,OAAO,KAAK;AAAA,EAC/B,CAAC;AACD,SAAO,QAAQ,aAAa,CAAC,GAAG,IAAI,GAAG;AACzC;;;AD8BO,IAAM,iCAAN,MAAwE;AAAA,EAiB7E,YAAY,QAA4B;AACtC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA,EAGM,OAAO,WAAmD;AAAA;AAC9D,YAAM,MAAM,MAAM,sBAAsB,KAAK,MAAM;AAEnD,UAAI,KAAK,OAAO,gBAAgB,UAAU;AACxC,YAAI,CAAC;AACH,gBAAM,IAAI,MAAM,gDAAgD;AAClE,kBAAU,aAAa,OAAO,IAAI,SAAS,CAAC;AAAA,MAC9C;AACA,UAAI,KAAK,OAAO,gBAAgB,YAAY;AAC1C,eAAO,SAAS,OAAO,IAAI,SAAS;AAAA,MACtC;AACA,UAAI,KAAK,OAAO,gBAAgB,WAAW;AACzC,eAAO,KAAK,IAAI,SAAS,GAAG,QAAQ;AAAA,MACtC;AACA,aAAO;AAAA,IACT;AAAA;AAAA,EAEM,UAAwB;AAAA;AAC5B,YAAMC,gBAAe,IAAI,oBAAoB;AAC7C,kBAAYA,aAAY;AACxB,gBAAUA,aAAY;AAGtB,YAAM,MAAM,MAAM,uBAAuB,KAAK,MAAM;AACpD,aAAO;AAAA,IACT;AAAA;AACF;AAMO,IAAM,iCAAN,MAAwE;AAAA,EAc7E,YAAY,QAA4B;AACtC,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA,EAIM,SAAuB;AAAA;AAC3B,aAAO,sBAAsB,KAAK,MAAM;AAAA,IAC1C;AAAA;AAAA,EAEM,UAAwB;AAAA;AAC5B,aAAO,uBAAuB,KAAK,MAAM;AAAA,IAC3C;AAAA;AACF;AAeO,IAAM,+BAAN,MAAM,sCAAqC,+BAA+B;AAAA;AAAA,EAK/E,YACE,QAEU,eAAe,IAAI,gCAAgC,GAC7D;AACA,UAAM,iCACD,SADC;AAAA,MAEJ,OAAO,cAAc,OAAO,WAAW;AAAA;AAAA,MAEvC,cAAc;AAAA,IAChB,EAAC;AAPS;AAAA,EAQZ;AAAA;AAAA;AAAA;AAAA,EAKM,OAAsB;AAAA;AAE1B,WAAK,YAAY,MAAM;AAAA,QACrB,KAAK,OAAO;AAAA,QACZ,KAAK,OAAO;AAAA,MACd;AACA,WAAK,eAAe,IAAIC;AAAA,QACtB,KAAK,OAAO;AAAA,QACZ,KAAK,UAAU;AAAA,QACf,KAAK,UAAU;AAAA,QACf;AAAA,UACE,aAAa,KAAK,OAAO;AAAA,QAC3B;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,cACJ,MACA,OACgC;AAAA;AAChC,UAAI,CAAC,KAAK,aAAc,OAAM,KAAK,KAAK;AACxC,YAAM,eAAe,MAAM,KAAK,aAAa,gBAAgB;AAC7D,UAAI,CAAC,aAAc,OAAM,IAAI,MAAM,oCAAoC;AAGvE,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA;AAAA,QACL,KAAK,OAAO;AAAA,QACZ,KAAK;AAAA;AAAA,MACP;AAEA,kBAAY,IAAI,oBAAoB,GAAG,MAAM;AAG7C,YAAM,oBAAoB;AAAA,QACxB;AAAA,QACA,KAAK,OAAO;AAAA,MACd;AAEA,UAAI,sBAAsB,WAAW;AAEnC,eAAO,MAAM;AAAA,MACf,WAAW,sBAAsB,YAAY;AAE3C,kCAA0B,wBAAwB;AAAA,MACpD;AACA,aAAO;AAAA,IACT;AAAA;AAAA;AAAA,EAGM,iBAA8C;AAAA;AAClD,YAAM,cAAc,eAAe,IAAI,oBAAoB,CAAC;AAE5D,UAAI,CAAC,YAAa,QAAO;AAEzB,aAAO;AAAA,QACL,eAAe,CAAC,CAAC,YAAY;AAAA,QAC7B,SAAS,YAAY;AAAA,QACrB,aAAa,YAAY;AAAA,QACzB,cAAc,YAAY;AAAA,MAC5B;AAAA,IACF;AAAA;AAAA,EAEM,0BAAgD;AAAA;AACpD,UAAI;AACF,cAAM,cAAc,MAAM,KAAK,eAAe;AAC9C,YAAI,EAAC,2CAAa,YAAW,CAAC,YAAY,aAAa;AACrD,gBAAM,yBAAyB,iCAAK,cAAL,EAAkB,eAAe,MAAM;AACtE,sBAAY,IAAI,oBAAoB,CAAC;AACrC,iBAAO;AAAA,QACT;AACA,YAAI,CAAC,KAAK,aAAa,CAAC,KAAK,aAAc,OAAM,KAAK,KAAK;AAG3D,cAAM;AAAA,UACJ;AAAA,YACE,cAAc,YAAY;AAAA,YAC1B,UAAU,YAAY;AAAA,YACtB,eAAe,YAAY;AAAA,UAC7B;AAAA,UACA,KAAK;AAAA,UACL,KAAK;AAAA,UACL,KAAK,OAAO;AAAA,QACd;AACA,eAAO;AAAA,MACT,SAAS,OAAO;AACd,gBAAQ,KAAK,sCAAsC,KAAK;AACxD,cAAM,yBAAyB;AAAA,UAC7B,eAAe;AAAA,QACjB;AACA,oBAAY,IAAI,oBAAoB,CAAC;AACrC,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA,EAEA,OAAa,MACX,QACiC;AAAA;AACjC,YAAM,WAAW,IAAI,8BAA6B,MAAM;AACxD,YAAM,SAAS,KAAK;AAEpB,aAAO;AAAA,IACT;AAAA;AACF;;;AEvRA,SAAS,gBAAAC,qBAAoB;AAgBtB,IAAM,+BAAN,MAAM,8BAA+D;AAAA,EAKlE,YACG,YACA,SACA,mBACT;AAHS;AACA;AACA;AAET,SAAK,eAAe,IAAI,gCAAgC,OAAO;AAAA,EACjE;AAAA,EACA,0BAAgD;AAC9C,UAAM,IAAI,MAAM,yBAAyB;AAAA,EAC3C;AAAA,EAEM,OAAsB;AAAA;AAE1B,WAAK,YAAY,MAAM;AAAA,QACrB,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA,MACP;AACA,WAAK,eAAe,IAAIC;AAAA,QACtB,KAAK,WAAW;AAAA,QAChB,KAAK,UAAU;AAAA,QACf,KAAK,UAAU;AAAA,QACf;AAAA,UACE,aAAa,KAAK,WAAW;AAAA,QAC/B;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA;AAAA,EAEM,cACJ,MACA,OACgC;AAAA;AAChC,UAAI,CAAC,KAAK,aAAc,OAAM,KAAK,KAAK;AACxC,YAAM,eAAe,MAAM,KAAK,aAAa,gBAAgB;AAC7D,UAAI,CAAC,aAAc,OAAM,IAAI,MAAM,oCAAoC;AAGvE,YAAM,SAAS,MAAM;AAAA,QACnB;AAAA,QACA;AAAA,QACA,KAAK;AAAA,QACL,KAAK;AAAA;AAAA,QACL,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA;AAAA,MACP;AAEA,kBAAY,KAAK,SAAS,MAAM;AAEhC,aAAO;AAAA,IACT;AAAA;AAAA,EAEM,iBAA8C;AAAA;AAClD,YAAM,cAAc,eAAe,KAAK,OAAO;AAE/C,UAAI,CAAC,YAAa,QAAO;AAEzB,aAAO;AAAA,QACL,eAAe,CAAC,CAAC,YAAY;AAAA,QAC7B,SAAS,YAAY;AAAA,QACrB,aAAa,YAAY;AAAA,QACzB,cAAc,YAAY;AAAA,MAC5B;AAAA,IACF;AAAA;AAAA,EAEA,OAAa,MACX,YACA,SACA,mBACiC;AAAA;AACjC,YAAM,WAAW,IAAI;AAAA,QACnB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,SAAS,KAAK;AAEpB,aAAO;AAAA,IACT;AAAA;AACF;;;ACxFA,SAAsB,uBACpB,MACA,OACA,SACA,QACgC;AAAA;AAlBlC;AAmBE,UAAM,qBAAqB,MAAM,6BAA6B;AAAA,MAC5D,iCACK,SADL;AAAA,QAEE,cAAa,YAAO,gBAAP,YAAsB;AAAA,MACrC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAEA,WAAO,mBAAmB,cAAc,MAAM,KAAK;AAAA,EACrD;AAAA;AAEO,SAAS,WAAW,SAA+B;AACxD,SAAO,CAAC,CAAC,QAAQ,IAAI,UAAU;AACjC;AAEA,SAAsB,cACpB,QAKA,SACc;AAAA;AA1ChB;AA4CE,UAAM,SAAQ,YAAO,UAAP,YAAgB,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,CAAC;AACpE,UAAM,UAAS,YAAO,WAAP,YAAiB;AAChC,UAAM,eAAe,IAAI,gCAAgC,OAAO;AAChE,UAAM,gBAAgB,IAAI,+BAA+B,iCACpD,SADoD;AAAA,MAEvD;AAAA,MACA;AAAA,MACA,cAAa,YAAO,gBAAP,YAAsB;AAAA;AAAA,MAEnC,cAAc;AAAA,IAChB,EAAC;AAED,WAAO,cAAc,OAAO;AAAA,EAC9B;AAAA;;;ACxDA,SAAS,gBAAgB;AAGzB,SAAsB,QAAQ,SAA4C;AAAA;AAJ1E;AAKE,UAAM,SAAS,eAAe,OAAO;AACrC,QAAI,CAAC,OAAQ,QAAO;AAGpB,YAAQ,oBAAS,OAAO,QAAQ,MAAxB,mBAA2B,YAA3B,YAA+C;AAAA,EACzD;AAAA;;;ACFA,SAAS,gBAAAC,qBAAoB;AAEtB,IAAM,iCAAN,MAAM,gCAAkE;AAAA,EAIrE,YACE,YACA,SACA,mBACR;AAHQ;AACA;AACA;AAAA,EACP;AAAA,EAEG,OAAsB;AAAA;AAE1B,WAAK,YAAY,MAAM;AAAA,QACrB,KAAK,WAAW;AAAA,QAChB,KAAK;AAAA,MACP;AACA,WAAK,eAAe,IAAIC;AAAA,QACtB,KAAK,WAAW;AAAA,QAChB,KAAK,UAAU;AAAA,QACf,KAAK,UAAU;AAAA,QACf;AAAA,UACE,aAAa,KAAK,WAAW;AAAA,QAC/B;AAAA,MACF;AAEA,aAAO;AAAA,IACT;AAAA;AAAA,EAEA,OAAa,MACX,YACA,SACA,mBACyC;AAAA;AACzC,YAAM,YAAY,IAAI;AAAA,QACpB;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,UAAU,KAAK;AAErB,aAAO;AAAA,IACT;AAAA;AAAA,EAEM,gBAAgB;AAAA;AACpB,UAAI,CAAC,KAAK,aAAc,OAAM,KAAK,KAAK;AAExC,YAAM,SAAS,eAAe,KAAK,OAAO;AAC1C,UAAI,EAAC,iCAAQ,eAAe,OAAM,IAAI,MAAM,4BAA4B;AAExE,YAAM,eAAe,KAAK;AAC1B,YAAM,kBACJ,MAAM,aAAa;AAAA,QACjB,OAAO;AAAA,MACT;AAEF,kBAAY,KAAK,SAAS,eAAe;AAEzC,aAAO;AAAA,IACT;AAAA;AACF;;;AC7DA,SAAsB,cACpB,SACA,QACgC;AAAA;AAXlC;AAYE,UAAM,YAAY,MAAM,+BAA+B;AAAA,MACrD,iCACK,SADL;AAAA,QAEE,cAAa,YAAO,gBAAP,YAAsB;AAAA,MACrC;AAAA,MACA;AAAA,MACA,OAAO;AAAA,IACT;AAEA,WAAO,UAAU,cAAc;AAAA,EACjC;AAAA;","names":["OAuthTokens","OAuth2Client","window","localStorage","OAuth2Client","OAuth2Client","OAuth2Client","OAuth2Client","OAuth2Client"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/chunk-F2CKPLXX.js","../src/shared/storage.ts","../src/constants.ts","../src/shared/types.ts","../src/shared/util.ts","../src/lib/oauth.ts","../src/utils.ts","../src/lib/jwt.ts","../src/shared/UserSession.ts","../src/services/PKCE.ts","../src/browser/storage.ts","../src/services/AuthenticationService.ts","../src/lib/windowUtil.ts","../src/server/ServerAuthenticationResolver.ts","../src/server/login.ts","../src/shared/session.ts","../src/shared/GenericAuthenticationRefresher.ts","../src/server/refresh.ts"],"names":["OAuthTokens","OAuth2Client","window","localStorage"],"mappings":"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","file":"/Users/kevincolgan/code/civic-auth/packages/civic-auth-client/dist/chunk-F2CKPLXX.js","sourcesContent":[null,"import { AuthStorage, SessionData, UnknownObject, User } from \"@/types.js\";\n\ntype SameSiteOption = \"strict\" | \"lax\" | \"none\";\n\nexport interface SessionStorage {\n get(): SessionData;\n getUser(): User<UnknownObject> | null;\n set(data: Partial<SessionData>): void;\n setUser(data: User<UnknownObject> | null): void;\n clear(): void;\n}\n\nexport type CookieStorageSettings = {\n httpOnly: boolean;\n secure: boolean;\n sameSite: SameSiteOption;\n expires: Date;\n path: string;\n};\n\nexport const DEFAULT_COOKIE_DURATION = 60 * 15; // 15 minutes\n\nexport abstract class CookieStorage implements AuthStorage {\n protected settings: CookieStorageSettings;\n protected constructor(settings: Partial<CookieStorageSettings> = {}) {\n this.settings = {\n httpOnly: settings.httpOnly ?? true,\n secure: settings.secure ?? true,\n // the callback request comes the auth server\n // 'lax' ensures the code_verifier cookie is sent with the request\n sameSite: settings.sameSite ?? \"lax\",\n expires:\n settings.expires ??\n new Date(Date.now() + 1000 * DEFAULT_COOKIE_DURATION),\n path: settings.path ?? \"/\",\n };\n }\n abstract get(key: string): string | null;\n abstract set(key: string, value: string): void;\n}\n","const DEFAULT_SCOPES = [\n \"openid\",\n \"profile\",\n \"email\",\n \"forwardedTokens\",\n \"offline_access\",\n];\nconst IFRAME_ID = \"civic-auth-iframe\";\n\nconst AUTH_SERVER = \"https://auth-dev.civic.com/oauth\";\n\nconst DEFAULT_OAUTH_GET_PARAMS = [\"code\", \"state\", \"iss\"];\n\nexport { DEFAULT_SCOPES, DEFAULT_OAUTH_GET_PARAMS, IFRAME_ID, AUTH_SERVER };\n","export enum OAuthTokens {\n ID_TOKEN = \"id_token\",\n ACCESS_TOKEN = \"access_token\",\n REFRESH_TOKEN = \"refresh_token\",\n}\n\nexport enum UserStorage {\n USER = \"user\",\n}\n","// Utility functions shared by auth server and client integrations\n// Typically these functions should be used inside AuthenticationInitiator and AuthenticationResolver implementations\n\nimport {\n AuthStorage,\n Endpoints,\n JWTPayload,\n OIDCTokenResponseBody,\n ParsedTokens,\n} from \"@/types.js\";\nimport { OAuthTokens } from \"./types\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { getIssuerVariations, getOauthEndpoints } from \"@/lib/oauth.js\";\nimport * as jose from \"jose\";\nimport { withoutUndefined } from \"@/utils.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.js\";\nimport { GenericUserSession } from \"./UserSession\";\n\n/**\n * Given a PKCE code verifier, derive the code challenge using SHA\n */\nexport async function deriveCodeChallenge(\n codeVerifier: string,\n method: \"Plain\" | \"S256\" = \"S256\",\n): Promise<string> {\n if (method === \"Plain\") {\n console.warn(\"Using insecure plain code challenge method\");\n return codeVerifier;\n }\n\n const encoder = new TextEncoder();\n const data = encoder.encode(codeVerifier);\n const digest = await crypto.subtle.digest(\"SHA-256\", data);\n return btoa(String.fromCharCode(...new Uint8Array(digest)))\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n}\n\nexport async function getEndpointsWithOverrides(\n oauthServer: string,\n endpointOverrides: Partial<Endpoints> = {},\n) {\n const endpoints = await getOauthEndpoints(oauthServer);\n return {\n ...endpoints,\n ...endpointOverrides,\n };\n}\n\nexport async function generateOauthLoginUrl(config: {\n clientId: string;\n scopes: string[];\n state: string;\n redirectUrl: string;\n oauthServer: string;\n nonce?: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n const endpoints = await getEndpointsWithOverrides(\n config.oauthServer,\n config.endpointOverrides,\n );\n const oauth2Client = buildOauth2Client(\n config.clientId,\n config.redirectUrl,\n endpoints,\n );\n const challenge = await config.pkceConsumer.getCodeChallenge();\n const oAuthUrl = await oauth2Client.createAuthorizationURL({\n state: config.state,\n scopes: config.scopes,\n });\n // The OAuth2 client supports PKCE, but does not allow passing in a code challenge from some other source\n // It only allows passing in a code verifier which it then hashes itself.\n oAuthUrl.searchParams.append(\"code_challenge\", challenge);\n oAuthUrl.searchParams.append(\"code_challenge_method\", \"S256\");\n if (config.nonce) {\n // nonce isn't supported by oslo, so we add it manually\n oAuthUrl.searchParams.append(\"nonce\", config.nonce);\n }\n // Required by the auth server for offline_access scope\n oAuthUrl.searchParams.append(\"prompt\", \"consent\");\n\n console.log(\"Generated OAuth URL\", oAuthUrl.toString());\n return oAuthUrl;\n}\n\nexport async function generateOauthLogoutUrl(config: {\n clientId: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n}): Promise<URL> {\n // TODO\n return new URL(\"http://localhost\");\n}\n\nexport function buildOauth2Client(\n clientId: string,\n redirectUri: string,\n endpoints: Endpoints,\n): OAuth2Client {\n return new OAuth2Client(clientId, endpoints.auth, endpoints.token, {\n redirectURI: redirectUri,\n });\n}\n\nexport async function exchangeTokens(\n code: string,\n state: string,\n pkceProducer: PKCEProducer,\n oauth2Client: OAuth2Client,\n oauthServer: string,\n endpoints: Endpoints,\n) {\n const codeVerifier = await pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in state\");\n\n const tokens =\n await oauth2Client.validateAuthorizationCode<OIDCTokenResponseBody>(code, {\n codeVerifier,\n });\n\n // Validate relevant tokens\n try {\n await validateOauth2Tokens(tokens, endpoints, oauth2Client, oauthServer);\n } catch (error) {\n console.error(\"tokenExchange error\", { error, tokens });\n throw new Error(\n `OIDC tokens validation failed: ${(error as Error).message}`,\n );\n }\n\n return tokens;\n}\n\nexport function storeTokens(\n storage: AuthStorage,\n tokens: OIDCTokenResponseBody,\n) {\n // store tokens in storage ( TODO we should probably store them against the state to allow multiple logins )\n storage.set(OAuthTokens.ID_TOKEN, tokens.id_token);\n storage.set(OAuthTokens.ACCESS_TOKEN, tokens.access_token);\n if (tokens.refresh_token)\n storage.set(OAuthTokens.REFRESH_TOKEN, tokens.refresh_token);\n}\n\nexport function clearTokens(storage: AuthStorage) {\n Object.values(OAuthTokens).forEach((cookie) => {\n storage.set(cookie, \"\");\n });\n}\nexport function clearUser(storage: AuthStorage) {\n const userSession = new GenericUserSession(storage);\n userSession.set(null);\n}\n\nexport function retrieveTokens(\n storage: AuthStorage,\n): OIDCTokenResponseBody | null {\n const idToken = storage.get(OAuthTokens.ID_TOKEN);\n const accessToken = storage.get(OAuthTokens.ACCESS_TOKEN);\n const refreshToken = storage.get(OAuthTokens.REFRESH_TOKEN);\n\n if (!idToken || !accessToken) return null;\n\n return {\n id_token: idToken,\n access_token: accessToken,\n refresh_token: refreshToken ?? undefined,\n };\n}\n\nexport async function validateOauth2Tokens(\n tokens: OIDCTokenResponseBody,\n endpoints: Endpoints,\n oauth2Client: OAuth2Client,\n issuer: string,\n): Promise<ParsedTokens> {\n const JWKS = jose.createRemoteJWKSet(new URL(endpoints.jwks));\n\n // validate the ID token\n const idTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.id_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n audience: oauth2Client.clientId,\n },\n );\n\n // validate the access token\n const accessTokenResponse = await jose.jwtVerify<JWTPayload>(\n tokens.access_token,\n JWKS,\n {\n issuer: getIssuerVariations(issuer),\n },\n );\n\n return withoutUndefined({\n id_token: idTokenResponse.payload,\n access_token: accessTokenResponse.payload,\n refresh_token: tokens.refresh_token,\n });\n}\n","import { DisplayMode, Endpoints, OpenIdConfiguration } from \"@/types\";\nimport { v4 as uuid } from \"uuid\";\n\nconst getIssuerVariations = (issuer: string): string[] => {\n const issuerWithoutSlash = issuer.endsWith(\"/\")\n ? issuer.slice(0, issuer.length - 1)\n : issuer;\n\n const issuerWithSlash = `${issuerWithoutSlash}/`;\n\n return [issuerWithoutSlash, issuerWithSlash];\n};\n\nconst addSlashIfNeeded = (url: string): string =>\n url.endsWith(\"/\") ? url : `${url}/`;\n\nconst getOauthEndpoints = async (oauthServer: string): Promise<Endpoints> => {\n const openIdConfigResponse = await fetch(\n `${addSlashIfNeeded(oauthServer)}.well-known/openid-configuration`,\n );\n const openIdConfig =\n (await openIdConfigResponse.json()) as OpenIdConfiguration;\n return {\n jwks: openIdConfig.jwks_uri,\n auth: openIdConfig.authorization_endpoint,\n token: openIdConfig.token_endpoint,\n userinfo: openIdConfig.userinfo_endpoint,\n };\n};\n\n/**\n * creates a state string for the OAuth2 flow, encoding the display mode too for future use\n * @param {DisplayMode} displayMode\n * @returns {string}\n */\nconst generateState = (displayMode: DisplayMode): string => {\n const jsonString = JSON.stringify({\n uuid: uuid(),\n displayMode,\n });\n return btoa(jsonString);\n};\n\n/**\n * parses the state string from the OAuth2 flow, decoding the display mode too\n * @param state\n * @param sessionDisplayMode\n * @returns { uuid: string, displayMode: DisplayMode }\n */\nconst displayModeFromState = (\n state: string,\n sessionDisplayMode: DisplayMode | undefined,\n): DisplayMode | undefined => {\n try {\n const jsonString = atob(state);\n return JSON.parse(jsonString).displayMode;\n } catch {\n console.error(\"Failed to parse displayMode from state:\", state);\n return sessionDisplayMode;\n }\n};\n\nexport {\n getIssuerVariations,\n getOauthEndpoints,\n displayModeFromState,\n generateState,\n};\n","import { clsx, type ClassValue } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Checks if a popup window is blocked by the browser.\n *\n * This function attempts to open a small popup window and then checks if it was successfully created.\n * If the popup is blocked by the browser, the function returns `true`. Otherwise, it returns `false`.\n *\n * @returns {boolean} - `true` if the popup is blocked, `false` otherwise.\n */\nconst isPopupBlocked = (): boolean => {\n // First we try to open a small popup window. It either returns a window object or null.\n const popup = window.open(\"\", \"\", \"width=1,height=1\");\n\n // If window.open() returns null, popup is definitely blocked\n if (!popup) {\n return true;\n }\n\n try {\n // Try to access a property of the popup to check if it's usable\n if (typeof popup.closed === \"undefined\") {\n throw new Error(\"Popup is blocked\");\n }\n } catch {\n // Accessing the popup's properties throws an error if the popup is blocked\n return true;\n }\n\n // Close the popup immediately if it was opened\n popup.close();\n return false;\n};\n\nconst cn = (...inputs: ClassValue[]) => {\n return twMerge(clsx(inputs));\n};\n\n// This type narrows T as far as it can by:\n// - removing all keys where the value is `undefined`\n// - making keys that are not undefined required\n// So, for example: given { a: string | undefined, b: string | undefined },\n// if you pass in { a: \"foo\" }, it returns an object of type: { a: string }\ntype WithoutUndefined<T> = {\n [K in keyof T as undefined extends T[K] ? never : K]: T[K];\n};\nexport const withoutUndefined = <T extends { [K in keyof T]: unknown }>(\n obj: T,\n): WithoutUndefined<T> => {\n const result = {} as WithoutUndefined<T>;\n\n for (const key in obj) {\n if (obj[key] !== undefined) {\n // TypeScript needs assurance that key is a valid key in WithoutUndefined<T>\n // We use type assertion here\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n (result as any)[key] = obj[key];\n }\n }\n\n return result;\n};\n\nexport { cn, isPopupBlocked };\n","import { ForwardedTokens, ForwardedTokensJWT } from \"@/types.js\";\n\nexport const convertForwardedTokenFormat = (\n inputTokens: ForwardedTokensJWT,\n): ForwardedTokens =>\n Object.fromEntries(\n Object.entries(inputTokens).map(([source, tokens]) => [\n source,\n {\n idToken: tokens?.id_token,\n accessToken: tokens?.access_token,\n refreshToken: tokens?.refresh_token,\n },\n ]),\n );\n","import { AuthStorage, ForwardedTokensJWT, User } from \"@/types\";\nimport { UserStorage } from \"./types\";\nimport { convertForwardedTokenFormat } from \"@/lib/jwt\";\n\nexport interface UserSession {\n get(): User | null;\n set(user: User): void;\n}\n\nexport class GenericUserSession implements UserSession {\n constructor(readonly storage: AuthStorage) {}\n\n get(): User | null {\n const user = this.storage.get(UserStorage.USER);\n return user ? JSON.parse(user) : null;\n }\n\n set(user: User | null): void {\n const forwardedTokens = user?.forwardedTokens\n ? convertForwardedTokenFormat(user?.forwardedTokens as ForwardedTokensJWT)\n : null;\n const value = user ? JSON.stringify({ ...user, forwardedTokens }) : \"\";\n this.storage.set(UserStorage.USER, value);\n }\n}\n","import { deriveCodeChallenge } from \"@/shared/util.js\";\nimport { generateCodeVerifier } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport { PKCEConsumer, PKCEProducer } from \"@/services/types.ts\";\nimport { AuthStorage } from \"@/types\";\n\n/** A PKCE consumer that retrieves the challenge from a server endpoint */\nexport class ConfidentialClientPKCEConsumer implements PKCEConsumer {\n constructor(private pkceChallengeEndpoint: string) {}\n async getCodeChallenge(): Promise<string> {\n const response = await fetch(this.pkceChallengeEndpoint);\n const data = (await response.json()) as { challenge: string };\n return data.challenge;\n }\n}\n\n/** A PKCE Producer that can generate and store a code verifier, but is agnostic as to the storage location */\nexport class GenericPublicClientPKCEProducer implements PKCEProducer {\n constructor(private storage: AuthStorage) {}\n\n // if there is already a verifier, return it,\n // If not, create a new one and store it\n async getCodeChallenge(): Promise<string> {\n // let verifier = await this.getCodeVerifier();\n // if (!verifier) {\n const verifier = generateCodeVerifier();\n this.storage.set(\"code_verifier\", verifier);\n // }\n return deriveCodeChallenge(verifier);\n }\n // if there is already a verifier, return it,\n async getCodeVerifier(): Promise<string | null> {\n return this.storage.get(\"code_verifier\");\n }\n}\n\n/** A PKCE Producer that is expected to run on a browser, and does not need a backend */\nexport class BrowserPublicClientPKCEProducer extends GenericPublicClientPKCEProducer {\n constructor() {\n super(new LocalStorageAdapter());\n }\n}\n","import { AuthStorage } from \"@/types\";\n\nexport class LocalStorageAdapter implements AuthStorage {\n get(key: string): string {\n return localStorage.getItem(key) || \"\";\n }\n\n set(key: string, value: string): void {\n localStorage.setItem(key, value);\n }\n}\n","// Proposals for revised versions of the SessionService AKA AuthSessionService\n\nimport {\n DisplayMode,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { BrowserPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport {\n clearTokens,\n clearUser,\n exchangeTokens,\n generateOauthLoginUrl,\n generateOauthLogoutUrl,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n validateOauth2Tokens,\n} from \"@/shared/util.js\";\nimport { displayModeFromState, generateState } from \"@/lib/oauth.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport { LocalStorageAdapter } from \"@/browser/storage.js\";\nimport {\n AuthenticationInitiator,\n AuthenticationResolver,\n PKCEConsumer,\n} from \"@/services/types.js\";\nimport { removeParamsWithoutReload } from \"@/lib/windowUtil\";\nimport { DEFAULT_OAUTH_GET_PARAMS } from \"@/constants\";\n\n/**\n * An authentication initiator that works on a browser. Since this is just triggering\n * login and logout, session data is not stored here.\n * An associated AuthenticationResolver would be needed to get the session data.\n * Storage is needed for the code verifier, this is the domain of the PKCEConsumer\n * The storage used by the PKCEConsumer should be available to the AuthenticationResolver.\n *\n * Example usage:\n *\n * 1) Client-only SPA -eg a react app with no server:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new BrowserPublicClientPKCEProducer(), // generate and retrieve the challenge client-side\n * ... other config\n * })\n *\n * 2) Client-side of a client/server app - eg a react app with a backend:\n * new BrowserAuthenticationInitiator({\n * pkceConsumer: new ConfidentialClientPKCEConsumer(\"https://myserver.com/pkce\"), // get the challenge from the server\n * ... other config\n * })\n */\nexport class BrowserAuthenticationInitiator implements AuthenticationInitiator {\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n // determines whether to trigger the login/logout in an iframe, a new browser window, or redirect the current one.\n displayMode: DisplayMode;\n oauthServer: string;\n // the endpoints to use for the login (if not obtained from the auth server\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n // the nonce to use for the login\n nonce?: string;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and then use the display mode to decide how to send the user there\n async signIn(iframeRef: HTMLIFrameElement | null): Promise<URL> {\n const url = await generateOauthLoginUrl(this.config);\n\n if (this.config.displayMode === \"iframe\") {\n if (!iframeRef)\n throw new Error(\"iframeRef is required for displayMode 'iframe'\");\n iframeRef.setAttribute(\"src\", url.toString());\n }\n if (this.config.displayMode === \"redirect\") {\n window.location.href = url.toString();\n }\n if (this.config.displayMode === \"new_tab\") {\n window.open(url.toString(), \"_blank\");\n }\n return url;\n }\n\n async signOut(): Promise<URL> {\n const localStorage = new LocalStorageAdapter();\n clearTokens(localStorage);\n clearUser(localStorage);\n // TODO open the iframe or new tab etc: the logout URL is not currently\n // supported by on the oauth, so just clear state until then\n const url = await generateOauthLogoutUrl(this.config);\n return url;\n }\n}\n\n/** A general-purpose authentication initiator, that just generates urls, but lets\n * the caller decide how to use them. This is useful for server-side applications\n * that may serve this URL to their front-ends or just call them directly\n */\nexport class GenericAuthenticationInitiator implements AuthenticationInitiator {\n protected config: {\n clientId: string;\n redirectUrl: string;\n state: string;\n scopes: string[];\n oauthServer: string;\n nonce?: string;\n // the endpoints to use for the login (if not obtained from the auth server)\n endpointOverrides?: Partial<Endpoints>;\n // used to get the PKCE challenge\n pkceConsumer: PKCEConsumer;\n };\n\n constructor(config: typeof this.config) {\n this.config = config;\n }\n\n // Use the config (Client ID, scopes OAuth Server, Endpoints, PKCEConsumer) to generate a new login url\n // and simply return the url\n async signIn(): Promise<URL> {\n return generateOauthLoginUrl(this.config);\n }\n\n async signOut(): Promise<URL> {\n return generateOauthLogoutUrl(this.config);\n }\n}\n\ntype BrowserAuthenticationConfig = {\n clientId: string;\n redirectUrl: string;\n scopes: string[];\n oauthServer: string;\n endpointOverrides?: Partial<Endpoints>;\n displayMode: DisplayMode;\n};\n\n/**\n * An authentication resolver that can run on the browser (i.e. a public client)\n * It uses PKCE for security. PKCE and Session data are stored in local storage\n */\nexport class BrowserAuthenticationService extends BrowserAuthenticationInitiator {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n // TODO WIP - perhaps we want to keep resolver and initiator separate here\n constructor(\n config: BrowserAuthenticationConfig,\n // Since we are running fully on the client, we produce as well as consume the PKCE challenge\n protected pkceProducer = new BrowserPublicClientPKCEProducer(),\n ) {\n super({\n ...config,\n state: generateState(config.displayMode),\n // Store and retrieve the PKCE challenge in local storage\n pkceConsumer: pkceProducer,\n });\n }\n\n // TODO too much code duplication here between the browser and the server variant.\n // Suggestion for refactor: Standardise the config for AuthenticationResolvers and create a one-shot\n // function for generating an oauth2client from it\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.config.oauthServer,\n this.config.endpointOverrides,\n );\n this.oauth2client = new OAuth2Client(\n this.config.clientId,\n this.endpoints.auth,\n this.endpoints.token,\n {\n redirectURI: this.config.redirectUrl,\n },\n );\n\n return this;\n }\n\n // Two responsibilities:\n // 1. resolve the auth code to get the tokens (should use library code)\n // 2. store the tokens in local storage\n async tokenExchange(\n code: string,\n state: string,\n ): Promise<OIDCTokenResponseBody> {\n if (!this.oauth2client) await this.init();\n const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\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.config.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(new LocalStorageAdapter(), tokens);\n\n // cleanup the browser window if needed\n const parsedDisplayMode = displayModeFromState(\n state,\n this.config.displayMode,\n );\n\n if (parsedDisplayMode === \"new_tab\") {\n // Close the popup window\n window.close();\n } else if (parsedDisplayMode === \"redirect\") {\n // these are the default oAuth params that get added to the URL which we want to remove\n removeParamsWithoutReload(DEFAULT_OAUTH_GET_PARAMS);\n }\n return tokens;\n }\n\n // Get the session data from local storage\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(new LocalStorageAdapter());\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\n }\n\n async validateExistingSession(): Promise<SessionData> {\n try {\n const sessionData = await this.getSessionData();\n if (!sessionData?.idToken || !sessionData.accessToken) {\n const unAuthenticatedSession = { ...sessionData, authenticated: false };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n if (!this.endpoints || !this.oauth2client) await this.init();\n\n // this function will throw if any of the tokens are invalid\n await validateOauth2Tokens(\n {\n access_token: sessionData.accessToken,\n id_token: sessionData.idToken,\n refresh_token: sessionData.refreshToken,\n },\n this.endpoints!,\n this.oauth2client!,\n this.config.oauthServer,\n );\n return sessionData;\n } catch (error) {\n console.warn(\"Failed to validate existing tokens\", error);\n const unAuthenticatedSession = {\n authenticated: false,\n };\n clearTokens(new LocalStorageAdapter());\n return unAuthenticatedSession;\n }\n }\n\n static async build(\n config: BrowserAuthenticationConfig,\n ): Promise<AuthenticationResolver> {\n const resolver = new BrowserAuthenticationService(config);\n await resolver.init();\n\n return resolver;\n }\n}\n","const isWindowInIframe = (window: Window): boolean => {\n if (typeof window !== \"undefined\") {\n // use the window width to determine if we're in an iframe or not\n try {\n if (window?.frameElement?.id === \"civic-auth-iframe\") {\n return true;\n }\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n } catch (_e) {\n // If we get an error, we're not in an iframe\n return false;\n }\n }\n return false;\n};\n\nconst removeParamsWithoutReload = (paramsToRemove: string[]) => {\n const url = new URL(window.location.href);\n paramsToRemove.forEach((param: string) => {\n url.searchParams.delete(param);\n });\n window.history.replaceState({}, \"\", url);\n};\n\nexport { isWindowInIframe, removeParamsWithoutReload };\n","import { GenericPublicClientPKCEProducer } from \"@/services/PKCE.js\";\nimport { OAuth2Client } from \"oslo/oauth2\";\nimport {\n AuthStorage,\n Endpoints,\n OIDCTokenResponseBody,\n SessionData,\n} from \"@/types.js\";\nimport { AuthConfig } from \"@/server/config.js\";\nimport {\n exchangeTokens,\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.js\";\nimport { AuthenticationResolver, PKCEProducer } from \"@/services/types.ts\";\n\nexport class ServerAuthenticationResolver implements AuthenticationResolver {\n private pkceProducer: PKCEProducer;\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 this.pkceProducer = new GenericPublicClientPKCEProducer(storage);\n }\n validateExistingSession(): Promise<SessionData> {\n throw new Error(\"Method not implemented.\");\n }\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.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 const codeVerifier = await this.pkceProducer.getCodeVerifier();\n if (!codeVerifier) throw new Error(\"Code verifier not found in storage\");\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.authConfig.oauthServer,\n this.endpoints!, // clean up types here to avoid the ! operator\n );\n\n storeTokens(this.storage, tokens);\n\n return tokens;\n }\n\n async getSessionData(): Promise<SessionData | null> {\n const storageData = retrieveTokens(this.storage);\n\n if (!storageData) return null;\n\n return {\n authenticated: !!storageData.id_token,\n idToken: storageData.id_token,\n accessToken: storageData.access_token,\n refreshToken: storageData.refresh_token,\n };\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","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { 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 { AuthConfig } from \"@/server/config.ts\";\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 ?? AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return authSessionService.tokenExchange(code, state);\n}\n\nexport function isLoggedIn(storage: AuthStorage): boolean {\n return !!storage.get(\"id_token\");\n}\n\nexport async function buildLoginUrl(\n config: Pick<AuthConfig, \"oauthServer\" | \"clientId\" | \"redirectUrl\"> & {\n scopes?: string[];\n state?: string;\n nonce?: 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 ?? AUTH_SERVER,\n // When retrieving the PKCE challenge on the server-side, we produce it and store it in the session\n pkceConsumer: pkceProducer,\n });\n\n return authInitiator.signIn();\n}\n","import { retrieveTokens } from \"@/shared/util.js\";\nimport { parseJWT } from \"oslo/jwt\";\nimport { AuthStorage, User } from \"@/types.js\";\n\nexport async function getUser(storage: AuthStorage): Promise<User | null> {\n const tokens = retrieveTokens(storage);\n if (!tokens) return null;\n\n // Assumes all information is in the ID token\n return (parseJWT(tokens.id_token)?.payload as User) ?? null;\n}\n","import { AuthenticationRefresher } from \"@/services/types.ts\";\nimport { AuthStorage, Endpoints, OIDCTokenResponseBody } from \"@/types\";\nimport {\n getEndpointsWithOverrides,\n retrieveTokens,\n storeTokens,\n} from \"@/shared/util.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\nimport { OAuth2Client } from \"oslo/oauth2\";\n\nexport class GenericAuthenticationRefresher implements AuthenticationRefresher {\n private oauth2client: OAuth2Client | undefined;\n private endpoints: Endpoints | undefined;\n\n private constructor(\n private authConfig: AuthConfig,\n private storage: AuthStorage,\n private endpointOverrides?: Partial<Endpoints>,\n ) {}\n\n async init(): Promise<this> {\n // resolve oauth config\n this.endpoints = await getEndpointsWithOverrides(\n this.authConfig.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 static async build(\n authConfig: AuthConfig,\n storage: AuthStorage,\n endpointOverrides?: Partial<Endpoints>,\n ): Promise<GenericAuthenticationRefresher> {\n const refresher = new GenericAuthenticationRefresher(\n authConfig,\n storage,\n endpointOverrides,\n );\n await refresher.init();\n\n return refresher;\n }\n\n async refreshTokens() {\n if (!this.oauth2client) await this.init();\n\n const tokens = retrieveTokens(this.storage);\n if (!tokens?.refresh_token) throw new Error(\"No refresh token available\");\n\n const oauth2Client = this.oauth2client!;\n const refreshedTokens =\n await oauth2Client.refreshAccessToken<OIDCTokenResponseBody>(\n tokens.refresh_token,\n );\n\n storeTokens(this.storage, refreshedTokens);\n\n return tokens;\n }\n}\n","import { AuthStorage, OIDCTokenResponseBody } from \"@/types.js\";\nimport { AUTH_SERVER } from \"@/constants.js\";\nimport { GenericAuthenticationRefresher } from \"@/shared/GenericAuthenticationRefresher.ts\";\nimport { AuthConfig } from \"@/server/config.ts\";\n\n/**\n * Refresh the current set of OIDC tokens\n */\nexport async function refreshTokens(\n storage: AuthStorage,\n config: AuthConfig,\n): Promise<OIDCTokenResponseBody> {\n const refresher = await GenericAuthenticationRefresher.build(\n {\n ...config,\n oauthServer: config.oauthServer ?? AUTH_SERVER,\n },\n storage,\n config.endpointOverrides,\n );\n\n return refresher.refreshTokens();\n}\n"]}
|
|
File without changes
|