fix: enable connection link generation for desktop app

This commit is contained in:
Bohdan Triapitsyn
2026-07-01 19:11:05 +03:00
parent bc4a7d358a
commit a62ec20ff6
3 changed files with 113 additions and 4 deletions
@@ -396,6 +396,35 @@ export const registerAuthAndAccessRoutes = (app, dependencies) => {
}
};
const runWithClientCreateAuth = async (req, res, next, handler) => {
try {
if (typeof uiAuthController.resolveAuthContext === 'function') {
const context = await uiAuthController.resolveAuthContext(req, res, {
allowClientAuth: true,
allowUrlToken: false,
});
if (context?.type === 'session') {
await handler(context);
return;
}
if (context?.type === 'client') {
const client = await clientRecordFromAuthContext(context);
if (client?.clientKind === 'desktop-local') {
await handler({ ...context, client });
return;
}
return res.status(403).json({ error: 'Client tokens cannot create remote clients' });
}
}
await runWithUiAuth(req, res, next, async () => {
await handler({ type: 'session' });
}, { sessionOnly: true });
} catch (error) {
next(error);
}
};
const clientIdFromAuthContext = (context) => {
const raw = context?.client?.id || context?.clientId;
return typeof raw === 'string' && raw.length > 0 ? raw : null;
@@ -567,7 +596,7 @@ export const registerAuthAndAccessRoutes = (app, dependencies) => {
});
app.post('/api/client-auth/clients', express.json({ limit: '64kb' }), async (req, res, next) => {
await runWithUiAuth(req, res, next, async () => {
await runWithClientCreateAuth(req, res, next, async () => {
const result = await remoteClientAuthRuntime.createClient({
label: req.body?.label,
clientKind: req.body?.clientKind,
@@ -575,7 +604,7 @@ export const registerAuthAndAccessRoutes = (app, dependencies) => {
});
res.setHeader('Cache-Control', 'no-store');
res.status(201).json(result);
}, { sessionOnly: true });
});
});
app.delete('/api/client-auth/clients/:id', async (req, res, next) => {
@@ -399,6 +399,36 @@ describe('client auth routes', () => {
expect(revoked.body.client.id).toBe(current.body.client.id);
});
it('allows only the local desktop client token to create remote client tokens', async () => {
const app = express();
let authContext = { type: 'session' };
const dependencies = createDependencies({
resolveAuthContext: async () => authContext,
});
registerAuthAndAccessRoutes(app, dependencies);
const desktop = await request(app)
.post('/api/client-auth/clients')
.send({ label: 'OpenChamber Desktop', clientKind: 'desktop-local' });
const remote = await request(app)
.post('/api/client-auth/clients')
.send({ label: 'Phone' });
authContext = { type: 'client', clientId: remote.body.client.id, client: remote.body.client };
const denied = await request(app)
.post('/api/client-auth/clients')
.send({ label: 'Another phone' });
expect(denied.status).toBe(403);
expect(denied.body.error).toBe('Client tokens cannot create remote clients');
authContext = { type: 'client', clientId: desktop.body.client.id, client: desktop.body.client };
const created = await request(app)
.post('/api/client-auth/clients')
.send({ label: 'Mobile' });
expect(created.status).toBe(201);
expect(created.body.client.label).toBe('Mobile');
});
it('requires UI-session auth for passkey registration management routes', async () => {
const app = express();
const dependencies = createDependencies();