@@ -120,9 +120,10 @@ export default eventHandler(async (event: H3Event) => {
120120
121121 config . redirectURL = config . redirectURL || `${ requestURL . protocol } //${ requestURL . host } ${ requestURL . pathname } `
122122
123- const state = await handleState ( event )
124-
125123 if ( ! query . code ) {
124+ // Initial authorization request (generate and store state)
125+ const state = await generateState ( event )
126+
126127 config . scope = config . scope || [ ]
127128 if ( ! config . scope . includes ( 'api' ) ) {
128129 config . scope . push ( 'api' )
@@ -141,17 +142,32 @@ export default eventHandler(async (event: H3Event) => {
141142 )
142143 }
143144
144- if ( query . state !== state ) {
145+ // Callback with code (validate and consume state)
146+ const storedState = getCookie ( event , 'studio-oauth-state' )
147+
148+ if ( ! storedState ) {
145149 throw createError ( {
146- statusCode : 500 ,
147- message : 'Invalid state' ,
150+ statusCode : 400 ,
151+ message : 'OAuth state cookie not found. Please try logging in again. ' ,
148152 data : {
149- query,
150- state,
153+ hint : 'State cookie may have expired or been cleared' ,
151154 } ,
152155 } )
153156 }
154157
158+ if ( query . state !== storedState ) {
159+ throw createError ( {
160+ statusCode : 400 ,
161+ message : 'Invalid state - OAuth state mismatch' ,
162+ data : {
163+ hint : 'This may be caused by browser refresh, navigation, or expired session' ,
164+ } ,
165+ } )
166+ }
167+
168+ // State validated, delete the cookie
169+ deleteCookie ( event , 'studio-oauth-state' )
170+
155171 const token = await requestAccessToken ( config . tokenURL as string , {
156172 body : {
157173 grant_type : 'authorization_code' ,
@@ -233,14 +249,7 @@ async function requestAccessToken(url: string, options: RequestAccessTokenOption
233249 }
234250}
235251
236- async function handleState ( event : H3Event ) {
237- const state = getCookie ( event , 'studio-oauth-state' )
238-
239- if ( state ) {
240- deleteCookie ( event , 'studio-oauth-state' )
241- return state
242- }
243-
252+ async function generateState ( event : H3Event ) {
244253 const newState = Array . from ( getRandomValues ( new Uint8Array ( 32 ) ) )
245254 . map ( b => b . toString ( 16 ) . padStart ( 2 , '0' ) )
246255 . join ( '' )
0 commit comments