-
Notifications
You must be signed in to change notification settings - Fork 37
feat(auth-nextjs): add auth-nextjs package #2765
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR is being reviewed by Cursor Bugbot
Details
Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.
To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.
packages/passport/sdk-sample-app/src/pages/api/auth/sandbox/[...nextauth].api.ts
Outdated
Show resolved
Hide resolved
|
View your CI Pipeline Execution ↗ for commit 0d731e2
☁️ Nx Cloud last updated this comment at |
|
| Command | Status | Duration | Result |
|---|---|---|---|
nx affected -t build,lint,test |
❌ Failed | 3m 12s | View ↗ |
nx run-many -p @imtbl/sdk,@imtbl/checkout-widge... |
✅ Succeeded | 3s | View ↗ |
☁️ Nx Cloud last updated this comment at 2025-12-17 04:04:32 UTC
|
|
||
| return handler(session, ...args); | ||
| }; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
withAuth doesn't check for session errors
Medium Severity
The withAuth helper only checks if (!session) but doesn't check for session.error. When a refresh token is invalid (e.g., revoked or expired after 365 days), auth() returns a session with error: "RefreshTokenError". The handler would receive this invalid session and could fail when using the stale accessToken for API calls. The README explicitly documents that server code should check for session.error, but this helper doesn't implement that check.
| fetchData(); | ||
| } | ||
| // eslint-disable-next-line | ||
| }, []); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Stale closure causes failed token refresh in useHydratedData
Medium Severity
The useHydratedData effect uses an empty dependency array, causing it to run immediately on mount before the Auth instance is initialized (Auth is created in a parent component's effect, which runs after child effects). When ssr: false due to an expired token, fetchData calls getAccessToken, which finds auth === null and then throws "Session expired" instead of waiting for Auth to initialize and refresh the token. This contradicts the documented behavior that promises automatic client-side token refresh when SSR is skipped.
Additional Locations (1)
| // 1. SSR was skipped (token expired) - need to refresh token and fetch | ||
| // 2. Server fetch failed - retry on client | ||
| // 3. No server data - need to fetch | ||
| const needsClientFetch = !ssr || Boolean(fetchError) || serverData === null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary client refetch when server returns null data
Medium Severity
The condition serverData === null in needsClientFetch causes unnecessary client-side fetches when the server successfully returns null as a legitimate response. When ssr=true and no fetchError, but data is null (e.g., "no results found"), the client incorrectly re-fetches instead of using the server's null result. The condition !ssr already handles when SSR was skipped, and Boolean(fetchError) handles server errors, making serverData === null redundant and incorrect.
| ); | ||
|
|
||
| // Track if we've already started fetching to prevent duplicate calls | ||
| const hasFetchedRef = useRef(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hook state not synchronized when props change
Medium Severity
The useHydratedData hook initializes state with useState(serverData) but never syncs state when props change. If a component instance receives new props (e.g., navigating between routes using the same component), data retains the old value because useState only uses the initial value. Combined with hasFetchedRef preventing re-fetches, the component displays stale data from previous props instead of the new serverData.
| } finally { | ||
| setIsLoading(false); | ||
| } | ||
| }, [fetcher, getAccessToken]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing fetch cancellation causes stale data race condition
Medium Severity
The useHydratedData hook has a race condition where in-flight fetches are not cancelled when props change. When props change from ssr: false to ssr: true (e.g., during soft navigation after token refresh), the props-sync effect correctly sets the fresh serverData. However, the previously started client-side fetch continues running and when it completes, setData(result) overwrites the correct server data with stale results. There's no AbortController, fetch ID tracking, or staleness check to prevent this.
Additional Locations (1)
|
|
||
| hasFetchedRef.current = true; | ||
| fetchData(); | ||
| }, [needsClientFetch, ssr, auth, fetchData]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Client fetch fails when session not yet loaded
Medium Severity
When ssr=true but fetchError exists (server-side fetch failed), useHydratedData immediately attempts a client-side retry without waiting for the session to load from useSession(). The guard if (!ssr && !auth) return only waits for auth when ssr=false, but when ssr=true with a fetchError, it proceeds immediately. If useSession() is still in 'loading' state, getAccessToken() will throw "No access token available" because session is undefined. After this error, hasFetchedRef.current remains true, blocking retries even after the session loads.

Summary
Adding auth-nextjs for convenient integration with nextjs + SSR.
Note
Add
@imtbl/auth-nextjspackage (Auth.js v5 for Next.js App Router)ImmutableAuthProvider,useImmutableAuth,useAccessToken,useHydratedData, andCallbackPagefor popup/redirect flows with client-side token refreshcreateImmutableAuth,createAuthConfig,getAuthenticatedData,createProtectedFetchers,withAuth, andcreateAuthMiddlewarefor SSR, route protection, and server actionsisTokenExpiredutility anduserinfovalidation in credentials providerCore
@imtbl/authupdatesTOKEN_REFRESHED(on silent refresh) andUSER_REMOVED(on permanent auth errors) events; refine refresh logic and add testsSample app wiring
Repo/config tweaks
.npmrc, add syncpack peer-deps ignore, add eslint/jest/tsup/tsconfig for new packageWritten by Cursor Bugbot for commit 0d731e2. This will update automatically on new commits. Configure here.