![]() Server : Apache/2 System : Linux server-15-235-50-60 5.15.0-164-generic #174-Ubuntu SMP Fri Nov 14 20:25:16 UTC 2025 x86_64 User : gositeme ( 1004) PHP Version : 8.2.29 Disable Function : exec,system,passthru,shell_exec,proc_close,proc_open,dl,popen,show_source,posix_kill,posix_mkfifo,posix_getpwuid,posix_setpgid,posix_setsid,posix_setuid,posix_setgid,posix_seteuid,posix_setegid,posix_uname Directory : /home/gositeme/domains/lavocat.quebec/private_html/node_modules/next-auth/src/react/ |
// Note about signIn() and signOut() methods:
//
// On signIn() and signOut() we pass 'json: true' to request a response in JSON
// instead of HTTP as redirect URLs on other domains are not returned to
// requests made using the fetch API in the browser, and we need to ask the API
// to return the response as a JSON object (the end point still defaults to
// returning an HTTP response with a redirect for non-JavaScript clients).
//
// We use HTTP POST requests with CSRF Tokens to protect against CSRF attacks.
import * as React from "react"
import _logger, { proxyLogger } from "../utils/logger"
import parseUrl from "../utils/parse-url"
import { Session } from ".."
import {
BroadcastChannel,
CtxOrReq,
apiBaseUrl,
fetchData,
now,
AuthClientConfig,
} from "../client/_utils"
import type {
ClientSafeProvider,
LiteralUnion,
SessionProviderProps,
SignInAuthorizationParams,
SignInOptions,
SignInResponse,
SignOutParams,
SignOutResponse,
UseSessionOptions,
} from "./types"
import type {
BuiltInProviderType,
RedirectableProviderType,
} from "../providers"
export * from "./types"
// This behaviour mirrors the default behaviour for getting the site name that
// happens server side in server/index.js
// 1. An empty value is legitimate when the code is being invoked client side as
// relative URLs are valid in that context and so defaults to empty.
// 2. When invoked server side the value is picked up from an environment
// variable and defaults to 'http://localhost:3000'.
const __NEXTAUTH: AuthClientConfig = {
baseUrl: parseUrl(process.env.NEXTAUTH_URL ?? process.env.VERCEL_URL).origin,
basePath: parseUrl(process.env.NEXTAUTH_URL).path,
baseUrlServer: parseUrl(
process.env.NEXTAUTH_URL_INTERNAL ??
process.env.NEXTAUTH_URL ??
process.env.VERCEL_URL
).origin,
basePathServer: parseUrl(
process.env.NEXTAUTH_URL_INTERNAL ?? process.env.NEXTAUTH_URL
).path,
_lastSync: 0,
_session: undefined,
_getSession: () => {},
}
const broadcast = BroadcastChannel()
const logger = proxyLogger(_logger, __NEXTAUTH.basePath)
function useOnline() {
const [isOnline, setIsOnline] = React.useState(
typeof navigator !== "undefined" ? navigator.onLine : false
)
const setOnline = () => setIsOnline(true)
const setOffline = () => setIsOnline(false)
React.useEffect(() => {
window.addEventListener("online", setOnline)
window.addEventListener("offline", setOffline)
return () => {
window.removeEventListener("online", setOnline)
window.removeEventListener("offline", setOffline)
}
}, [])
return isOnline
}
type UpdateSession = (data?: any) => Promise<Session | null>
export type SessionContextValue<R extends boolean = false> = R extends true
?
| { update: UpdateSession; data: Session; status: "authenticated" }
| { update: UpdateSession; data: null; status: "loading" }
:
| { update: UpdateSession; data: Session; status: "authenticated" }
| {
update: UpdateSession
data: null
status: "unauthenticated" | "loading"
}
export const SessionContext = React.createContext?.<
SessionContextValue | undefined
>(undefined)
/**
* React Hook that gives you access
* to the logged in user's session data.
*
* [Documentation](https://next-auth.js.org/getting-started/client#usesession)
*/
export function useSession<R extends boolean>(
options?: UseSessionOptions<R>
): SessionContextValue<R> {
if (!SessionContext) {
throw new Error("React Context is unavailable in Server Components")
}
// @ts-expect-error Satisfy TS if branch on line below
const value: SessionContextValue<R> = React.useContext(SessionContext)
if (!value && process.env.NODE_ENV !== "production") {
throw new Error(
"[next-auth]: `useSession` must be wrapped in a <SessionProvider />"
)
}
const { required, onUnauthenticated } = options ?? {}
const requiredAndNotLoading = required && value.status === "unauthenticated"
React.useEffect(() => {
if (requiredAndNotLoading) {
const url = `/api/auth/signin?${new URLSearchParams({
error: "SessionRequired",
callbackUrl: window.location.href,
})}`
if (onUnauthenticated) onUnauthenticated()
else window.location.href = url
}
}, [requiredAndNotLoading, onUnauthenticated])
if (requiredAndNotLoading) {
return {
data: value.data,
update: value.update,
status: "loading",
}
}
return value
}
export type GetSessionParams = CtxOrReq & {
event?: "storage" | "timer" | "hidden" | string
triggerEvent?: boolean
broadcast?: boolean
}
export async function getSession(params?: GetSessionParams) {
const session = await fetchData<Session>(
"session",
__NEXTAUTH,
logger,
params
)
if (params?.broadcast ?? true) {
broadcast.post({ event: "session", data: { trigger: "getSession" } })
}
return session
}
/**
* Returns the current Cross Site Request Forgery Token (CSRF Token)
* required to make POST requests (e.g. for signing in and signing out).
* You likely only need to use this if you are not using the built-in
* `signIn()` and `signOut()` methods.
*
* [Documentation](https://next-auth.js.org/getting-started/client#getcsrftoken)
*/
export async function getCsrfToken(params?: CtxOrReq) {
const response = await fetchData<{ csrfToken: string }>(
"csrf",
__NEXTAUTH,
logger,
params
)
return response?.csrfToken
}
/**
* It calls `/api/auth/providers` and returns
* a list of the currently configured authentication providers.
* It can be useful if you are creating a dynamic custom sign in page.
*
* [Documentation](https://next-auth.js.org/getting-started/client#getproviders)
*/
export async function getProviders() {
return await fetchData<
Record<LiteralUnion<BuiltInProviderType>, ClientSafeProvider>
>("providers", __NEXTAUTH, logger)
}
/**
* Client-side method to initiate a signin flow
* or send the user to the signin page listing all possible providers.
* Automatically adds the CSRF token to the request.
*
* [Documentation](https://next-auth.js.org/getting-started/client#signin)
*/
export async function signIn<
P extends RedirectableProviderType | undefined = undefined
>(
provider?: LiteralUnion<
P extends RedirectableProviderType
? P | BuiltInProviderType
: BuiltInProviderType
>,
options?: SignInOptions,
authorizationParams?: SignInAuthorizationParams
): Promise<
P extends RedirectableProviderType ? SignInResponse | undefined : undefined
> {
const { callbackUrl = window.location.href, redirect = true } = options ?? {}
const baseUrl = apiBaseUrl(__NEXTAUTH)
const providers = await getProviders()
if (!providers) {
window.location.href = `${baseUrl}/error`
return
}
if (!provider || !(provider in providers)) {
window.location.href = `${baseUrl}/signin?${new URLSearchParams({
callbackUrl,
})}`
return
}
const isCredentials = providers[provider].type === "credentials"
const isEmail = providers[provider].type === "email"
const isSupportingReturn = isCredentials || isEmail
const signInUrl = `${baseUrl}/${
isCredentials ? "callback" : "signin"
}/${provider}`
const _signInUrl = `${signInUrl}${authorizationParams ? `?${new URLSearchParams(authorizationParams)}` : ""}`
const res = await fetch(_signInUrl, {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
// @ts-expect-error
body: new URLSearchParams({
...options,
csrfToken: await getCsrfToken(),
callbackUrl,
json: true,
}),
})
const data = await res.json()
// TODO: Do not redirect for Credentials and Email providers by default in next major
if (redirect || !isSupportingReturn) {
const url = data.url ?? callbackUrl
window.location.href = url
// If url contains a hash, the browser does not reload the page. We reload manually
if (url.includes("#")) window.location.reload()
return
}
const error = new URL(data.url).searchParams.get("error")
if (res.ok) {
await __NEXTAUTH._getSession({ event: "storage" })
}
return {
error,
status: res.status,
ok: res.ok,
url: error ? null : data.url,
} as any
}
/**
* Signs the user out, by removing the session cookie.
* Automatically adds the CSRF token to the request.
*
* [Documentation](https://next-auth.js.org/getting-started/client#signout)
*/
export async function signOut<R extends boolean = true>(
options?: SignOutParams<R>
): Promise<R extends true ? undefined : SignOutResponse> {
const { callbackUrl = window.location.href } = options ?? {}
const baseUrl = apiBaseUrl(__NEXTAUTH)
const fetchOptions = {
method: "post",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
// @ts-expect-error
body: new URLSearchParams({
csrfToken: await getCsrfToken(),
callbackUrl,
json: true,
}),
}
const res = await fetch(`${baseUrl}/signout`, fetchOptions)
const data = await res.json()
broadcast.post({ event: "session", data: { trigger: "signout" } })
if (options?.redirect ?? true) {
const url = data.url ?? callbackUrl
window.location.href = url
// If url contains a hash, the browser does not reload the page. We reload manually
if (url.includes("#")) window.location.reload()
// @ts-expect-error
return
}
await __NEXTAUTH._getSession({ event: "storage" })
return data
}
/**
* Provider to wrap the app in to make session data available globally.
* Can also be used to throttle the number of requests to the endpoint
* `/api/auth/session`.
*
* [Documentation](https://next-auth.js.org/getting-started/client#sessionprovider)
*/
export function SessionProvider(props: SessionProviderProps) {
if (!SessionContext) {
throw new Error("React Context is unavailable in Server Components")
}
const { children, basePath, refetchInterval, refetchWhenOffline } = props
if (basePath) __NEXTAUTH.basePath = basePath
/**
* If session was `null`, there was an attempt to fetch it,
* but it failed, but we still treat it as a valid initial value.
*/
const hasInitialSession = props.session !== undefined
/** If session was passed, initialize as already synced */
__NEXTAUTH._lastSync = hasInitialSession ? now() : 0
const [session, setSession] = React.useState(() => {
if (hasInitialSession) __NEXTAUTH._session = props.session
return props.session
})
/** If session was passed, initialize as not loading */
const [loading, setLoading] = React.useState(!hasInitialSession)
React.useEffect(() => {
__NEXTAUTH._getSession = async ({ event } = {}) => {
try {
const storageEvent = event === "storage"
// We should always update if we don't have a client session yet
// or if there are events from other tabs/windows
if (storageEvent || __NEXTAUTH._session === undefined) {
__NEXTAUTH._lastSync = now()
__NEXTAUTH._session = await getSession({
broadcast: !storageEvent,
})
setSession(__NEXTAUTH._session)
return
}
if (
// If there is no time defined for when a session should be considered
// stale, then it's okay to use the value we have until an event is
// triggered which updates it
!event ||
// If the client doesn't have a session then we don't need to call
// the server to check if it does (if they have signed in via another
// tab or window that will come through as a "stroage" event
// event anyway)
__NEXTAUTH._session === null ||
// Bail out early if the client session is not stale yet
now() < __NEXTAUTH._lastSync
) {
return
}
// An event or session staleness occurred, update the client session.
__NEXTAUTH._lastSync = now()
__NEXTAUTH._session = await getSession()
setSession(__NEXTAUTH._session)
} catch (error) {
logger.error("CLIENT_SESSION_ERROR", error as Error)
} finally {
setLoading(false)
}
}
__NEXTAUTH._getSession()
return () => {
__NEXTAUTH._lastSync = 0
__NEXTAUTH._session = undefined
__NEXTAUTH._getSession = () => {}
}
}, [])
React.useEffect(() => {
// Listen for storage events and update session if event fired from
// another window (but suppress firing another event to avoid a loop)
// Fetch new session data but tell it to not to fire another event to
// avoid an infinite loop.
// Note: We could pass session data through and do something like
// `setData(message.data)` but that can cause problems depending
// on how the session object is being used in the client; it is
// more robust to have each window/tab fetch it's own copy of the
// session object rather than share it across instances.
const unsubscribe = broadcast.receive(() =>
__NEXTAUTH._getSession({ event: "storage" })
)
return () => unsubscribe()
}, [])
React.useEffect(() => {
const { refetchOnWindowFocus = true } = props
// Listen for when the page is visible, if the user switches tabs
// and makes our tab visible again, re-fetch the session, but only if
// this feature is not disabled.
const visibilityHandler = () => {
if (refetchOnWindowFocus && document.visibilityState === "visible")
__NEXTAUTH._getSession({ event: "visibilitychange" })
}
document.addEventListener("visibilitychange", visibilityHandler, false)
return () =>
document.removeEventListener("visibilitychange", visibilityHandler, false)
}, [props.refetchOnWindowFocus])
const isOnline = useOnline()
// TODO: Flip this behavior in next major version
const shouldRefetch = refetchWhenOffline !== false || isOnline
React.useEffect(() => {
if (refetchInterval && shouldRefetch) {
const refetchIntervalTimer = setInterval(() => {
if (__NEXTAUTH._session) {
__NEXTAUTH._getSession({ event: "poll" })
}
}, refetchInterval * 1000)
return () => clearInterval(refetchIntervalTimer)
}
}, [refetchInterval, shouldRefetch])
const value: any = React.useMemo(
() => ({
data: session,
status: loading
? "loading"
: session
? "authenticated"
: "unauthenticated",
async update(data) {
if (loading || !session) return
setLoading(true)
const newSession = await fetchData<Session>(
"session",
__NEXTAUTH,
logger,
{ req: { body: { csrfToken: await getCsrfToken(), data } } }
)
setLoading(false)
if (newSession) {
setSession(newSession)
broadcast.post({ event: "session", data: { trigger: "getSession" } })
}
return newSession
},
}),
[session, loading]
)
return (
<SessionContext.Provider value={value}>{children}</SessionContext.Provider>
)
}