@oauth42/next 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{middleware-B8dYrjZ1.d.mts → auth-ClOnIcCK.d.mts} +22 -31
- package/dist/{middleware-B8dYrjZ1.d.ts → auth-ClOnIcCK.d.ts} +22 -31
- package/dist/client/index.d.mts +15 -7
- package/dist/client/index.d.ts +15 -7
- package/dist/client/index.js +13 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +13 -2
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +220 -12
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +221 -13
- package/dist/index.mjs.map +1 -1
- package/dist/middleware/index.d.mts +39 -0
- package/dist/middleware/index.d.ts +39 -0
- package/dist/middleware/index.js +172 -0
- package/dist/middleware/index.js.map +1 -0
- package/dist/middleware/index.mjs +144 -0
- package/dist/middleware/index.mjs.map +1 -0
- package/dist/server/index.d.mts +2 -1
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +220 -12
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +223 -15
- package/dist/server/index.mjs.map +1 -1
- package/package.json +8 -3
- package/src/types/next-auth.d.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/client/index.ts","../../src/client/hooks.ts","../../src/client/components.tsx","../../src/utils/hosted-auth.ts","../../src/client/auth.ts"],"sourcesContent":["// Client-side exports\n\n// Re-export commonly used next-auth/react functions\nexport { signIn, signOut, useSession, SessionProvider } from 'next-auth/react';\nexport type { Session } from 'next-auth';\nexport {\n useOAuth42Session,\n useOAuth42User,\n useOAuth42Tokens,\n useRequireAuth,\n} from './hooks';\n\nexport type {\n OAuth42Session,\n UseOAuth42SessionReturn,\n} from './hooks';\n\nexport {\n SignInButton,\n SignOutButton,\n UserProfile,\n AuthStatus,\n ProtectedComponent,\n} from './components';\n\nexport type {\n SignInButtonProps,\n SignOutButtonProps,\n UserProfileProps,\n AuthStatusProps,\n ProtectedComponentProps,\n} from './components';\n\n// Hosted auth utilities\nexport {\n redirectToHostedAuth,\n verifyState,\n DEFAULT_HOSTED_AUTH_CONFIG,\n} from '../utils/hosted-auth';\n\nexport type {\n HostedAuthOptions,\n HostedAuthConfig,\n} from '../utils/hosted-auth';\n\n// Custom authentication utilities\nexport {\n loginWithPassword,\n initiateAuthenticatorLogin,\n completeAuthenticatorLogin,\n simulateApproval,\n logout,\n logoutEverywhere,\n} from './auth';\n\nexport type {\n LoginWithPasswordOptions,\n LoginWithAuthenticatorOptions,\n AuthError,\n} from './auth';","import { useSession, signIn, signOut } from 'next-auth/react';\nimport { useCallback, useEffect, useState } from 'react';\n\nexport type OAuth42Session<E = {}> = ({\n user?: {\n email?: string | null;\n name?: string | null;\n image?: string | null;\n username?: string;\n emailVerified?: boolean;\n };\n accessToken?: string;\n idToken?: string;\n expires?: string;\n}) & E;\n\nexport interface UseOAuth42SessionReturn<E = {}> {\n session: OAuth42Session<E> | null;\n loading: boolean;\n error: Error | null;\n isAuthenticated: boolean;\n signIn: () => Promise<void>;\n signOut: () => Promise<void>;\n}\n\n/**\n * Hook to manage OAuth42 session with optional extra fields\n */\nexport function useOAuth42Session<E = {}>(): UseOAuth42SessionReturn<E> {\n const { data: session, status } = useSession();\n const [error, setError] = useState<Error | null>(null);\n \n const handleSignIn = useCallback(async () => {\n try {\n setError(null);\n await signIn('oauth42');\n } catch (err) {\n setError(err as Error);\n }\n }, []);\n \n const handleSignOut = useCallback(async () => {\n try {\n setError(null);\n await signOut();\n } catch (err) {\n setError(err as Error);\n }\n }, []);\n \n return {\n session: session as unknown as OAuth42Session<E> | null,\n loading: status === 'loading',\n error,\n isAuthenticated: status === 'authenticated',\n signIn: handleSignIn,\n signOut: handleSignOut,\n };\n}\n\n/**\n * Hook to get the current OAuth42 user\n */\nexport function useOAuth42User<E = {}>() {\n const { session, isAuthenticated } = useOAuth42Session<E>();\n \n return {\n user: isAuthenticated ? session?.user : null,\n isAuthenticated,\n };\n}\n\n/**\n * Hook to manage OAuth42 tokens\n */\nexport function useOAuth42Tokens<E = {}>() {\n const { session } = useOAuth42Session<E>();\n const [isExpired, setIsExpired] = useState(false);\n \n useEffect(() => {\n if (session?.expires) {\n const expiryTime = new Date(session.expires).getTime();\n const now = Date.now();\n setIsExpired(now >= expiryTime);\n \n // Set a timer to update expiry status\n const timeUntilExpiry = expiryTime - now;\n if (timeUntilExpiry > 0) {\n const timer = setTimeout(() => {\n setIsExpired(true);\n }, timeUntilExpiry);\n \n return () => clearTimeout(timer);\n }\n }\n }, [session?.expires]);\n \n return {\n accessToken: session?.accessToken,\n idToken: session?.idToken,\n isExpired,\n refreshToken: async () => {\n // Trigger a session refresh\n await signIn('oauth42');\n },\n };\n}\n\n/**\n * Hook for protected routes\n */\nexport function useRequireAuth(redirectTo: string = '/auth/signin') {\n const { isAuthenticated, loading } = useOAuth42Session();\n const [isRedirecting, setIsRedirecting] = useState(false);\n \n useEffect(() => {\n if (!loading && !isAuthenticated && !isRedirecting) {\n setIsRedirecting(true);\n if (typeof window !== 'undefined') {\n window.location.href = redirectTo;\n }\n }\n }, [isAuthenticated, loading, redirectTo, isRedirecting]);\n \n return {\n isAuthenticated,\n loading: loading || isRedirecting,\n };\n}\n","import React from 'react';\nimport { signIn, signOut } from 'next-auth/react';\nimport { useOAuth42Session, useOAuth42User } from './hooks';\n\nexport interface SignInButtonProps {\n children?: React.ReactNode;\n className?: string;\n callbackUrl?: string;\n onClick?: () => void;\n}\n\n/**\n * Sign in button component\n */\nexport function SignInButton({ \n children = 'Sign in with OAuth42', \n className = '',\n callbackUrl = '/',\n onClick\n}: SignInButtonProps) {\n const handleClick = async () => {\n if (onClick) onClick();\n await signIn('oauth42', { callbackUrl });\n };\n \n return (\n <button\n onClick={handleClick}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport interface SignOutButtonProps {\n children?: React.ReactNode;\n className?: string;\n callbackUrl?: string;\n onClick?: () => void;\n}\n\n/**\n * Sign out button component\n */\nexport function SignOutButton({ \n children = 'Sign out', \n className = '',\n callbackUrl = '/',\n onClick\n}: SignOutButtonProps) {\n const handleClick = async () => {\n if (onClick) onClick();\n await signOut({ callbackUrl });\n };\n \n return (\n <button\n onClick={handleClick}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport interface UserProfileProps {\n className?: string;\n showEmail?: boolean;\n showName?: boolean;\n showImage?: boolean;\n loadingComponent?: React.ReactNode;\n notAuthenticatedComponent?: React.ReactNode;\n}\n\n/**\n * User profile display component\n */\nexport function UserProfile({\n className = '',\n showEmail = true,\n showName = true,\n showImage = true,\n loadingComponent = <div>Loading...</div>,\n notAuthenticatedComponent = <div>Not authenticated</div>,\n}: UserProfileProps) {\n const { session, loading, isAuthenticated } = useOAuth42Session();\n \n if (loading) {\n return <>{loadingComponent}</>;\n }\n \n if (!isAuthenticated || !session?.user) {\n return <>{notAuthenticatedComponent}</>;\n }\n \n const { user } = session;\n \n return (\n <div className={className}>\n {showImage && user.image && (\n <img \n src={user.image} \n alt={user.name || 'User'} \n style={{ width: 50, height: 50, borderRadius: '50%' }}\n />\n )}\n {showName && user.name && <div>{user.name}</div>}\n {showEmail && user.email && <div>{user.email}</div>}\n </div>\n );\n}\n\nexport interface AuthStatusProps {\n authenticatedComponent?: React.ReactNode;\n unauthenticatedComponent?: React.ReactNode;\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * Conditional rendering based on auth status\n */\nexport function AuthStatus({\n authenticatedComponent,\n unauthenticatedComponent,\n loadingComponent = <div>Loading...</div>,\n}: AuthStatusProps) {\n const { isAuthenticated, loading } = useOAuth42Session();\n \n if (loading) {\n return <>{loadingComponent}</>;\n }\n \n return <>{isAuthenticated ? authenticatedComponent : unauthenticatedComponent}</>;\n}\n\nexport interface ProtectedComponentProps {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * Wrapper component for protected content\n */\nexport function ProtectedComponent({\n children,\n fallback = <SignInButton />,\n loadingComponent = <div>Loading...</div>,\n}: ProtectedComponentProps) {\n const { isAuthenticated, loading } = useOAuth42Session();\n \n if (loading) {\n return <>{loadingComponent}</>;\n }\n \n if (!isAuthenticated) {\n return <>{fallback}</>;\n }\n \n return <>{children}</>;\n}","/**\n * Utilities for OAuth42 Hosted Authentication\n */\n\nexport interface HostedAuthOptions {\n /** OAuth2 client ID */\n clientId: string;\n /** Redirect URI after authentication */\n redirectUri: string;\n /** OAuth2 scopes (space-separated) */\n scope?: string;\n /** OAuth2 state parameter for CSRF protection */\n state?: string;\n /** Base URL for hosted auth (defaults to production) */\n baseUrl?: string;\n}\n\n/**\n * Generate a random state parameter for CSRF protection\n */\nfunction generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Redirect to OAuth42 hosted authentication pages\n *\n * @example\n * ```ts\n * import { redirectToHostedAuth } from '@oauth42/next/client';\n *\n * function LoginButton() {\n * return (\n * <button onClick={() => redirectToHostedAuth({\n * clientId: process.env.NEXT_PUBLIC_OAUTH42_CLIENT_ID!,\n * redirectUri: `${window.location.origin}/api/auth/callback`,\n * })}>\n * Sign in with OAuth42\n * </button>\n * );\n * }\n * ```\n */\nexport function redirectToHostedAuth(options: HostedAuthOptions): void {\n const {\n clientId,\n redirectUri,\n scope = 'openid profile email',\n state = generateState(),\n baseUrl = 'https://auth.oauth42.com',\n } = options;\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: 'code',\n scope,\n state,\n });\n\n const authUrl = `${baseUrl}/login?${params.toString()}`;\n\n // Store state in sessionStorage for verification on callback\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('oauth42_state', state);\n window.location.href = authUrl;\n }\n}\n\n/**\n * Verify state parameter on OAuth2 callback\n * Call this in your callback page to verify the state matches\n *\n * @example\n * ```ts\n * import { verifyState } from '@oauth42/next/client';\n *\n * export default function CallbackPage() {\n * const searchParams = useSearchParams();\n * const state = searchParams.get('state');\n *\n * if (!verifyState(state)) {\n * return <div>Invalid state parameter</div>;\n * }\n *\n * // Continue with token exchange...\n * }\n * ```\n */\nexport function verifyState(state: string | null): boolean {\n if (typeof window === 'undefined') return false;\n if (!state) return false;\n\n const storedState = sessionStorage.getItem('oauth42_state');\n sessionStorage.removeItem('oauth42_state');\n\n return storedState === state;\n}\n\n/**\n * Configuration for hosted authentication\n */\nexport interface HostedAuthConfig {\n /** Enable hosted authentication */\n enabled: boolean;\n /** Base URL for hosted auth pages (optional, defaults to production) */\n baseUrl?: string;\n /** Feature flags for hosted auth */\n features?: {\n /** Allow user signup */\n signup?: boolean;\n /** Allow social login */\n socialLogin?: boolean;\n /** Allow password reset */\n passwordReset?: boolean;\n };\n}\n\n/**\n * Default hosted auth configuration\n */\nexport const DEFAULT_HOSTED_AUTH_CONFIG: HostedAuthConfig = {\n enabled: true,\n baseUrl: 'https://auth.oauth42.com',\n features: {\n signup: true,\n socialLogin: false,\n passwordReset: true,\n },\n};\n","/**\n * OAuth42 Custom Authentication Utilities\n *\n * Provides functions for implementing custom login UIs in customer apps\n * while properly handling OAuth2 PKCE flows and next-auth integration.\n */\n\nimport { signIn } from 'next-auth/react';\n\n// PKCE utilities\nfunction base64URLEncode(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\nasync function generateCodeVerifier(): Promise<string> {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64URLEncode(array.buffer);\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const hash = await crypto.subtle.digest('SHA-256', data);\n return base64URLEncode(hash);\n}\n\nfunction generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64URLEncode(array.buffer);\n}\n\nexport interface LoginWithPasswordOptions {\n email: string;\n password: string;\n mfaCode?: string;\n /**\n * URL to redirect to after successful authentication.\n * If not provided, will redirect to '/'\n */\n callbackUrl?: string;\n}\n\nexport interface LoginWithAuthenticatorOptions {\n email: string;\n sessionId: string;\n /**\n * URL to redirect to after successful authentication.\n * If not provided, will redirect to '/'\n */\n callbackUrl?: string;\n}\n\nexport interface AuthError {\n error: string;\n error_description?: string;\n requires_enrollment?: boolean;\n enrollment_token?: string;\n requires_mfa?: boolean;\n}\n\n/**\n * Authenticate with email/password and complete OAuth PKCE flow\n *\n * This function handles the full authentication flow:\n * 1. Authenticates with the backend using credentials\n * 2. Uses the access token to authorize the OAuth client\n * 3. Exchanges authorization code for tokens via next-auth\n *\n * @example\n * ```tsx\n * const result = await loginWithPassword({\n * email: 'user@example.com',\n * password: 'password123',\n * callbackUrl: '/dashboard'\n * });\n *\n * if (result.success) {\n * // User is authenticated, next-auth session is set\n * } else if (result.requires_mfa) {\n * // Prompt for MFA code and call again with mfaCode\n * }\n * ```\n */\nexport async function loginWithPassword(\n options: LoginWithPasswordOptions\n): Promise<{ success: boolean; access_token?: string } & Partial<AuthError>> {\n try {\n // Step 1: Authenticate with backend to get access token\n const loginResponse = await fetch('/api/auth/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: options.email,\n password: options.password,\n ...(options.mfaCode ? { mfa_code: options.mfaCode } : {}),\n }),\n });\n\n if (!loginResponse.ok) {\n const errorData = await loginResponse.json().catch(() => ({}));\n const desc: string = errorData?.error_description || errorData?.message || '';\n\n // Handle special cases\n if (loginResponse.status === 403 && errorData?.requires_enrollment) {\n return {\n success: false,\n error: 'enrollment_required',\n error_description: 'MFA enrollment required',\n requires_enrollment: true,\n enrollment_token: errorData.enrollment_token,\n };\n }\n\n if (loginResponse.status === 403 && /mfa required/i.test(desc)) {\n return {\n success: false,\n error: 'mfa_required',\n error_description: 'MFA code required',\n requires_mfa: true,\n };\n }\n\n if (loginResponse.status === 401 && /invalid mfa code/i.test(desc)) {\n return {\n success: false,\n error: 'invalid_mfa_code',\n error_description: 'Invalid MFA code',\n requires_mfa: true,\n };\n }\n\n return {\n success: false,\n error: 'authentication_failed',\n error_description: desc || 'Invalid credentials',\n };\n }\n\n const { access_token } = await loginResponse.json();\n\n // Return access token for the application to use in OAuth authorize flow\n return { success: true, access_token };\n } catch (error) {\n console.error('Login error:', error);\n return {\n success: false,\n error: 'network_error',\n error_description: 'Failed to connect to authentication server',\n };\n }\n}\n\n/**\n * Initiate authenticator (passwordless) login and return challenge code\n *\n * @example\n * ```tsx\n * const result = await initiateAuthenticatorLogin({\n * email: 'user@example.com',\n * sessionId: crypto.randomUUID()\n * });\n *\n * if (result.success) {\n * // Display result.challengeCode to user\n * // Wait for WebSocket approval or poll for completion\n * }\n * ```\n */\nexport async function initiateAuthenticatorLogin(\n options: LoginWithAuthenticatorOptions\n): Promise<{\n success: boolean;\n challengeCode?: string;\n challengeId?: string;\n} & Partial<AuthError>> {\n try {\n const response = await fetch('/api/auth/passwordless/initiate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: options.email,\n session_id: options.sessionId,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n return {\n success: false,\n error: 'initiation_failed',\n error_description: errorData.error_description || 'Failed to create challenge',\n };\n }\n\n const data = await response.json();\n\n return {\n success: true,\n challengeCode: data.challenge_code,\n challengeId: data.challenge_id,\n };\n } catch (error) {\n console.error('Authenticator login error:', error);\n return {\n success: false,\n error: 'network_error',\n error_description: 'Failed to connect to authentication server',\n };\n }\n}\n\n/**\n * Complete authenticator login after approval\n *\n * Call this after receiving approval notification via WebSocket\n * or after the user has approved on their mobile device.\n * Returns the access token for the application to use in OAuth authorize flow.\n *\n * @param accessToken - Access token received from approval payload\n */\nexport async function completeAuthenticatorLogin(\n accessToken: string\n): Promise<{ success: boolean; access_token: string }> {\n return { success: true, access_token: accessToken };\n}\n\n/**\n * Simulate approval for testing (development only)\n *\n * @param challengeId - The challenge ID to approve\n * @param selectedCode - The code that was displayed to the user\n */\nexport async function simulateApproval(\n challengeId: string,\n selectedCode: string\n): Promise<{ success: boolean }> {\n try {\n await fetch('/api/auth/challenge/approve', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n challenge_id: challengeId,\n selected_code: selectedCode,\n }),\n });\n\n return { success: true };\n } catch (error) {\n console.error('Simulated approval failed:', error);\n return { success: false };\n }\n}\n\n/**\n * Logout the current user from the app only (app-level logout)\n *\n * This clears the next-auth session for this app only. The user remains\n * logged into the OAuth42 provider and will auto-authenticate on next login.\n * This is standard SSO behavior.\n *\n * For provider-level logout (sign out of all apps), use logoutEverywhere().\n *\n * @param callbackUrl - URL to redirect to after logout (default: '/')\n *\n * @example\n * ```tsx\n * import { logout } from '@oauth42/next/client';\n *\n * const handleLogout = async () => {\n * await logout({ callbackUrl: '/login' });\n * };\n * ```\n */\nexport async function logout(options?: { callbackUrl?: string }): Promise<void> {\n // Import signOut from next-auth/react\n const { signOut } = await import('next-auth/react');\n\n // Clear next-auth session (app-level only)\n await signOut({\n callbackUrl: options?.callbackUrl || '/',\n redirect: true\n });\n}\n\n/**\n * Logout the current user from ALL apps using OAuth42 (provider-level logout)\n *\n * This redirects to the OAuth42 provider's logout endpoint to clear the\n * oauth42_session cookie, effectively logging the user out of all apps.\n *\n * Use this when testing fresh login flows or when the user explicitly\n * wants to sign out of everything.\n *\n * @param issuer - The OAuth42 issuer URL (e.g., 'https://localhost:8443')\n * @param callbackUrl - URL to redirect to after logout (default: current origin)\n *\n * @example\n * ```tsx\n * import { logoutEverywhere } from '@oauth42/next/client';\n *\n * const handleLogoutEverywhere = () => {\n * const issuer = process.env.NEXT_PUBLIC_OAUTH42_ISSUER || 'https://localhost:8443';\n * logoutEverywhere(issuer, '/auth/signin');\n * };\n * ```\n */\nexport function logoutEverywhere(issuer: string, callbackUrl?: string): void {\n const redirectUri = callbackUrl || window.location.origin;\n\n // Redirect to OAuth42 provider logout endpoint\n // This clears the oauth42_session cookie and redirects back\n window.location.href = `${issuer}/auth/logout?redirect_uri=${encodeURIComponent(redirectUri)}`;\n}\n"],"mappings":"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","names":["signIn","signOut","useSession","signIn","signOut","signIn","signOut","signOut"]}
|
|
1
|
+
{"version":3,"sources":["../../src/client/index.ts","../../src/client/hooks.ts","../../src/client/components.tsx","../../src/utils/hosted-auth.ts","../../src/client/auth.ts"],"sourcesContent":["// Client-side exports\n\n// Re-export commonly used next-auth/react functions\nexport { signIn, signOut, useSession, SessionProvider } from 'next-auth/react';\nexport type { Session } from 'next-auth';\nexport {\n useOAuth42Session,\n useOAuth42User,\n useOAuth42Tokens,\n useRequireAuth,\n} from './hooks';\n\nexport type {\n OAuth42Session,\n UseOAuth42SessionReturn,\n} from './hooks';\n\nexport {\n SignInButton,\n SignOutButton,\n UserProfile,\n AuthStatus,\n ProtectedComponent,\n} from './components';\n\nexport type {\n SignInButtonProps,\n SignOutButtonProps,\n UserProfileProps,\n AuthStatusProps,\n ProtectedComponentProps,\n} from './components';\n\n// Hosted auth utilities\nexport {\n redirectToHostedAuth,\n verifyState,\n DEFAULT_HOSTED_AUTH_CONFIG,\n} from '../utils/hosted-auth';\n\nexport type {\n HostedAuthOptions,\n HostedAuthConfig,\n} from '../utils/hosted-auth';\n\n// Custom authentication utilities\nexport {\n loginWithPassword,\n initiateAuthenticatorLogin,\n completeAuthenticatorLogin,\n simulateApproval,\n logout,\n logoutEverywhere,\n} from './auth';\n\nexport type {\n LoginWithPasswordOptions,\n LoginWithAuthenticatorOptions,\n AuthError,\n} from './auth';","import { useSession, signIn, signOut } from 'next-auth/react';\nimport { useCallback, useEffect, useState } from 'react';\n\nexport type OAuth42Session<E = {}> = ({\n user?: {\n email?: string | null;\n name?: string | null;\n image?: string | null;\n username?: string;\n emailVerified?: boolean;\n };\n accessToken?: string;\n idToken?: string;\n expires?: string;\n}) & E;\n\nexport interface UseOAuth42SessionReturn<E = {}> {\n session: OAuth42Session<E> | null;\n loading: boolean;\n error: Error | null;\n isAuthenticated: boolean;\n signIn: () => Promise<void>;\n signOut: () => Promise<void>;\n}\n\n/**\n * Hook to manage OAuth42 session with optional extra fields\n */\nexport function useOAuth42Session<E = {}>(): UseOAuth42SessionReturn<E> {\n const { data: session, status } = useSession();\n const [error, setError] = useState<Error | null>(null);\n \n const handleSignIn = useCallback(async () => {\n try {\n setError(null);\n await signIn('oauth42');\n } catch (err) {\n setError(err as Error);\n }\n }, []);\n \n const handleSignOut = useCallback(async () => {\n try {\n setError(null);\n await signOut();\n } catch (err) {\n setError(err as Error);\n }\n }, []);\n \n return {\n session: session as unknown as OAuth42Session<E> | null,\n loading: status === 'loading',\n error,\n isAuthenticated: status === 'authenticated',\n signIn: handleSignIn,\n signOut: handleSignOut,\n };\n}\n\n/**\n * Hook to get the current OAuth42 user\n */\nexport function useOAuth42User<E = {}>() {\n const { session, isAuthenticated } = useOAuth42Session<E>();\n \n return {\n user: isAuthenticated ? session?.user : null,\n isAuthenticated,\n };\n}\n\n/**\n * Hook to manage OAuth42 tokens\n */\nexport function useOAuth42Tokens<E = {}>() {\n const { session } = useOAuth42Session<E>();\n const [isExpired, setIsExpired] = useState(false);\n \n useEffect(() => {\n if (session?.expires) {\n const expiryTime = new Date(session.expires).getTime();\n const now = Date.now();\n setIsExpired(now >= expiryTime);\n \n // Set a timer to update expiry status\n const timeUntilExpiry = expiryTime - now;\n if (timeUntilExpiry > 0) {\n const timer = setTimeout(() => {\n setIsExpired(true);\n }, timeUntilExpiry);\n \n return () => clearTimeout(timer);\n }\n }\n }, [session?.expires]);\n \n return {\n accessToken: session?.accessToken,\n idToken: session?.idToken,\n isExpired,\n refreshToken: async () => {\n // Trigger a session refresh\n await signIn('oauth42');\n },\n };\n}\n\n/**\n * Hook for protected routes\n */\nexport function useRequireAuth(redirectTo: string = '/auth/signin') {\n const { isAuthenticated, loading } = useOAuth42Session();\n const [isRedirecting, setIsRedirecting] = useState(false);\n \n useEffect(() => {\n if (!loading && !isAuthenticated && !isRedirecting) {\n setIsRedirecting(true);\n if (typeof window !== 'undefined') {\n window.location.href = redirectTo;\n }\n }\n }, [isAuthenticated, loading, redirectTo, isRedirecting]);\n \n return {\n isAuthenticated,\n loading: loading || isRedirecting,\n };\n}\n","import React from 'react';\nimport { signIn, signOut } from 'next-auth/react';\nimport { useOAuth42Session, useOAuth42User } from './hooks';\n\nexport interface SignInButtonProps {\n children?: React.ReactNode;\n className?: string;\n callbackUrl?: string;\n onClick?: () => void;\n}\n\n/**\n * Sign in button component\n */\nexport function SignInButton({ \n children = 'Sign in with OAuth42', \n className = '',\n callbackUrl = '/',\n onClick\n}: SignInButtonProps) {\n const handleClick = async () => {\n if (onClick) onClick();\n await signIn('oauth42', { callbackUrl });\n };\n \n return (\n <button\n onClick={handleClick}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport interface SignOutButtonProps {\n children?: React.ReactNode;\n className?: string;\n callbackUrl?: string;\n onClick?: () => void;\n}\n\n/**\n * Sign out button component\n */\nexport function SignOutButton({ \n children = 'Sign out', \n className = '',\n callbackUrl = '/',\n onClick\n}: SignOutButtonProps) {\n const handleClick = async () => {\n if (onClick) onClick();\n await signOut({ callbackUrl });\n };\n \n return (\n <button\n onClick={handleClick}\n className={className}\n type=\"button\"\n >\n {children}\n </button>\n );\n}\n\nexport interface UserProfileProps {\n className?: string;\n showEmail?: boolean;\n showName?: boolean;\n showImage?: boolean;\n loadingComponent?: React.ReactNode;\n notAuthenticatedComponent?: React.ReactNode;\n}\n\n/**\n * User profile display component\n */\nexport function UserProfile({\n className = '',\n showEmail = true,\n showName = true,\n showImage = true,\n loadingComponent = <div>Loading...</div>,\n notAuthenticatedComponent = <div>Not authenticated</div>,\n}: UserProfileProps) {\n const { session, loading, isAuthenticated } = useOAuth42Session();\n \n if (loading) {\n return <>{loadingComponent}</>;\n }\n \n if (!isAuthenticated || !session?.user) {\n return <>{notAuthenticatedComponent}</>;\n }\n \n const { user } = session;\n \n return (\n <div className={className}>\n {showImage && user.image && (\n <img \n src={user.image} \n alt={user.name || 'User'} \n style={{ width: 50, height: 50, borderRadius: '50%' }}\n />\n )}\n {showName && user.name && <div>{user.name}</div>}\n {showEmail && user.email && <div>{user.email}</div>}\n </div>\n );\n}\n\nexport interface AuthStatusProps {\n authenticatedComponent?: React.ReactNode;\n unauthenticatedComponent?: React.ReactNode;\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * Conditional rendering based on auth status\n */\nexport function AuthStatus({\n authenticatedComponent,\n unauthenticatedComponent,\n loadingComponent = <div>Loading...</div>,\n}: AuthStatusProps) {\n const { isAuthenticated, loading } = useOAuth42Session();\n \n if (loading) {\n return <>{loadingComponent}</>;\n }\n \n return <>{isAuthenticated ? authenticatedComponent : unauthenticatedComponent}</>;\n}\n\nexport interface ProtectedComponentProps {\n children: React.ReactNode;\n fallback?: React.ReactNode;\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * Wrapper component for protected content\n */\nexport function ProtectedComponent({\n children,\n fallback = <SignInButton />,\n loadingComponent = <div>Loading...</div>,\n}: ProtectedComponentProps) {\n const { isAuthenticated, loading } = useOAuth42Session();\n \n if (loading) {\n return <>{loadingComponent}</>;\n }\n \n if (!isAuthenticated) {\n return <>{fallback}</>;\n }\n \n return <>{children}</>;\n}","/**\n * Utilities for OAuth42 Hosted Authentication\n */\n\nexport interface HostedAuthOptions {\n /** OAuth2 client ID */\n clientId: string;\n /** Redirect URI after authentication */\n redirectUri: string;\n /** OAuth2 scopes (space-separated) */\n scope?: string;\n /** OAuth2 state parameter for CSRF protection */\n state?: string;\n /** Base URL for OAuth42 issuer/API (defaults to production) */\n issuer?: string;\n}\n\n/**\n * Generate a random state parameter for CSRF protection\n */\nfunction generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');\n}\n\n/**\n * Redirect to OAuth42 hosted authentication pages\n *\n * @example\n * ```ts\n * import { redirectToHostedAuth } from '@oauth42/next/client';\n *\n * function LoginButton() {\n * return (\n * <button onClick={() => redirectToHostedAuth({\n * clientId: process.env.NEXT_PUBLIC_OAUTH42_CLIENT_ID!,\n * redirectUri: `${window.location.origin}/api/auth/callback`,\n * })}>\n * Sign in with OAuth42\n * </button>\n * );\n * }\n * ```\n */\nexport function redirectToHostedAuth(options: HostedAuthOptions): void {\n const {\n clientId,\n redirectUri,\n scope = 'openid profile email',\n state = generateState(),\n issuer = 'https://api.oauth42.com',\n } = options;\n\n const params = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: 'code',\n scope,\n state,\n });\n\n // Redirect to the backend's authorize endpoint, which handles the OAuth flow\n // and redirects to hosted auth login if user is not authenticated\n const authUrl = `${issuer}/oauth2/authorize?${params.toString()}`;\n\n // Store state in sessionStorage for verification on callback\n if (typeof window !== 'undefined') {\n sessionStorage.setItem('oauth42_state', state);\n window.location.href = authUrl;\n }\n}\n\n/**\n * Verify state parameter on OAuth2 callback\n * Call this in your callback page to verify the state matches\n *\n * @example\n * ```ts\n * import { verifyState } from '@oauth42/next/client';\n *\n * export default function CallbackPage() {\n * const searchParams = useSearchParams();\n * const state = searchParams.get('state');\n *\n * if (!verifyState(state)) {\n * return <div>Invalid state parameter</div>;\n * }\n *\n * // Continue with token exchange...\n * }\n * ```\n */\nexport function verifyState(state: string | null): boolean {\n if (typeof window === 'undefined') return false;\n if (!state) return false;\n\n const storedState = sessionStorage.getItem('oauth42_state');\n sessionStorage.removeItem('oauth42_state');\n\n return storedState === state;\n}\n\n/**\n * Configuration for hosted authentication\n */\nexport interface HostedAuthConfig {\n /** Enable hosted authentication */\n enabled: boolean;\n /** Base URL for hosted auth pages (optional, defaults to production) */\n baseUrl?: string;\n /** Feature flags for hosted auth */\n features?: {\n /** Allow user signup */\n signup?: boolean;\n /** Allow social login */\n socialLogin?: boolean;\n /** Allow password reset */\n passwordReset?: boolean;\n };\n}\n\n/**\n * Default hosted auth configuration\n */\nexport const DEFAULT_HOSTED_AUTH_CONFIG: HostedAuthConfig = {\n enabled: true,\n baseUrl: 'https://auth.oauth42.com',\n features: {\n signup: true,\n socialLogin: false,\n passwordReset: true,\n },\n};\n","/**\n * OAuth42 Custom Authentication Utilities\n *\n * Provides functions for implementing custom login UIs in customer apps\n * while properly handling OAuth2 PKCE flows and next-auth integration.\n */\n\nimport { signIn } from 'next-auth/react';\n\n// PKCE utilities\nfunction base64URLEncode(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = '';\n for (let i = 0; i < bytes.byteLength; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary)\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n}\n\nasync function generateCodeVerifier(): Promise<string> {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64URLEncode(array.buffer);\n}\n\nasync function generateCodeChallenge(verifier: string): Promise<string> {\n const encoder = new TextEncoder();\n const data = encoder.encode(verifier);\n const hash = await crypto.subtle.digest('SHA-256', data);\n return base64URLEncode(hash);\n}\n\nfunction generateState(): string {\n const array = new Uint8Array(32);\n crypto.getRandomValues(array);\n return base64URLEncode(array.buffer);\n}\n\nexport interface LoginWithPasswordOptions {\n email: string;\n password: string;\n mfaCode?: string;\n /**\n * URL to redirect to after successful authentication.\n * If not provided, will redirect to '/'\n */\n callbackUrl?: string;\n}\n\nexport interface LoginWithAuthenticatorOptions {\n email: string;\n sessionId: string;\n /**\n * URL to redirect to after successful authentication.\n * If not provided, will redirect to '/'\n */\n callbackUrl?: string;\n}\n\nexport interface AuthError {\n error: string;\n error_description?: string;\n requires_enrollment?: boolean;\n enrollment_token?: string;\n requires_mfa?: boolean;\n}\n\n/**\n * Authenticate with email/password and complete OAuth PKCE flow\n *\n * This function handles the full authentication flow:\n * 1. Authenticates with the backend using credentials\n * 2. Uses the access token to authorize the OAuth client\n * 3. Exchanges authorization code for tokens via next-auth\n *\n * @example\n * ```tsx\n * const result = await loginWithPassword({\n * email: 'user@example.com',\n * password: 'password123',\n * callbackUrl: '/dashboard'\n * });\n *\n * if (result.success) {\n * // User is authenticated, next-auth session is set\n * } else if (result.requires_mfa) {\n * // Prompt for MFA code and call again with mfaCode\n * }\n * ```\n */\nexport async function loginWithPassword(\n options: LoginWithPasswordOptions\n): Promise<{ success: boolean; access_token?: string } & Partial<AuthError>> {\n try {\n // Step 1: Authenticate with backend to get access token\n const loginResponse = await fetch('/api/auth/login', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: options.email,\n password: options.password,\n ...(options.mfaCode ? { mfa_code: options.mfaCode } : {}),\n }),\n });\n\n if (!loginResponse.ok) {\n const errorData = await loginResponse.json().catch(() => ({}));\n const desc: string = errorData?.error_description || errorData?.message || '';\n\n // Handle special cases\n if (loginResponse.status === 403 && errorData?.requires_enrollment) {\n return {\n success: false,\n error: 'enrollment_required',\n error_description: 'MFA enrollment required',\n requires_enrollment: true,\n enrollment_token: errorData.enrollment_token,\n };\n }\n\n if (loginResponse.status === 403 && /mfa required/i.test(desc)) {\n return {\n success: false,\n error: 'mfa_required',\n error_description: 'MFA code required',\n requires_mfa: true,\n };\n }\n\n if (loginResponse.status === 401 && /invalid mfa code/i.test(desc)) {\n return {\n success: false,\n error: 'invalid_mfa_code',\n error_description: 'Invalid MFA code',\n requires_mfa: true,\n };\n }\n\n return {\n success: false,\n error: 'authentication_failed',\n error_description: desc || 'Invalid credentials',\n };\n }\n\n const { access_token } = await loginResponse.json();\n\n // Return access token for the application to use in OAuth authorize flow\n return { success: true, access_token };\n } catch (error) {\n console.error('Login error:', error);\n return {\n success: false,\n error: 'network_error',\n error_description: 'Failed to connect to authentication server',\n };\n }\n}\n\n/**\n * Initiate authenticator (passwordless) login and return challenge code\n *\n * @example\n * ```tsx\n * const result = await initiateAuthenticatorLogin({\n * email: 'user@example.com',\n * sessionId: crypto.randomUUID()\n * });\n *\n * if (result.success) {\n * // Display result.challengeCode to user\n * // Wait for WebSocket approval or poll for completion\n * }\n * ```\n */\nexport async function initiateAuthenticatorLogin(\n options: LoginWithAuthenticatorOptions\n): Promise<{\n success: boolean;\n challengeCode?: string;\n challengeId?: string;\n} & Partial<AuthError>> {\n try {\n const response = await fetch('/api/auth/passwordless/initiate', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n email: options.email,\n session_id: options.sessionId,\n }),\n });\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n return {\n success: false,\n error: 'initiation_failed',\n error_description: errorData.error_description || 'Failed to create challenge',\n };\n }\n\n const data = await response.json();\n\n return {\n success: true,\n challengeCode: data.challenge_code,\n challengeId: data.challenge_id,\n };\n } catch (error) {\n console.error('Authenticator login error:', error);\n return {\n success: false,\n error: 'network_error',\n error_description: 'Failed to connect to authentication server',\n };\n }\n}\n\n/**\n * Complete authenticator login after approval\n *\n * Call this after receiving approval notification via WebSocket\n * or after the user has approved on their mobile device.\n * Returns the access token for the application to use in OAuth authorize flow.\n *\n * @param accessToken - Access token received from approval payload\n */\nexport async function completeAuthenticatorLogin(\n accessToken: string\n): Promise<{ success: boolean; access_token: string }> {\n return { success: true, access_token: accessToken };\n}\n\n/**\n * Simulate approval for testing (development only)\n *\n * @param challengeId - The challenge ID to approve\n * @param selectedCode - The code that was displayed to the user\n */\nexport async function simulateApproval(\n challengeId: string,\n selectedCode: string\n): Promise<{ success: boolean }> {\n try {\n await fetch('/api/auth/challenge/approve', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n challenge_id: challengeId,\n selected_code: selectedCode,\n }),\n });\n\n return { success: true };\n } catch (error) {\n console.error('Simulated approval failed:', error);\n return { success: false };\n }\n}\n\n/**\n * Logout the current user from the app only (app-level logout)\n *\n * This clears the next-auth session for this app AND removes the app-user\n * mapping from the session registry. On next login, the user will see\n * the account picker to choose which account to use.\n *\n * For provider-level logout (sign out of all apps), use logoutEverywhere().\n *\n * @param options.callbackUrl - URL to redirect to after logout (default: '/')\n * @param options.clientId - OAuth client ID to clear from registry\n * @param options.issuer - OAuth42 issuer URL for the logout endpoint\n *\n * @example\n * ```tsx\n * import { logout } from '@oauth42/next/client';\n *\n * const handleLogout = async () => {\n * await logout({\n * callbackUrl: '/login',\n * clientId: process.env.NEXT_PUBLIC_OAUTH42_CLIENT_ID,\n * issuer: process.env.NEXT_PUBLIC_OAUTH_ISSUER || 'https://localhost:8443'\n * });\n * };\n * ```\n */\nexport async function logout(options?: {\n callbackUrl?: string;\n clientId?: string;\n issuer?: string;\n}): Promise<void> {\n // If clientId and issuer provided, call backend to clear app_user from registry\n if (options?.clientId && options?.issuer) {\n try {\n await fetch(`${options.issuer}/oauth2/logout?client_id=${encodeURIComponent(options.clientId)}`, {\n method: 'POST',\n credentials: 'include', // Include cookies (registry cookie)\n });\n } catch (err) {\n console.warn('[OAuth42] Failed to clear app user from registry:', err);\n // Continue with NextAuth signOut even if this fails\n }\n }\n\n // Import signOut from next-auth/react\n const { signOut } = await import('next-auth/react');\n\n // Clear next-auth session (app-level only)\n await signOut({\n callbackUrl: options?.callbackUrl || '/',\n redirect: true\n });\n}\n\n/**\n * Logout the current user from ALL apps using OAuth42 (provider-level logout)\n *\n * This redirects to the OAuth42 provider's logout endpoint to clear the\n * oauth42_session cookie, effectively logging the user out of all apps.\n *\n * Use this when testing fresh login flows or when the user explicitly\n * wants to sign out of everything.\n *\n * @param issuer - The OAuth42 issuer URL (e.g., 'https://localhost:8443')\n * @param callbackUrl - URL to redirect to after logout (default: current origin)\n *\n * @example\n * ```tsx\n * import { logoutEverywhere } from '@oauth42/next/client';\n *\n * const handleLogoutEverywhere = () => {\n * const issuer = process.env.NEXT_PUBLIC_OAUTH42_ISSUER || 'https://localhost:8443';\n * logoutEverywhere(issuer, '/auth/signin');\n * };\n * ```\n */\nexport function logoutEverywhere(issuer: string, callbackUrl?: string): void {\n const redirectUri = callbackUrl || window.location.origin;\n\n // Redirect to OAuth42 provider logout endpoint\n // This clears the oauth42_session cookie and redirects back\n window.location.href = `${issuer}/auth/logout?redirect_uri=${encodeURIComponent(redirectUri)}`;\n}\n"],"mappings":"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","names":["signIn","signOut","useSession","signIn","signOut","signIn","signOut","signOut"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { C as CreateAuthOptions,
|
|
1
|
+
export { C as CreateAuthOptions, a as OAuth42Profile, O as OAuth42Provider, b as OAuth42ProviderOptions, c as createAuth, d as getOAuth42Session, g as getServerSession, r as refreshAccessToken, e as withOAuth42ServerSideProps, w as withOAuth42Session } from './auth-ClOnIcCK.mjs';
|
|
2
|
+
export { OAuth42AuthOptions, createMiddlewareConfig, withOAuth42Auth } from './middleware/index.mjs';
|
|
2
3
|
import { DefaultSession } from 'next-auth';
|
|
3
4
|
export { Session, User } from 'next-auth';
|
|
4
5
|
import 'next-auth/providers/oauth';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
export { C as CreateAuthOptions,
|
|
1
|
+
export { C as CreateAuthOptions, a as OAuth42Profile, O as OAuth42Provider, b as OAuth42ProviderOptions, c as createAuth, d as getOAuth42Session, g as getServerSession, r as refreshAccessToken, e as withOAuth42ServerSideProps, w as withOAuth42Session } from './auth-ClOnIcCK.js';
|
|
2
|
+
export { OAuth42AuthOptions, createMiddlewareConfig, withOAuth42Auth } from './middleware/index.js';
|
|
2
3
|
import { DefaultSession } from 'next-auth';
|
|
3
4
|
export { Session, User } from 'next-auth';
|
|
4
5
|
import 'next-auth/providers/oauth';
|
package/dist/index.js
CHANGED
|
@@ -95,8 +95,32 @@ var import_next_auth2 = __toESM(require("next-auth"));
|
|
|
95
95
|
|
|
96
96
|
// src/server/session.ts
|
|
97
97
|
var import_next_auth = require("next-auth");
|
|
98
|
+
var import_headers = require("next/headers");
|
|
99
|
+
var REFRESHED_TOKEN_HEADER = "x-oauth42-refreshed-token";
|
|
98
100
|
async function getOAuth42Session(...args) {
|
|
99
|
-
|
|
101
|
+
const session = await (0, import_next_auth.getServerSession)(...args);
|
|
102
|
+
if (!session) {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
let refreshedToken = null;
|
|
106
|
+
try {
|
|
107
|
+
if (args.length === 1) {
|
|
108
|
+
const headersList = await (0, import_headers.headers)();
|
|
109
|
+
refreshedToken = headersList.get(REFRESHED_TOKEN_HEADER);
|
|
110
|
+
} else if (args.length === 3) {
|
|
111
|
+
const req = args[0];
|
|
112
|
+
refreshedToken = req.headers[REFRESHED_TOKEN_HEADER] || null;
|
|
113
|
+
}
|
|
114
|
+
} catch {
|
|
115
|
+
}
|
|
116
|
+
if (refreshedToken) {
|
|
117
|
+
console.log("[OAuth42 Session] Using refreshed token from middleware");
|
|
118
|
+
return {
|
|
119
|
+
...session,
|
|
120
|
+
accessToken: refreshedToken
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return session;
|
|
100
124
|
}
|
|
101
125
|
function withOAuth42Session(handler, authOptions) {
|
|
102
126
|
return async (req, res) => {
|
|
@@ -128,6 +152,7 @@ function withOAuth42ServerSideProps(getServerSideProps, authOptions) {
|
|
|
128
152
|
|
|
129
153
|
// src/server/auth.ts
|
|
130
154
|
var NextAuth = import_next_auth2.default.default || import_next_auth2.default;
|
|
155
|
+
var activeRefresh = null;
|
|
131
156
|
function createAuth(options = {}) {
|
|
132
157
|
const clientId = options.clientId || process.env.OAUTH42_CLIENT_ID;
|
|
133
158
|
const clientSecret = options.clientSecret || process.env.OAUTH42_CLIENT_SECRET;
|
|
@@ -148,11 +173,16 @@ function createAuth(options = {}) {
|
|
|
148
173
|
],
|
|
149
174
|
callbacks: {
|
|
150
175
|
async jwt({ token, account, profile }) {
|
|
176
|
+
console.log("[OAuth42 SDK] JWT callback called", { hasAccount: !!account, hasProfile: !!profile });
|
|
151
177
|
if (account) {
|
|
178
|
+
console.log("[OAuth42 SDK] Initial sign in - storing tokens in JWT");
|
|
152
179
|
token.accessToken = account.access_token;
|
|
153
180
|
token.refreshToken = account.refresh_token;
|
|
154
181
|
token.expiresAt = account.expires_at;
|
|
155
182
|
token.idToken = account.id_token;
|
|
183
|
+
token.clientId = clientId;
|
|
184
|
+
token.clientSecret = clientSecret;
|
|
185
|
+
token.issuer = options.issuer || process.env.NEXT_PUBLIC_OAUTH_ISSUER || process.env.OAUTH42_ISSUER;
|
|
156
186
|
}
|
|
157
187
|
if (profile) {
|
|
158
188
|
const oauth42Profile = profile;
|
|
@@ -163,11 +193,16 @@ function createAuth(options = {}) {
|
|
|
163
193
|
if (options.callbacks?.jwt) {
|
|
164
194
|
return options.callbacks.jwt({ token, account, profile });
|
|
165
195
|
}
|
|
196
|
+
console.log("[OAuth42 SDK] JWT callback complete, returning token");
|
|
166
197
|
return token;
|
|
167
198
|
},
|
|
168
199
|
async session({ session, token }) {
|
|
200
|
+
console.log("[OAuth42 SDK] Session callback called", { hasToken: !!token, hasSession: !!session });
|
|
169
201
|
session.accessToken = token.accessToken;
|
|
170
202
|
session.idToken = token.idToken;
|
|
203
|
+
if (token.error) {
|
|
204
|
+
session.error = token.error;
|
|
205
|
+
}
|
|
171
206
|
if (session.user) {
|
|
172
207
|
session.user.email = token.email;
|
|
173
208
|
session.user.name = token.name;
|
|
@@ -177,9 +212,9 @@ function createAuth(options = {}) {
|
|
|
177
212
|
if (options.callbacks?.session) {
|
|
178
213
|
return options.callbacks.session({ session, token });
|
|
179
214
|
}
|
|
215
|
+
console.log("[OAuth42 SDK] Session callback complete, returning session");
|
|
180
216
|
return session;
|
|
181
|
-
}
|
|
182
|
-
...options.callbacks
|
|
217
|
+
}
|
|
183
218
|
},
|
|
184
219
|
pages: {
|
|
185
220
|
signIn: "/auth/signin",
|
|
@@ -192,15 +227,94 @@ function createAuth(options = {}) {
|
|
|
192
227
|
...options.session
|
|
193
228
|
},
|
|
194
229
|
debug: options.debug || process.env.NODE_ENV === "development",
|
|
195
|
-
secret: process.env.NEXTAUTH_SECRET
|
|
230
|
+
secret: process.env.NEXTAUTH_SECRET,
|
|
231
|
+
// Configure unique cookie names per app to prevent session conflicts on localhost
|
|
232
|
+
...options.cookiePrefix && {
|
|
233
|
+
cookies: {
|
|
234
|
+
sessionToken: {
|
|
235
|
+
name: `${options.cookiePrefix}.session-token`,
|
|
236
|
+
options: {
|
|
237
|
+
httpOnly: true,
|
|
238
|
+
sameSite: "lax",
|
|
239
|
+
path: "/",
|
|
240
|
+
secure: process.env.NODE_ENV === "production"
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
callbackUrl: {
|
|
244
|
+
name: `${options.cookiePrefix}.callback-url`,
|
|
245
|
+
options: {
|
|
246
|
+
httpOnly: true,
|
|
247
|
+
sameSite: "lax",
|
|
248
|
+
path: "/",
|
|
249
|
+
secure: process.env.NODE_ENV === "production"
|
|
250
|
+
}
|
|
251
|
+
},
|
|
252
|
+
csrfToken: {
|
|
253
|
+
name: `${options.cookiePrefix}.csrf-token`,
|
|
254
|
+
options: {
|
|
255
|
+
httpOnly: true,
|
|
256
|
+
sameSite: "lax",
|
|
257
|
+
path: "/",
|
|
258
|
+
secure: process.env.NODE_ENV === "production"
|
|
259
|
+
}
|
|
260
|
+
},
|
|
261
|
+
// PKCE code_verifier cookie - essential for PKCE flow
|
|
262
|
+
pkceCodeVerifier: {
|
|
263
|
+
name: `${options.cookiePrefix}.pkce.code_verifier`,
|
|
264
|
+
options: {
|
|
265
|
+
httpOnly: true,
|
|
266
|
+
sameSite: "lax",
|
|
267
|
+
path: "/",
|
|
268
|
+
secure: process.env.NODE_ENV === "production",
|
|
269
|
+
maxAge: 900
|
|
270
|
+
// 15 minutes
|
|
271
|
+
}
|
|
272
|
+
},
|
|
273
|
+
// State cookie for OAuth CSRF protection
|
|
274
|
+
state: {
|
|
275
|
+
name: `${options.cookiePrefix}.state`,
|
|
276
|
+
options: {
|
|
277
|
+
httpOnly: true,
|
|
278
|
+
sameSite: "lax",
|
|
279
|
+
path: "/",
|
|
280
|
+
secure: process.env.NODE_ENV === "production",
|
|
281
|
+
maxAge: 900
|
|
282
|
+
// 15 minutes
|
|
283
|
+
}
|
|
284
|
+
},
|
|
285
|
+
// Nonce cookie for OpenID Connect
|
|
286
|
+
nonce: {
|
|
287
|
+
name: `${options.cookiePrefix}.nonce`,
|
|
288
|
+
options: {
|
|
289
|
+
httpOnly: true,
|
|
290
|
+
sameSite: "lax",
|
|
291
|
+
path: "/",
|
|
292
|
+
secure: process.env.NODE_ENV === "production"
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
196
297
|
};
|
|
298
|
+
const handler = NextAuth(authOptions);
|
|
197
299
|
return {
|
|
198
300
|
auth: authOptions,
|
|
199
|
-
handlers:
|
|
301
|
+
handlers: { GET: handler, POST: handler }
|
|
200
302
|
};
|
|
201
303
|
}
|
|
202
304
|
var getServerSession = getOAuth42Session;
|
|
203
305
|
async function refreshAccessToken(token, clientId, clientSecret, issuer) {
|
|
306
|
+
if (activeRefresh) {
|
|
307
|
+
console.log("[OAuth42] Refresh already in progress, waiting...");
|
|
308
|
+
return await activeRefresh;
|
|
309
|
+
}
|
|
310
|
+
activeRefresh = doRefresh(token, clientId, clientSecret, issuer);
|
|
311
|
+
try {
|
|
312
|
+
return await activeRefresh;
|
|
313
|
+
} finally {
|
|
314
|
+
activeRefresh = null;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
async function doRefresh(token, clientId, clientSecret, issuer) {
|
|
204
318
|
try {
|
|
205
319
|
const baseUrl = issuer || process.env.OAUTH42_ISSUER || "https://oauth42.com";
|
|
206
320
|
const tokenUrl = `${baseUrl}/oauth2/token`;
|
|
@@ -227,6 +341,7 @@ async function refreshAccessToken(token, clientId, clientSecret, issuer) {
|
|
|
227
341
|
if (!response.ok) {
|
|
228
342
|
throw refreshedTokens;
|
|
229
343
|
}
|
|
344
|
+
console.log("[OAuth42] Token refreshed successfully");
|
|
230
345
|
return {
|
|
231
346
|
...token,
|
|
232
347
|
accessToken: refreshedTokens.access_token,
|
|
@@ -237,7 +352,7 @@ async function refreshAccessToken(token, clientId, clientSecret, issuer) {
|
|
|
237
352
|
error: void 0
|
|
238
353
|
};
|
|
239
354
|
} catch (error) {
|
|
240
|
-
console.error("Failed to refresh access token:", error);
|
|
355
|
+
console.error("[OAuth42] Failed to refresh access token:", error);
|
|
241
356
|
return {
|
|
242
357
|
...token,
|
|
243
358
|
error: "RefreshAccessTokenError"
|
|
@@ -248,11 +363,52 @@ async function refreshAccessToken(token, clientId, clientSecret, issuer) {
|
|
|
248
363
|
// src/server/middleware.ts
|
|
249
364
|
var import_server = require("next/server");
|
|
250
365
|
var import_jwt = require("next-auth/jwt");
|
|
366
|
+
async function refreshTokens(refreshToken, clientId, clientSecret, issuer) {
|
|
367
|
+
try {
|
|
368
|
+
const tokenUrl = `${issuer}/oauth2/token`;
|
|
369
|
+
const response = await fetch(tokenUrl, {
|
|
370
|
+
method: "POST",
|
|
371
|
+
headers: {
|
|
372
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
373
|
+
},
|
|
374
|
+
body: new URLSearchParams({
|
|
375
|
+
grant_type: "refresh_token",
|
|
376
|
+
refresh_token: refreshToken,
|
|
377
|
+
client_id: clientId,
|
|
378
|
+
client_secret: clientSecret
|
|
379
|
+
})
|
|
380
|
+
});
|
|
381
|
+
const data = await response.json();
|
|
382
|
+
if (!response.ok) {
|
|
383
|
+
console.error("[OAuth42 Middleware] Token refresh failed:", data);
|
|
384
|
+
return { success: false, error: data.error || "refresh_failed" };
|
|
385
|
+
}
|
|
386
|
+
console.log("[OAuth42 Middleware] Token refreshed successfully");
|
|
387
|
+
return {
|
|
388
|
+
success: true,
|
|
389
|
+
accessToken: data.access_token,
|
|
390
|
+
refreshToken: data.refresh_token,
|
|
391
|
+
expiresAt: Math.floor(Date.now() / 1e3) + (data.expires_in || 3600)
|
|
392
|
+
};
|
|
393
|
+
} catch (error) {
|
|
394
|
+
console.error("[OAuth42 Middleware] Token refresh error:", error);
|
|
395
|
+
return { success: false, error: "refresh_error" };
|
|
396
|
+
}
|
|
397
|
+
}
|
|
251
398
|
function withOAuth42Auth(options = {}) {
|
|
399
|
+
const secret = process.env.NEXTAUTH_SECRET;
|
|
400
|
+
const clientId = process.env.OAUTH42_CLIENT_ID;
|
|
401
|
+
const clientSecret = process.env.OAUTH42_CLIENT_SECRET;
|
|
402
|
+
const issuer = process.env.OAUTH42_ISSUER || "https://localhost:8443";
|
|
403
|
+
if (!secret) {
|
|
404
|
+
console.warn("[OAuth42 Middleware] NEXTAUTH_SECRET not set");
|
|
405
|
+
}
|
|
252
406
|
return async function middleware(req) {
|
|
407
|
+
const cookieName = options.cookiePrefix ? `${options.cookiePrefix}.session-token` : "next-auth.session-token";
|
|
253
408
|
const token = await (0, import_jwt.getToken)({
|
|
254
409
|
req,
|
|
255
|
-
secret
|
|
410
|
+
secret,
|
|
411
|
+
cookieName
|
|
256
412
|
});
|
|
257
413
|
const pathname = req.nextUrl.pathname;
|
|
258
414
|
if (options.publicPaths?.some((path) => pathname.startsWith(path))) {
|
|
@@ -262,16 +418,68 @@ function withOAuth42Auth(options = {}) {
|
|
|
262
418
|
if (!needsProtection) {
|
|
263
419
|
return import_server.NextResponse.next();
|
|
264
420
|
}
|
|
265
|
-
|
|
266
|
-
if (options.callbacks?.authorized) {
|
|
267
|
-
isAuthorized = await options.callbacks.authorized({ token, req });
|
|
268
|
-
}
|
|
269
|
-
if (!isAuthorized) {
|
|
421
|
+
if (!token) {
|
|
270
422
|
const signInUrl = options.pages?.signIn || "/auth/signin";
|
|
271
423
|
const url = new URL(signInUrl, req.url);
|
|
272
424
|
url.searchParams.set("callbackUrl", pathname);
|
|
273
425
|
return import_server.NextResponse.redirect(url);
|
|
274
426
|
}
|
|
427
|
+
const expiresAt = token.expiresAt;
|
|
428
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
429
|
+
const bufferSeconds = 60;
|
|
430
|
+
const needsRefresh = expiresAt && now >= expiresAt - bufferSeconds;
|
|
431
|
+
if (needsRefresh && token.refreshToken && clientId && clientSecret) {
|
|
432
|
+
console.log("[OAuth42 Middleware] Access token expired, refreshing...");
|
|
433
|
+
const refreshed = await refreshTokens(
|
|
434
|
+
token.refreshToken,
|
|
435
|
+
clientId,
|
|
436
|
+
clientSecret,
|
|
437
|
+
issuer
|
|
438
|
+
);
|
|
439
|
+
if (refreshed.success && refreshed.accessToken && refreshed.refreshToken) {
|
|
440
|
+
const updatedToken = {
|
|
441
|
+
...token,
|
|
442
|
+
accessToken: refreshed.accessToken,
|
|
443
|
+
refreshToken: refreshed.refreshToken,
|
|
444
|
+
expiresAt: refreshed.expiresAt
|
|
445
|
+
};
|
|
446
|
+
const newJwt = await (0, import_jwt.encode)({
|
|
447
|
+
token: updatedToken,
|
|
448
|
+
secret
|
|
449
|
+
});
|
|
450
|
+
const requestHeaders = new Headers(req.headers);
|
|
451
|
+
requestHeaders.set("x-oauth42-refreshed-token", refreshed.accessToken);
|
|
452
|
+
const response = import_server.NextResponse.next({
|
|
453
|
+
request: {
|
|
454
|
+
headers: requestHeaders
|
|
455
|
+
}
|
|
456
|
+
});
|
|
457
|
+
response.cookies.set(cookieName, newJwt, {
|
|
458
|
+
httpOnly: true,
|
|
459
|
+
sameSite: "lax",
|
|
460
|
+
path: "/",
|
|
461
|
+
secure: process.env.NODE_ENV === "production"
|
|
462
|
+
});
|
|
463
|
+
console.log("[OAuth42 Middleware] Cookie updated with refreshed tokens, header set for current request");
|
|
464
|
+
return response;
|
|
465
|
+
} else {
|
|
466
|
+
console.error("[OAuth42 Middleware] Refresh failed, redirecting to sign in");
|
|
467
|
+
const signInUrl = options.pages?.signIn || "/auth/signin";
|
|
468
|
+
const url = new URL(signInUrl, req.url);
|
|
469
|
+
url.searchParams.set("callbackUrl", pathname);
|
|
470
|
+
url.searchParams.set("error", "RefreshAccessTokenError");
|
|
471
|
+
return import_server.NextResponse.redirect(url);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
if (options.callbacks?.authorized) {
|
|
475
|
+
const isAuthorized = await options.callbacks.authorized({ token, req });
|
|
476
|
+
if (!isAuthorized) {
|
|
477
|
+
const signInUrl = options.pages?.signIn || "/auth/signin";
|
|
478
|
+
const url = new URL(signInUrl, req.url);
|
|
479
|
+
url.searchParams.set("callbackUrl", pathname);
|
|
480
|
+
return import_server.NextResponse.redirect(url);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
275
483
|
return import_server.NextResponse.next();
|
|
276
484
|
};
|
|
277
485
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/provider.ts","../src/server/auth.ts","../src/server/session.ts","../src/server/middleware.ts"],"sourcesContent":["// Main exports\nexport { OAuth42Provider } from './provider';\nexport type { OAuth42Profile, OAuth42ProviderOptions } from './provider';\n\n// Server-side exports\nexport { createAuth, getServerSession, refreshAccessToken } from './server/auth';\nexport type { CreateAuthOptions } from './server/auth';\n\nexport { withOAuth42Auth, createMiddlewareConfig } from './server/middleware';\nexport type { OAuth42AuthOptions } from './server/middleware';\n\nexport { getOAuth42Session, withOAuth42Session, withOAuth42ServerSideProps } from './server/session';\n\n// Type exports\nexport type { OAuth42Config } from './types';\n\n// Re-export NextAuth types for convenience\nexport type { Session, User } from 'next-auth';","import type { OAuthConfig, OAuthUserConfig } from 'next-auth/providers/oauth';\n\nexport interface OAuth42Profile {\n sub: string;\n email: string;\n email_verified?: boolean;\n name?: string;\n given_name?: string;\n family_name?: string;\n picture?: string;\n username?: string;\n id?: string;\n}\n\nexport interface OAuth42ProviderOptions {\n clientId: string;\n clientSecret: string;\n issuer?: string;\n authorizationUrl?: string;\n tokenUrl?: string;\n userinfoUrl?: string;\n scopes?: string[];\n pkceEnabled?: boolean;\n}\n\nexport function OAuth42Provider<P extends OAuth42Profile>(\n options: OAuthUserConfig<P> & Partial<OAuth42ProviderOptions>\n): OAuthConfig<P> {\n const issuer = options.issuer || process.env.OAUTH42_ISSUER || 'https://oauth42.com';\n const baseUrl = issuer.replace(/\\/$/, '');\n \n return {\n id: 'oauth42',\n name: 'OAuth42',\n type: 'oauth',\n version: '2.0',\n \n // Use OIDC discovery to automatically find endpoints\n wellKnown: `${baseUrl}/.well-known/openid-configuration`,\n \n // Also set individual endpoints for compatibility\n authorization: {\n url: `${baseUrl}/oauth2/authorize`,\n params: {\n scope: (options.scopes || ['openid', 'profile', 'email']).join(' '),\n response_type: 'code',\n },\n },\n token: `${baseUrl}/oauth2/token`,\n userinfo: `${baseUrl}/oauth2/userinfo`,\n \n client: {\n id: options.clientId,\n secret: options.clientSecret,\n token_endpoint_auth_method: 'client_secret_post',\n id_token_signed_response_alg: 'HS256', // OAuth42 uses HS256 for ID tokens\n },\n \n issuer: baseUrl,\n \n checks: options.pkceEnabled !== false ? ['pkce', 'state'] : ['state'],\n \n profile(profile: OAuth42Profile, tokens: any) {\n return {\n id: profile.sub || profile.id || profile.email,\n email: profile.email,\n emailVerified: profile.email_verified ? new Date() : null,\n name: profile.name || `${profile.given_name || ''} ${profile.family_name || ''}`.trim(),\n image: profile.picture,\n };\n },\n \n style: {\n logo: '/oauth42-logo.svg',\n bg: '#1e40af',\n text: '#ffffff',\n },\n \n options,\n };\n}","import NextAuthDefault from 'next-auth';\nimport type { NextAuthOptions } from 'next-auth';\nimport { OAuth42Provider, OAuth42Profile } from '../provider';\nimport { getOAuth42Session } from './session';\n\n// Handle both CommonJS and ESM exports\nconst NextAuth = (NextAuthDefault as any).default || NextAuthDefault;\n\nexport { type NextAuthOptions };\n\nexport interface CreateAuthOptions {\n clientId?: string;\n clientSecret?: string;\n issuer?: string;\n scopes?: string[];\n pkceEnabled?: boolean;\n debug?: boolean;\n callbacks?: NextAuthOptions['callbacks'];\n pages?: NextAuthOptions['pages'];\n session?: NextAuthOptions['session'];\n}\n\n/**\n * Create a pre-configured NextAuth instance for OAuth42\n * This provides a simplified setup with sensible defaults\n */\nexport function createAuth(options: CreateAuthOptions = {}) {\n const clientId = options.clientId || process.env.OAUTH42_CLIENT_ID;\n const clientSecret = options.clientSecret || process.env.OAUTH42_CLIENT_SECRET;\n \n if (!clientId || !clientSecret) {\n throw new Error(\n 'OAuth42 client credentials are required. ' +\n 'Set OAUTH42_CLIENT_ID and OAUTH42_CLIENT_SECRET environment variables ' +\n 'or pass them in the options.'\n );\n }\n \n const authOptions: NextAuthOptions = {\n providers: [\n OAuth42Provider({\n clientId,\n clientSecret,\n issuer: options.issuer,\n scopes: options.scopes,\n pkceEnabled: options.pkceEnabled,\n }),\n ],\n \n callbacks: {\n async jwt({ token, account, profile }) {\n // Store OAuth tokens in the JWT\n if (account) {\n token.accessToken = account.access_token;\n token.refreshToken = account.refresh_token;\n token.expiresAt = account.expires_at;\n token.idToken = account.id_token;\n }\n \n // Add user profile data\n if (profile) {\n const oauth42Profile = profile as OAuth42Profile;\n token.email = oauth42Profile.email;\n token.username = oauth42Profile.username;\n token.emailVerified = oauth42Profile.email_verified;\n }\n \n // Call custom callback if provided\n if (options.callbacks?.jwt) {\n return options.callbacks.jwt({ token, account, profile } as any);\n }\n \n return token;\n },\n \n async session({ session, token }) {\n // Add OAuth42-specific data to session\n session.accessToken = token.accessToken as string;\n session.idToken = token.idToken as string;\n\n if (session.user) {\n session.user.email = token.email as string;\n session.user.name = token.name as string;\n session.user.username = token.username as string;\n session.user.emailVerified = token.emailVerified as boolean;\n }\n\n // Call custom callback if provided\n if (options.callbacks?.session) {\n return options.callbacks.session({ session, token } as any);\n }\n\n return session;\n },\n \n ...options.callbacks,\n },\n \n pages: {\n signIn: '/auth/signin',\n signOut: '/auth/signout',\n error: '/auth/error',\n ...options.pages,\n },\n \n session: {\n strategy: 'jwt',\n ...options.session,\n },\n \n debug: options.debug || process.env.NODE_ENV === 'development',\n \n secret: process.env.NEXTAUTH_SECRET,\n };\n \n // Return the configuration and a function to create handlers\n return {\n auth: authOptions,\n handlers: NextAuth(authOptions),\n };\n}\n\n/**\n * Create NextAuth handlers for API routes\n */\nexport function createHandlers(authOptions: NextAuthOptions) {\n const handler = NextAuth(authOptions);\n return { GET: handler, POST: handler };\n}\n\n/**\n * Helper to get the current session server-side\n * @deprecated Use getOAuth42Session instead - this is now just an alias for backward compatibility\n * \n * This function is maintained for backward compatibility but internally\n * calls getOAuth42Session which properly handles both App Router and Pages Router\n */\nexport const getServerSession = getOAuth42Session;\n\n/**\n * Token refresh helper\n */\nexport async function refreshAccessToken(token: any, clientId: string, clientSecret: string, issuer?: string) {\n try {\n const baseUrl = issuer || process.env.OAUTH42_ISSUER || 'https://oauth42.com';\n const tokenUrl = `${baseUrl}/oauth2/token`;\n \n // In development, we need to handle self-signed certificates\n const fetchOptions: any = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: token.refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n }),\n };\n \n // Add agent for self-signed certificates in development\n if (process.env.NODE_ENV !== 'production' && tokenUrl.startsWith('https://')) {\n const https = await import('https');\n fetchOptions.agent = new https.Agent({\n rejectUnauthorized: false\n });\n }\n \n const response = await fetch(tokenUrl, fetchOptions);\n const refreshedTokens = await response.json();\n \n if (!response.ok) {\n throw refreshedTokens;\n }\n \n return {\n ...token,\n accessToken: refreshedTokens.access_token,\n refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,\n // Store expiration time in seconds (Unix timestamp)\n expiresAt: Math.floor(Date.now() / 1000) + (refreshedTokens.expires_in || 3600),\n // Explicitly remove any error property on successful refresh\n error: undefined,\n };\n } catch (error) {\n console.error('Failed to refresh access token:', error);\n return {\n ...token,\n error: 'RefreshAccessTokenError',\n };\n }\n}","import { getServerSession as getNextAuthSession } from 'next-auth';\nimport { NextAuthOptions } from 'next-auth';\nimport { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next';\n\n/**\n * Get the OAuth42 session server-side\n * \n * This is the primary method for retrieving sessions in OAuth42 SDK.\n * Supports both Pages Router and App Router:\n * \n * App Router:\n * ```ts\n * const session = await getOAuth42Session(authOptions);\n * ```\n * \n * Pages Router:\n * ```ts\n * const session = await getOAuth42Session(req, res, authOptions);\n * ```\n */\nexport async function getOAuth42Session(\n ...args: \n | [GetServerSidePropsContext['req'], GetServerSidePropsContext['res'], NextAuthOptions]\n | [NextApiRequest, NextApiResponse, NextAuthOptions]\n | [NextAuthOptions]\n) {\n return getNextAuthSession(...args as any);\n}\n\n/**\n * Helper for protecting API routes\n */\nexport function withOAuth42Session(\n handler: (req: NextApiRequest, res: NextApiResponse, session: any) => Promise<void> | void,\n authOptions: NextAuthOptions\n) {\n return async (req: NextApiRequest, res: NextApiResponse) => {\n const session = await getOAuth42Session(req, res, authOptions);\n \n if (!session) {\n return res.status(401).json({ error: 'Unauthorized' });\n }\n \n return handler(req, res, session);\n };\n}\n\n/**\n * Helper for protecting server-side props\n */\nexport function withOAuth42ServerSideProps(\n getServerSideProps: (\n context: GetServerSidePropsContext,\n session: any\n ) => Promise<any>,\n authOptions: NextAuthOptions\n) {\n return async (context: GetServerSidePropsContext) => {\n const session = await getOAuth42Session(\n context.req,\n context.res,\n authOptions\n );\n \n if (!session) {\n return {\n redirect: {\n destination: '/auth/signin',\n permanent: false,\n },\n };\n }\n \n return getServerSideProps(context, session);\n };\n}","import { NextRequest, NextResponse } from 'next/server';\nimport { getToken } from 'next-auth/jwt';\n\nexport interface OAuth42AuthOptions {\n pages?: {\n signIn?: string;\n error?: string;\n };\n callbacks?: {\n authorized?: (params: { token: any; req: NextRequest }) => boolean | Promise<boolean>;\n };\n protectedPaths?: string[];\n publicPaths?: string[];\n}\n\n/**\n * Middleware helper for protecting routes with OAuth42\n */\nexport function withOAuth42Auth(options: OAuth42AuthOptions = {}) {\n return async function middleware(req: NextRequest) {\n const token = await getToken({ \n req: req as any, \n secret: process.env.NEXTAUTH_SECRET \n });\n \n const pathname = req.nextUrl.pathname;\n \n // Check if path is explicitly public\n if (options.publicPaths?.some(path => pathname.startsWith(path))) {\n return NextResponse.next();\n }\n \n // Check if path needs protection\n const needsProtection = options.protectedPaths\n ? options.protectedPaths.some(path => pathname.startsWith(path))\n : true; // Default to protecting all paths\n \n if (!needsProtection) {\n return NextResponse.next();\n }\n \n // Check authorization\n let isAuthorized = !!token;\n \n if (options.callbacks?.authorized) {\n isAuthorized = await options.callbacks.authorized({ token, req });\n }\n \n if (!isAuthorized) {\n const signInUrl = options.pages?.signIn || '/auth/signin';\n const url = new URL(signInUrl, req.url);\n url.searchParams.set('callbackUrl', pathname);\n return NextResponse.redirect(url);\n }\n \n return NextResponse.next();\n };\n}\n\n/**\n * Helper to create middleware configuration\n */\nexport function createMiddlewareConfig(\n protectedPaths: string[] = ['/protected'],\n publicPaths: string[] = ['/auth', '/api/auth']\n) {\n return {\n matcher: [\n /*\n * Match all request paths except for the ones starting with:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - public folder\n */\n '/((?!_next/static|_next/image|favicon.ico|public).*)',\n ],\n protectedPaths,\n publicPaths,\n };\n}"],"mappings":"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","names":["import_next_auth","getNextAuthSession","NextAuthDefault"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider.ts","../src/server/auth.ts","../src/server/session.ts","../src/server/middleware.ts"],"sourcesContent":["// Main exports\nexport { OAuth42Provider } from './provider';\nexport type { OAuth42Profile, OAuth42ProviderOptions } from './provider';\n\n// Server-side exports\nexport { createAuth, getServerSession, refreshAccessToken } from './server/auth';\nexport type { CreateAuthOptions } from './server/auth';\n\nexport { withOAuth42Auth, createMiddlewareConfig } from './server/middleware';\nexport type { OAuth42AuthOptions } from './server/middleware';\n\nexport { getOAuth42Session, withOAuth42Session, withOAuth42ServerSideProps } from './server/session';\n\n// Type exports\nexport type { OAuth42Config } from './types';\n\n// Re-export NextAuth types for convenience\nexport type { Session, User } from 'next-auth';","import type { OAuthConfig, OAuthUserConfig } from 'next-auth/providers/oauth';\n\nexport interface OAuth42Profile {\n sub: string;\n email: string;\n email_verified?: boolean;\n name?: string;\n given_name?: string;\n family_name?: string;\n picture?: string;\n username?: string;\n id?: string;\n}\n\nexport interface OAuth42ProviderOptions {\n clientId: string;\n clientSecret: string;\n issuer?: string;\n authorizationUrl?: string;\n tokenUrl?: string;\n userinfoUrl?: string;\n scopes?: string[];\n pkceEnabled?: boolean;\n}\n\nexport function OAuth42Provider<P extends OAuth42Profile>(\n options: OAuthUserConfig<P> & Partial<OAuth42ProviderOptions>\n): OAuthConfig<P> {\n const issuer = options.issuer || process.env.OAUTH42_ISSUER || 'https://oauth42.com';\n const baseUrl = issuer.replace(/\\/$/, '');\n \n return {\n id: 'oauth42',\n name: 'OAuth42',\n type: 'oauth',\n version: '2.0',\n \n // Use OIDC discovery to automatically find endpoints\n wellKnown: `${baseUrl}/.well-known/openid-configuration`,\n \n // Also set individual endpoints for compatibility\n authorization: {\n url: `${baseUrl}/oauth2/authorize`,\n params: {\n scope: (options.scopes || ['openid', 'profile', 'email']).join(' '),\n response_type: 'code',\n },\n },\n token: `${baseUrl}/oauth2/token`,\n userinfo: `${baseUrl}/oauth2/userinfo`,\n \n client: {\n id: options.clientId,\n secret: options.clientSecret,\n token_endpoint_auth_method: 'client_secret_post',\n id_token_signed_response_alg: 'HS256', // OAuth42 uses HS256 for ID tokens\n },\n \n issuer: baseUrl,\n \n checks: options.pkceEnabled !== false ? ['pkce', 'state'] : ['state'],\n \n profile(profile: OAuth42Profile, tokens: any) {\n return {\n id: profile.sub || profile.id || profile.email,\n email: profile.email,\n emailVerified: profile.email_verified ? new Date() : null,\n name: profile.name || `${profile.given_name || ''} ${profile.family_name || ''}`.trim(),\n image: profile.picture,\n };\n },\n \n style: {\n logo: '/oauth42-logo.svg',\n bg: '#1e40af',\n text: '#ffffff',\n },\n \n options,\n };\n}","import NextAuthDefault from 'next-auth';\nimport type { NextAuthOptions } from 'next-auth';\nimport { OAuth42Provider, OAuth42Profile } from '../provider';\nimport { getOAuth42Session } from './session';\n\n// Handle both CommonJS and ESM exports\nconst NextAuth = (NextAuthDefault as any).default || NextAuthDefault;\n\nexport { type NextAuthOptions };\n\n// Simple per-process lock for explicit refresh via getAccessToken()\nlet activeRefresh: Promise<any> | null = null;\n\nexport interface CreateAuthOptions {\n clientId?: string;\n clientSecret?: string;\n issuer?: string;\n scopes?: string[];\n pkceEnabled?: boolean;\n debug?: boolean;\n callbacks?: NextAuthOptions['callbacks'];\n pages?: NextAuthOptions['pages'];\n session?: NextAuthOptions['session'];\n /**\n * Unique prefix for cookie names to allow multiple apps on the same domain.\n * Each app should use a different prefix (e.g., 'portal', 'admin', 'bond').\n * This prevents session cookie conflicts when running multiple apps on localhost.\n */\n cookiePrefix?: string;\n}\n\n/**\n * Create a pre-configured NextAuth instance for OAuth42\n * This provides a simplified setup with sensible defaults\n */\nexport function createAuth(options: CreateAuthOptions = {}) {\n const clientId = options.clientId || process.env.OAUTH42_CLIENT_ID;\n const clientSecret = options.clientSecret || process.env.OAUTH42_CLIENT_SECRET;\n \n if (!clientId || !clientSecret) {\n throw new Error(\n 'OAuth42 client credentials are required. ' +\n 'Set OAUTH42_CLIENT_ID and OAUTH42_CLIENT_SECRET environment variables ' +\n 'or pass them in the options.'\n );\n }\n \n const authOptions: NextAuthOptions = {\n providers: [\n OAuth42Provider({\n clientId,\n clientSecret,\n issuer: options.issuer,\n scopes: options.scopes,\n pkceEnabled: options.pkceEnabled,\n }),\n ],\n \n callbacks: {\n async jwt({ token, account, profile }) {\n console.log('[OAuth42 SDK] JWT callback called', { hasAccount: !!account, hasProfile: !!profile });\n\n // Initial sign in - store OAuth tokens in the JWT\n if (account) {\n console.log('[OAuth42 SDK] Initial sign in - storing tokens in JWT');\n token.accessToken = account.access_token;\n token.refreshToken = account.refresh_token;\n token.expiresAt = account.expires_at;\n token.idToken = account.id_token;\n token.clientId = clientId;\n token.clientSecret = clientSecret;\n token.issuer = options.issuer || process.env.NEXT_PUBLIC_OAUTH_ISSUER || process.env.OAUTH42_ISSUER;\n }\n\n // Add user profile data\n if (profile) {\n const oauth42Profile = profile as OAuth42Profile;\n token.email = oauth42Profile.email;\n token.username = oauth42Profile.username;\n token.emailVerified = oauth42Profile.email_verified;\n }\n\n // NOTE: Token refresh is handled by middleware (withOAuth42Auth)\n // Middleware can properly set cookies after refresh, which JWT callback cannot\n // do in Next.js App Router Server Components.\n\n // Call custom callback if provided\n if (options.callbacks?.jwt) {\n return options.callbacks.jwt({ token, account, profile } as any);\n }\n\n console.log('[OAuth42 SDK] JWT callback complete, returning token');\n return token;\n },\n\n async session({ session, token }) {\n console.log('[OAuth42 SDK] Session callback called', { hasToken: !!token, hasSession: !!session });\n\n // Add OAuth42-specific data to session\n session.accessToken = token.accessToken as string;\n session.idToken = token.idToken as string;\n\n // Pass through any token refresh errors to the client\n if (token.error) {\n session.error = token.error as string;\n }\n\n if (session.user) {\n session.user.email = token.email as string;\n session.user.name = token.name as string;\n session.user.username = token.username as string;\n session.user.emailVerified = token.emailVerified as boolean;\n }\n\n // Call custom callback if provided\n if (options.callbacks?.session) {\n return options.callbacks.session({ session, token } as any);\n }\n\n console.log('[OAuth42 SDK] Session callback complete, returning session');\n return session;\n },\n },\n \n pages: {\n signIn: '/auth/signin',\n signOut: '/auth/signout',\n error: '/auth/error',\n ...options.pages,\n },\n \n session: {\n strategy: 'jwt',\n ...options.session,\n },\n \n debug: options.debug || process.env.NODE_ENV === 'development',\n\n secret: process.env.NEXTAUTH_SECRET,\n\n // Configure unique cookie names per app to prevent session conflicts on localhost\n ...(options.cookiePrefix && {\n cookies: {\n sessionToken: {\n name: `${options.cookiePrefix}.session-token`,\n options: {\n httpOnly: true,\n sameSite: 'lax' as const,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n },\n },\n callbackUrl: {\n name: `${options.cookiePrefix}.callback-url`,\n options: {\n httpOnly: true,\n sameSite: 'lax' as const,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n },\n },\n csrfToken: {\n name: `${options.cookiePrefix}.csrf-token`,\n options: {\n httpOnly: true,\n sameSite: 'lax' as const,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n },\n },\n // PKCE code_verifier cookie - essential for PKCE flow\n pkceCodeVerifier: {\n name: `${options.cookiePrefix}.pkce.code_verifier`,\n options: {\n httpOnly: true,\n sameSite: 'lax' as const,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n maxAge: 900, // 15 minutes\n },\n },\n // State cookie for OAuth CSRF protection\n state: {\n name: `${options.cookiePrefix}.state`,\n options: {\n httpOnly: true,\n sameSite: 'lax' as const,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n maxAge: 900, // 15 minutes\n },\n },\n // Nonce cookie for OpenID Connect\n nonce: {\n name: `${options.cookiePrefix}.nonce`,\n options: {\n httpOnly: true,\n sameSite: 'lax' as const,\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n },\n },\n },\n }),\n };\n \n // Return the configuration and handlers for API routes\n const handler = NextAuth(authOptions);\n return {\n auth: authOptions,\n handlers: { GET: handler, POST: handler },\n };\n}\n\n/**\n * Create NextAuth handlers for API routes\n */\nexport function createHandlers(authOptions: NextAuthOptions) {\n const handler = NextAuth(authOptions);\n return { GET: handler, POST: handler };\n}\n\n/**\n * Helper to get the current session server-side\n * @deprecated Use getOAuth42Session instead - this is now just an alias for backward compatibility\n * \n * This function is maintained for backward compatibility but internally\n * calls getOAuth42Session which properly handles both App Router and Pages Router\n */\nexport const getServerSession = getOAuth42Session;\n\n/**\n * Token refresh helper with simple per-process locking\n *\n * The lock prevents multiple concurrent refresh calls from the same process,\n * reducing unnecessary token churn. The backend also has a 10-second grace\n * period for blacklisted tokens, so concurrent requests across processes\n * will still succeed.\n */\nexport async function refreshAccessToken(token: any, clientId: string, clientSecret: string, issuer?: string): Promise<any> {\n // If a refresh is already in progress, wait for it\n if (activeRefresh) {\n console.log('[OAuth42] Refresh already in progress, waiting...');\n return await activeRefresh;\n }\n\n // Start the refresh and store the promise\n activeRefresh = doRefresh(token, clientId, clientSecret, issuer);\n try {\n return await activeRefresh;\n } finally {\n activeRefresh = null;\n }\n}\n\nasync function doRefresh(token: any, clientId: string, clientSecret: string, issuer?: string): Promise<any> {\n try {\n const baseUrl = issuer || process.env.OAUTH42_ISSUER || 'https://oauth42.com';\n const tokenUrl = `${baseUrl}/oauth2/token`;\n\n // In development, we need to handle self-signed certificates\n const fetchOptions: any = {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: token.refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n }),\n };\n\n // Add agent for self-signed certificates in development\n if (process.env.NODE_ENV !== 'production' && tokenUrl.startsWith('https://')) {\n const https = await import('https');\n fetchOptions.agent = new https.Agent({\n rejectUnauthorized: false\n });\n }\n\n const response = await fetch(tokenUrl, fetchOptions);\n const refreshedTokens = await response.json();\n\n if (!response.ok) {\n throw refreshedTokens;\n }\n\n console.log('[OAuth42] Token refreshed successfully');\n return {\n ...token,\n accessToken: refreshedTokens.access_token,\n refreshToken: refreshedTokens.refresh_token ?? token.refreshToken,\n // Store expiration time in seconds (Unix timestamp)\n expiresAt: Math.floor(Date.now() / 1000) + (refreshedTokens.expires_in || 3600),\n // Explicitly remove any error property on successful refresh\n error: undefined,\n };\n } catch (error) {\n console.error('[OAuth42] Failed to refresh access token:', error);\n return {\n ...token,\n error: 'RefreshAccessTokenError',\n };\n }\n}","import { getServerSession as getNextAuthSession } from 'next-auth';\nimport { NextAuthOptions } from 'next-auth';\nimport { GetServerSidePropsContext, NextApiRequest, NextApiResponse } from 'next';\nimport { headers } from 'next/headers';\n\n/** Header name used by middleware to pass refreshed tokens to API routes */\nconst REFRESHED_TOKEN_HEADER = 'x-oauth42-refreshed-token';\n\n/**\n * Get the OAuth42 session server-side\n *\n * This is the primary method for retrieving sessions in OAuth42 SDK.\n * Supports both Pages Router and App Router:\n *\n * App Router:\n * ```ts\n * const session = await getOAuth42Session(authOptions);\n * ```\n *\n * Pages Router:\n * ```ts\n * const session = await getOAuth42Session(req, res, authOptions);\n * ```\n *\n * **Token Refresh Support:**\n * When middleware refreshes an expired token, it passes the new token via\n * the `x-oauth42-refreshed-token` header. This function automatically detects\n * and uses that refreshed token, ensuring API routes always have a valid token.\n */\nexport async function getOAuth42Session(\n ...args:\n | [GetServerSidePropsContext['req'], GetServerSidePropsContext['res'], NextAuthOptions]\n | [NextApiRequest, NextApiResponse, NextAuthOptions]\n | [NextAuthOptions]\n) {\n const session = await getNextAuthSession(...args as any);\n\n if (!session) {\n return null;\n }\n\n // Check for refreshed token from middleware\n // This handles the race condition where middleware refreshes the token\n // but the API route still reads the old token from the session cookie\n let refreshedToken: string | null = null;\n\n try {\n // App Router: use headers() from next/headers\n if (args.length === 1) {\n const headersList = await headers();\n refreshedToken = headersList.get(REFRESHED_TOKEN_HEADER);\n }\n // Pages Router: check request headers\n else if (args.length === 3) {\n const req = args[0] as NextApiRequest | GetServerSidePropsContext['req'];\n refreshedToken = (req.headers[REFRESHED_TOKEN_HEADER] as string) || null;\n }\n } catch {\n // headers() may throw if called outside of a request context\n // This is fine - just use the session token as-is\n }\n\n if (refreshedToken) {\n console.log('[OAuth42 Session] Using refreshed token from middleware');\n return {\n ...session,\n accessToken: refreshedToken,\n };\n }\n\n return session;\n}\n\n/**\n * Helper for protecting API routes\n */\nexport function withOAuth42Session(\n handler: (req: NextApiRequest, res: NextApiResponse, session: any) => Promise<void> | void,\n authOptions: NextAuthOptions\n) {\n return async (req: NextApiRequest, res: NextApiResponse) => {\n const session = await getOAuth42Session(req, res, authOptions);\n \n if (!session) {\n return res.status(401).json({ error: 'Unauthorized' });\n }\n \n return handler(req, res, session);\n };\n}\n\n/**\n * Helper for protecting server-side props\n */\nexport function withOAuth42ServerSideProps(\n getServerSideProps: (\n context: GetServerSidePropsContext,\n session: any\n ) => Promise<any>,\n authOptions: NextAuthOptions\n) {\n return async (context: GetServerSidePropsContext) => {\n const session = await getOAuth42Session(\n context.req,\n context.res,\n authOptions\n );\n \n if (!session) {\n return {\n redirect: {\n destination: '/auth/signin',\n permanent: false,\n },\n };\n }\n \n return getServerSideProps(context, session);\n };\n}","import { NextRequest, NextResponse } from 'next/server';\nimport { getToken, encode } from 'next-auth/jwt';\n\nexport interface OAuth42AuthOptions {\n pages?: {\n signIn?: string;\n error?: string;\n };\n callbacks?: {\n authorized?: (params: { token: any; req: NextRequest }) => boolean | Promise<boolean>;\n };\n protectedPaths?: string[];\n publicPaths?: string[];\n /**\n * Cookie prefix for custom cookie names. Must match the prefix used in createAuth().\n * E.g., 'oauth42-portal' will look for cookie 'oauth42-portal.session-token'\n */\n cookiePrefix?: string;\n}\n\n/**\n * Refresh tokens by calling the OAuth42 backend directly\n */\nasync function refreshTokens(\n refreshToken: string,\n clientId: string,\n clientSecret: string,\n issuer: string\n): Promise<{ success: boolean; accessToken?: string; refreshToken?: string; expiresAt?: number; error?: string }> {\n try {\n const tokenUrl = `${issuer}/oauth2/token`;\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: clientId,\n client_secret: clientSecret,\n }),\n });\n\n const data = await response.json();\n\n if (!response.ok) {\n console.error('[OAuth42 Middleware] Token refresh failed:', data);\n return { success: false, error: data.error || 'refresh_failed' };\n }\n\n console.log('[OAuth42 Middleware] Token refreshed successfully');\n return {\n success: true,\n accessToken: data.access_token,\n refreshToken: data.refresh_token,\n expiresAt: Math.floor(Date.now() / 1000) + (data.expires_in || 3600),\n };\n } catch (error) {\n console.error('[OAuth42 Middleware] Token refresh error:', error);\n return { success: false, error: 'refresh_error' };\n }\n}\n\n/**\n * Middleware helper for protecting routes with OAuth42\n *\n * This middleware handles:\n * 1. Route protection (redirect to login if no session)\n * 2. Token refresh (refresh expired tokens and update cookie)\n */\nexport function withOAuth42Auth(options: OAuth42AuthOptions = {}) {\n const secret = process.env.NEXTAUTH_SECRET;\n const clientId = process.env.OAUTH42_CLIENT_ID;\n const clientSecret = process.env.OAUTH42_CLIENT_SECRET;\n const issuer = process.env.OAUTH42_ISSUER || 'https://localhost:8443';\n\n if (!secret) {\n console.warn('[OAuth42 Middleware] NEXTAUTH_SECRET not set');\n }\n\n return async function middleware(req: NextRequest) {\n // Build cookie name - if prefix is provided, use custom name\n const cookieName = options.cookiePrefix\n ? `${options.cookiePrefix}.session-token`\n : 'next-auth.session-token';\n\n const token = await getToken({\n req: req as any,\n secret,\n cookieName,\n });\n\n const pathname = req.nextUrl.pathname;\n\n // Check if path is explicitly public\n if (options.publicPaths?.some(path => pathname.startsWith(path))) {\n return NextResponse.next();\n }\n\n // Check if path needs protection\n const needsProtection = options.protectedPaths\n ? options.protectedPaths.some(path => pathname.startsWith(path))\n : true; // Default to protecting all paths\n\n if (!needsProtection) {\n return NextResponse.next();\n }\n\n // No token at all - redirect to sign in\n if (!token) {\n const signInUrl = options.pages?.signIn || '/auth/signin';\n const url = new URL(signInUrl, req.url);\n url.searchParams.set('callbackUrl', pathname);\n return NextResponse.redirect(url);\n }\n\n // Check if access token is expired or expiring soon (60 second buffer)\n const expiresAt = token.expiresAt as number | undefined;\n const now = Math.floor(Date.now() / 1000);\n const bufferSeconds = 60;\n const needsRefresh = expiresAt && now >= expiresAt - bufferSeconds;\n\n if (needsRefresh && token.refreshToken && clientId && clientSecret) {\n console.log('[OAuth42 Middleware] Access token expired, refreshing...');\n\n const refreshed = await refreshTokens(\n token.refreshToken as string,\n clientId,\n clientSecret,\n issuer\n );\n\n if (refreshed.success && refreshed.accessToken && refreshed.refreshToken) {\n // Update the token with new values\n const updatedToken = {\n ...token,\n accessToken: refreshed.accessToken,\n refreshToken: refreshed.refreshToken,\n expiresAt: refreshed.expiresAt,\n };\n\n // Re-encode the JWT\n const newJwt = await encode({\n token: updatedToken,\n secret: secret!,\n });\n\n // Create response with request headers that pass the new token to API routes\n // This is necessary because API routes read from the request, not the response cookie\n const requestHeaders = new Headers(req.headers);\n requestHeaders.set('x-oauth42-refreshed-token', refreshed.accessToken);\n\n const response = NextResponse.next({\n request: {\n headers: requestHeaders,\n },\n });\n\n // Set cookie with same settings NextAuth uses (for future requests)\n response.cookies.set(cookieName, newJwt, {\n httpOnly: true,\n sameSite: 'lax',\n path: '/',\n secure: process.env.NODE_ENV === 'production',\n });\n\n console.log('[OAuth42 Middleware] Cookie updated with refreshed tokens, header set for current request');\n return response;\n } else {\n // Refresh failed - redirect to sign in\n console.error('[OAuth42 Middleware] Refresh failed, redirecting to sign in');\n const signInUrl = options.pages?.signIn || '/auth/signin';\n const url = new URL(signInUrl, req.url);\n url.searchParams.set('callbackUrl', pathname);\n url.searchParams.set('error', 'RefreshAccessTokenError');\n return NextResponse.redirect(url);\n }\n }\n\n // Check custom authorization callback\n if (options.callbacks?.authorized) {\n const isAuthorized = await options.callbacks.authorized({ token, req });\n if (!isAuthorized) {\n const signInUrl = options.pages?.signIn || '/auth/signin';\n const url = new URL(signInUrl, req.url);\n url.searchParams.set('callbackUrl', pathname);\n return NextResponse.redirect(url);\n }\n }\n\n return NextResponse.next();\n };\n}\n\n/**\n * Helper to create middleware configuration\n */\nexport function createMiddlewareConfig(\n protectedPaths: string[] = ['/protected'],\n publicPaths: string[] = ['/auth', '/api/auth']\n) {\n return {\n matcher: [\n /*\n * Match all request paths except for the ones starting with:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - public folder\n */\n '/((?!_next/static|_next/image|favicon.ico|public).*)',\n ],\n protectedPaths,\n publicPaths,\n };\n}\n"],"mappings":"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","names":["import_next_auth","getNextAuthSession","NextAuthDefault"]}
|