Skip to content

Commit 6586773

Browse files
committed
fix(oauth): better handling of state
1 parent 42cb5ef commit 6586773

File tree

1 file changed

+24
-15
lines changed

1 file changed

+24
-15
lines changed

src/module/src/runtime/server/routes/auth/gitlab.get.ts

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)