@@ -10,6 +10,7 @@ import type { CommonUseAuthReturn, GetSessionOptions, SecondarySignInOptions, Si
1010import { useTypedBackendConfig } from '../../helpers'
1111import { getRequestURLWN } from '../common/getRequestURL'
1212import { determineCallbackUrl } from '../../utils/callbackUrl'
13+ import { createAuthError , toAuthError } from '../../utils/authError'
1314import type { SessionData } from './useAuthState'
1415import { navigateToAuthPageWN } from './utils/navigateToAuthPage'
1516import type { NuxtApp } from '#app/nuxt'
@@ -78,7 +79,10 @@ export function useAuth(): UseAuthReturn {
7879 data,
7980 loading,
8081 status,
81- lastRefreshedAt
82+ lastRefreshedAt,
83+ error,
84+ setError,
85+ clearError
8286 } = useAuthState ( )
8387
8488 /**
@@ -93,12 +97,18 @@ export function useAuth(): UseAuthReturn {
9397 options ?: SecondarySignInOptions ,
9498 authorizationParams ?: Record < string , string >
9599 ) : Promise < SignInResult > {
100+ // Clear previous error
101+ clearError ( )
102+
96103 // 1. Lead to error page if no providers are available
97104 const configuredProviders = await getProviders ( )
98105 if ( ! configuredProviders ) {
99106 const errorUrl = resolveApiUrlPath ( 'error' , runtimeConfig )
100107 const navigationResult = await navigateToAuthPageWN ( nuxt , errorUrl , true )
101108
109+ const authError = createAuthError . invalidProvider ( )
110+ setError ( authError )
111+
102112 return {
103113 // Future AuthJS compat here and in other places
104114 // https://authjs.dev/reference/core/errors#invalidprovider
@@ -130,6 +140,9 @@ export function useAuth(): UseAuthReturn {
130140 if ( ! selectedProvider ) {
131141 const navigationResult = await navigateToAuthPageWN ( nuxt , hrefSignInAllProviderPage , true )
132142
143+ const authError = createAuthError . invalidProvider ( provider )
144+ setError ( authError )
145+
133146 return {
134147 // https://authjs.dev/reference/core/errors#invalidprovider
135148 error : 'InvalidProvider' ,
@@ -173,19 +186,28 @@ export function useAuth(): UseAuthReturn {
173186 } ,
174187 /* proxyCookies = */ true
175188 )
176- . catch < Record < string , any > > ( ( error : { data : any } ) => error . data )
189+ . catch < Record < string , any > > ( ( err : { data : any } ) => {
190+ // Set error state for network/server errors
191+ const authError = toAuthError ( err )
192+ setError ( authError )
193+ return err . data
194+ } )
177195
178- const data = await callWithNuxt ( nuxt , fetchSignIn )
196+ const responseData = await callWithNuxt ( nuxt , fetchSignIn )
179197
180198 if ( redirect || ! isSupportingReturn ) {
181- const href = data . url ?? callbackUrl
199+ const href = responseData . url ?? callbackUrl
182200 const navigationResult = await navigateToAuthPageWN ( nuxt , href )
183201
184202 // We use `http://_` as a base to allow relative URLs in `callbackUrl`. We only need the `error` query param
185- const error = new URL ( href , 'http://_' ) . searchParams . get ( 'error' )
203+ const urlError = new URL ( href , 'http://_' ) . searchParams . get ( 'error' )
204+
205+ if ( urlError ) {
206+ setError ( createAuthError . invalidCredentials ( urlError ) )
207+ }
186208
187209 return {
188- error,
210+ error : urlError ,
189211 ok : true ,
190212 status : 302 ,
191213 url : href ,
@@ -194,14 +216,19 @@ export function useAuth(): UseAuthReturn {
194216 }
195217
196218 // At this point the request succeeded (i.e., it went through)
197- const error = new URL ( data . url ) . searchParams . get ( 'error' )
219+ const urlError = new URL ( responseData . url ) . searchParams . get ( 'error' )
220+
221+ if ( urlError ) {
222+ setError ( createAuthError . invalidCredentials ( urlError ) )
223+ }
224+
198225 await getSessionWithNuxt ( nuxt )
199226
200227 return {
201- error,
228+ error : urlError ,
202229 status : 200 ,
203230 ok : true ,
204- url : error ? null : data . url ,
231+ url : urlError ? null : responseData . url ,
205232 navigationResult : undefined ,
206233 }
207234 }
@@ -213,11 +240,18 @@ export function useAuth(): UseAuthReturn {
213240 // Pass the `Host` header when making internal requests
214241 const headers = await getRequestHeaders ( nuxt , false )
215242
216- return _fetch < GetProvidersResult > (
217- nuxt ,
218- '/providers' ,
219- { headers }
220- )
243+ try {
244+ return await _fetch < GetProvidersResult > (
245+ nuxt ,
246+ '/providers' ,
247+ { headers }
248+ )
249+ }
250+ catch ( err ) {
251+ const authError = toAuthError ( err )
252+ setError ( authError )
253+ return null
254+ }
221255 }
222256
223257 /**
@@ -262,6 +296,11 @@ export function useAuth(): UseAuthReturn {
262296 data . value = isNonEmptyObject ( sessionData ) ? sessionData : null
263297 loading . value = false
264298
299+ // Clear error on successful session fetch
300+ if ( data . value ) {
301+ clearError ( )
302+ }
303+
265304 if ( required && status . value === 'unauthenticated' ) {
266305 return onUnauthenticated ( )
267306 }
@@ -276,8 +315,21 @@ export function useAuth(): UseAuthReturn {
276315 callbackUrl : callbackUrl || callbackUrlFallback
277316 }
278317 } ,
279- onRequestError : onError ,
280- onResponseError : onError ,
318+ onRequestError : ( { error : fetchError } ) => {
319+ onError ( )
320+ const authError = toAuthError ( fetchError )
321+ setError ( authError )
322+ } ,
323+ onResponseError : ( { error : fetchError , response } ) => {
324+ onError ( )
325+ if ( response ?. status === 401 ) {
326+ setError ( createAuthError . sessionExpired ( ) )
327+ }
328+ else {
329+ const authError = toAuthError ( fetchError )
330+ setError ( authError )
331+ }
332+ } ,
281333 headers
282334 } , /* proxyCookies = */ true )
283335 }
@@ -291,6 +343,9 @@ export function useAuth(): UseAuthReturn {
291343 * @param options - Options for sign out, e.g., to `redirect` the user to a specific page after sign out has completed
292344 */
293345 async function signOut ( options ?: SignOutOptions ) {
346+ // Clear previous error
347+ clearError ( )
348+
294349 const { callbackUrl : userCallbackUrl , redirect = true } = options ?? { }
295350 const csrfToken = await getCsrfTokenWithNuxt ( nuxt )
296351
@@ -302,23 +357,33 @@ export function useAuth(): UseAuthReturn {
302357 )
303358
304359 if ( ! csrfToken ) {
360+ const authError = createAuthError . unknown ( 'Could not fetch CSRF Token for signing out' )
361+ setError ( authError )
305362 throw createError ( { statusCode : 400 , message : 'Could not fetch CSRF Token for signing out' } )
306363 }
307364
308- const signoutData = await _fetch < { url : string } > ( nuxt , '/signout' , {
309- method : 'POST' ,
310- headers : {
311- 'Content-Type' : 'application/x-www-form-urlencoded' ,
312- ...( await getRequestHeaders ( nuxt ) )
313- } ,
314- onRequest : ( { options } ) => {
315- options . body = new URLSearchParams ( {
316- csrfToken : csrfToken as string ,
317- callbackUrl,
318- json : 'true'
319- } )
320- }
321- } ) . catch ( error => error . data )
365+ let signoutData : { url : string }
366+ try {
367+ signoutData = await _fetch < { url : string } > ( nuxt , '/signout' , {
368+ method : 'POST' ,
369+ headers : {
370+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
371+ ...( await getRequestHeaders ( nuxt ) )
372+ } ,
373+ onRequest : ( { options } ) => {
374+ options . body = new URLSearchParams ( {
375+ csrfToken : csrfToken as string ,
376+ callbackUrl,
377+ json : 'true'
378+ } )
379+ }
380+ } )
381+ }
382+ catch ( err ) {
383+ const authError = toAuthError ( err )
384+ setError ( authError )
385+ signoutData = ( err as any ) . data ?? { url : callbackUrl }
386+ }
322387
323388 if ( redirect ) {
324389 const url = signoutData . url ?? callbackUrl
@@ -350,7 +415,15 @@ export function useAuth(): UseAuthReturn {
350415 */
351416 async function getCsrfToken ( ) {
352417 const headers = await getRequestHeaders ( nuxt )
353- return _fetch < { csrfToken : string } > ( nuxt , '/csrf' , { headers } ) . then ( response => response . csrfToken )
418+ try {
419+ const response = await _fetch < { csrfToken : string } > ( nuxt , '/csrf' , { headers } )
420+ return response . csrfToken
421+ }
422+ catch ( err ) {
423+ const authError = toAuthError ( err )
424+ setError ( authError )
425+ throw err
426+ }
354427 }
355428 function getCsrfTokenWithNuxt ( nuxt : NuxtApp ) {
356429 return callWithNuxt ( nuxt , getCsrfToken )
@@ -360,6 +433,8 @@ export function useAuth(): UseAuthReturn {
360433 status,
361434 data : readonly ( data ) as Readonly < Ref < SessionData | null | undefined > > ,
362435 lastRefreshedAt : readonly ( lastRefreshedAt ) ,
436+ error : readonly ( error ) ,
437+ clearError,
363438 getSession,
364439 getCsrfToken,
365440 getProviders,
0 commit comments