fix(auth): require a hashed poll secret for desktop handoff (#2357)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-02 17:25:54 +02:00
1 parent b82681b77a
commit f703969e80
45 files changed
+382 -188

No files matched your search

+35 -1
View File
@@ -9,10 +9,12 @@ import {
AuthTokenWithUserIdResponse,
EmailRevertRequest,
ForgotPasswordRequest,
HandoffCancelRequest,
HandoffCodeParam,
HandoffCompleteRequest,
HandoffInfoResponse,
HandoffInitiateResponse,
HandoffStatusRequest,
HandoffStatusResponse,
IpAuthorizationPollQuery,
IpAuthorizationPollResponse,
@@ -632,10 +634,39 @@ export function AuthController(app: HonoApp) {
return ctx.json(response);
},
);
app.post(
'/auth/handoff/:code/status',
RateLimitMiddleware(RateLimitConfigs.AUTH_HANDOFF_STATUS),
Validator('param', HandoffCodeParam),
Validator('json', HandoffStatusRequest),
OpenAPI({
operationId: 'get_handoff_status_with_secret',
summary: 'Get handoff status with secret',
responseSchema: HandoffStatusResponse,
statusCode: 200,
security: [],
tags: ['Auth'],
description:
'Check the status of a handoff session using the poll secret from initiation. Returns the authentication token once the handoff is complete and the presented secret matches.',
}),
async (ctx) => {
const clientIp = requireClientIp(ctx.req.raw, {
trustClientIpHeader: Config.proxy.trust_client_ip_header,
clientIpHeaderName: Config.proxy.client_ip_header,
});
const response = await ctx.get('authRequestService').getHandoffStatus({
code: ctx.req.valid('param').code,
clientIp,
pollSecret: ctx.req.valid('json').poll_secret,
});
return ctx.json(response);
},
);
app.delete(
'/auth/handoff/:code',
RateLimitMiddleware(RateLimitConfigs.AUTH_HANDOFF_CANCEL),
Validator('param', HandoffCodeParam),
Validator('json', HandoffCancelRequest),
OpenAPI({
operationId: 'cancel_handoff',
summary: 'Cancel handoff',
@@ -646,7 +677,10 @@ export function AuthController(app: HonoApp) {
description: 'Cancel an ongoing handoff session. The handoff code will no longer be valid for authentication.',
}),
async (ctx) => {
await ctx.get('authRequestService').cancelHandoff({code: ctx.req.valid('param').code});
await ctx.get('authRequestService').cancelHandoff({
code: ctx.req.valid('param').code,
pollSecret: ctx.req.valid('json').poll_secret,
});
return ctx.body(null, 204);
},
);