@@ -154,31 +154,80 @@ export function createAuthConfig(config: ImmutableAuthConfig): NextAuthConfig {
154154 async jwt ( {
155155 token, user, trigger, session : sessionUpdate ,
156156 } : any ) {
157- // Initial sign in - store all token data
158- if ( user ) {
159- return {
160- ...token ,
161- sub : user . sub ,
162- email : user . email ,
163- nickname : user . nickname ,
164- accessToken : user . accessToken ,
165- refreshToken : user . refreshToken ,
166- idToken : user . idToken ,
167- accessTokenExpires : user . accessTokenExpires ,
168- zkEvm : user . zkEvm ,
169- } ;
170- }
157+ try {
158+ // Initial sign in - store all token data
159+ if ( user ) {
160+ return {
161+ ...token ,
162+ sub : user . sub ,
163+ email : user . email ,
164+ nickname : user . nickname ,
165+ accessToken : user . accessToken ,
166+ refreshToken : user . refreshToken ,
167+ idToken : user . idToken ,
168+ accessTokenExpires : user . accessTokenExpires ,
169+ zkEvm : user . zkEvm ,
170+ } ;
171+ }
172+
173+ // Handle session update (for client-side token sync or forceRefresh)
174+ // When client-side Auth refreshes tokens via TOKEN_REFRESHED event,
175+ // it calls updateSession() which triggers this callback with the new tokens.
176+ // We clear any stale error (e.g., TokenExpired) on successful update.
177+ if ( trigger === 'update' && sessionUpdate ) {
178+ const update = sessionUpdate as Record < string , unknown > ;
179+
180+ // If forceRefresh is requested, perform server-side token refresh
181+ // This is used after zkEVM registration to get updated claims from IDP
182+ if ( update . forceRefresh && token . refreshToken ) {
183+ try {
184+ const refreshed = await refreshAccessToken (
185+ token . refreshToken as string ,
186+ config . clientId ,
187+ authDomain ,
188+ ) ;
189+ // Extract zkEvm claims from the refreshed idToken
190+ const zkEvm = extractZkEvmFromIdToken ( refreshed . idToken ) ;
191+ return {
192+ ...token ,
193+ accessToken : refreshed . accessToken ,
194+ refreshToken : refreshed . refreshToken ,
195+ idToken : refreshed . idToken ,
196+ accessTokenExpires : refreshed . accessTokenExpires ,
197+ zkEvm : zkEvm ?? token . zkEvm , // Keep existing zkEvm if not in new token
198+ error : undefined ,
199+ } ;
200+ } catch ( error ) {
201+ // eslint-disable-next-line no-console
202+ console . error ( '[auth-next-server] Force refresh failed:' , error ) ;
203+ return {
204+ ...token ,
205+ error : 'RefreshTokenError' ,
206+ } ;
207+ }
208+ }
209+
210+ // Standard session update - merge provided values
211+ return {
212+ ...token ,
213+ ...( update . accessToken ? { accessToken : update . accessToken } : { } ) ,
214+ ...( update . refreshToken ? { refreshToken : update . refreshToken } : { } ) ,
215+ ...( update . idToken ? { idToken : update . idToken } : { } ) ,
216+ ...( update . accessTokenExpires ? { accessTokenExpires : update . accessTokenExpires } : { } ) ,
217+ ...( update . zkEvm ? { zkEvm : update . zkEvm } : { } ) ,
218+ // Clear any stale error when valid tokens are synced from client-side
219+ error : undefined ,
220+ } ;
221+ }
171222
172- // Handle session update (for client-side token sync or forceRefresh)
173- // When client-side Auth refreshes tokens via TOKEN_REFRESHED event,
174- // it calls updateSession() which triggers this callback with the new tokens.
175- // We clear any stale error (e.g., TokenExpired) on successful update.
176- if ( trigger === 'update' && sessionUpdate ) {
177- const update = sessionUpdate as Record < string , unknown > ;
223+ // Return token if not expired
224+ if ( ! isTokenExpired ( token . accessTokenExpires as number ) ) {
225+ return token ;
226+ }
178227
179- // If forceRefresh is requested, perform server-side token refresh
180- // This is used after zkEVM registration to get updated claims from IDP
181- if ( update . forceRefresh && token . refreshToken ) {
228+ // Token expired - attempt server-side refresh
229+ // This ensures clients always get fresh tokens from session callbacks
230+ if ( token . refreshToken ) {
182231 try {
183232 const refreshed = await refreshAccessToken (
184233 token . refreshToken as string ,
@@ -194,91 +243,54 @@ export function createAuthConfig(config: ImmutableAuthConfig): NextAuthConfig {
194243 idToken : refreshed . idToken ,
195244 accessTokenExpires : refreshed . accessTokenExpires ,
196245 zkEvm : zkEvm ?? token . zkEvm , // Keep existing zkEvm if not in new token
197- error : undefined ,
246+ error : undefined , // Clear any previous error
198247 } ;
199248 } catch ( error ) {
200- // eslint-disable-next-line no-console
201- console . error ( '[auth-next-server] Force refresh failed:' , error ) ;
249+ // eslint-disable-next-line no-console
250+ console . error ( '[auth-next-server] Token refresh failed:' , error ) ;
202251 return {
203252 ...token ,
204253 error : 'RefreshTokenError' ,
205254 } ;
206255 }
207256 }
208257
209- // Standard session update - merge provided values
258+ // No refresh token available
210259 return {
211260 ...token ,
212- ...( update . accessToken ? { accessToken : update . accessToken } : { } ) ,
213- ...( update . refreshToken ? { refreshToken : update . refreshToken } : { } ) ,
214- ...( update . idToken ? { idToken : update . idToken } : { } ) ,
215- ...( update . accessTokenExpires ? { accessTokenExpires : update . accessTokenExpires } : { } ) ,
216- ...( update . zkEvm ? { zkEvm : update . zkEvm } : { } ) ,
217- // Clear any stale error when valid tokens are synced from client-side
218- error : undefined ,
261+ error : 'TokenExpired' ,
219262 } ;
263+ } catch ( error ) {
264+ // eslint-disable-next-line no-console
265+ console . error ( '[auth-next-server] JWT callback error:' , error ) ;
266+ throw error ;
220267 }
221-
222- // Return token if not expired
223- if ( ! isTokenExpired ( token . accessTokenExpires as number ) ) {
224- return token ;
225- }
226-
227- // Token expired - attempt server-side refresh
228- // This ensures clients always get fresh tokens from session callbacks
229- if ( token . refreshToken ) {
230- try {
231- const refreshed = await refreshAccessToken (
232- token . refreshToken as string ,
233- config . clientId ,
234- authDomain ,
235- ) ;
236- // Extract zkEvm claims from the refreshed idToken
237- const zkEvm = extractZkEvmFromIdToken ( refreshed . idToken ) ;
238- return {
239- ...token ,
240- accessToken : refreshed . accessToken ,
241- refreshToken : refreshed . refreshToken ,
242- idToken : refreshed . idToken ,
243- accessTokenExpires : refreshed . accessTokenExpires ,
244- zkEvm : zkEvm ?? token . zkEvm , // Keep existing zkEvm if not in new token
245- error : undefined , // Clear any previous error
246- } ;
247- } catch ( error ) {
248- // eslint-disable-next-line no-console
249- console . error ( '[auth-next-server] Token refresh failed:' , error ) ;
250- return {
251- ...token ,
252- error : 'RefreshTokenError' ,
253- } ;
254- }
255- }
256-
257- // No refresh token available
258- return {
259- ...token ,
260- error : 'TokenExpired' ,
261- } ;
262268 } ,
263269
264270 // eslint-disable-next-line @typescript-eslint/no-explicit-any
265271 async session ( { session, token } : any ) {
266- // Expose token data to the session
267- return {
268- ...session ,
269- user : {
270- ...session . user ,
271- sub : token . sub as string ,
272- email : token . email as string | undefined ,
273- nickname : token . nickname as string | undefined ,
274- } ,
275- accessToken : token . accessToken as string ,
276- refreshToken : token . refreshToken as string | undefined ,
277- idToken : token . idToken as string | undefined ,
278- accessTokenExpires : token . accessTokenExpires as number ,
279- zkEvm : token . zkEvm ,
280- ...( token . error && { error : token . error as string } ) ,
281- } ;
272+ try {
273+ // Expose token data to the session
274+ return {
275+ ...session ,
276+ user : {
277+ ...session . user ,
278+ sub : token . sub as string ,
279+ email : token . email as string | undefined ,
280+ nickname : token . nickname as string | undefined ,
281+ } ,
282+ accessToken : token . accessToken as string ,
283+ refreshToken : token . refreshToken as string | undefined ,
284+ idToken : token . idToken as string | undefined ,
285+ accessTokenExpires : token . accessTokenExpires as number ,
286+ zkEvm : token . zkEvm ,
287+ ...( token . error && { error : token . error as string } ) ,
288+ } ;
289+ } catch ( error ) {
290+ // eslint-disable-next-line no-console
291+ console . error ( '[auth-next-server] Session callback error:' , error ) ;
292+ throw error ;
293+ }
282294 } ,
283295 } ,
284296
0 commit comments