mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-06-19 21:31:46 +00:00
remove(oauth): drop browser-initiated DCR registration flow
OAuthRegisterPage and its server routes (GET /api/oauth/register/validate, POST /api/oauth/register) are superseded by the RFC 7591 machine-to-machine DCR endpoint (POST /oauth/register). Claude.ai and compliant MCP clients register via RFC 7591, then go through the standard /oauth/authorize consent screen for scope selection.
This commit is contained in:
@@ -358,76 +358,6 @@ oauthApiRouter.post('/authorize', requireCookieAuth, (req: Request, res: Respons
|
||||
return res.json({ redirect: url.toString() });
|
||||
});
|
||||
|
||||
// ---- Browser-initiated dynamic client registration ----
|
||||
|
||||
// SPA calls this on load to validate DCR params before rendering scope selection UI
|
||||
oauthApiRouter.get('/register/validate', validateLimiter, optionalAuth, (req: Request, res: Response) => {
|
||||
if (!isAddonEnabled(ADDON_IDS.MCP)) return res.status(404).end();
|
||||
|
||||
const { redirect_uri, client_name, scope } = req.query as Record<string, string>;
|
||||
const userId = (req as OptionalAuthRequest).user?.id ?? null;
|
||||
|
||||
if (!redirect_uri) {
|
||||
return res.json({ valid: false, error: 'invalid_request', error_description: 'redirect_uri is required' });
|
||||
}
|
||||
|
||||
if (!isValidRedirectUri(redirect_uri)) {
|
||||
return res.json({ valid: false, error: 'invalid_redirect_uri', error_description: 'redirect_uri must use HTTPS (localhost is exempt)' });
|
||||
}
|
||||
|
||||
// Anti-fingerprinting: don't expose details to unauthenticated callers
|
||||
if (userId === null) {
|
||||
return res.json({ valid: true, loginRequired: true });
|
||||
}
|
||||
|
||||
const resolvedName = (client_name || '').trim().slice(0, 100) || 'MCP Client';
|
||||
const requestedScopes = (scope || '').split(' ').filter(s => (ALL_SCOPES as string[]).includes(s));
|
||||
|
||||
return res.json({ valid: true, client_name: resolvedName, requested_scopes: requestedScopes });
|
||||
});
|
||||
|
||||
// User submits DCR approval (or cancel) — requires cookie auth
|
||||
oauthApiRouter.post('/register', requireCookieAuth, (req: Request, res: Response) => {
|
||||
if (!isAddonEnabled(ADDON_IDS.MCP)) return res.status(403).json({ error: 'MCP is not enabled' });
|
||||
|
||||
const { user } = req as AuthRequest;
|
||||
const { client_name, redirect_uri, scopes, state, approved } = req.body as {
|
||||
client_name: string;
|
||||
redirect_uri: string;
|
||||
scopes: string[];
|
||||
state?: string;
|
||||
approved?: boolean;
|
||||
};
|
||||
const ip = getClientIp(req);
|
||||
|
||||
// Validate redirect_uri before constructing any redirect URL
|
||||
if (!redirect_uri || !isValidRedirectUri(redirect_uri)) {
|
||||
return res.status(400).json({ error: 'invalid_request', error_description: 'Invalid redirect_uri' });
|
||||
}
|
||||
|
||||
if (approved === false) {
|
||||
const url = new URL(redirect_uri);
|
||||
url.searchParams.set('error', 'access_denied');
|
||||
url.searchParams.set('error_description', 'User cancelled the registration');
|
||||
if (state) url.searchParams.set('state', state);
|
||||
return res.json({ redirect: url.toString() });
|
||||
}
|
||||
|
||||
const result = createOAuthClient(
|
||||
user.id, client_name, [redirect_uri], scopes, ip,
|
||||
{ isPublic: true, createdVia: 'browser-registration' },
|
||||
);
|
||||
if (result.error) return res.status(result.status || 400).json({ error: result.error });
|
||||
|
||||
const newClientId = result.client!.client_id as string;
|
||||
saveConsent(newClientId, user.id, scopes, ip);
|
||||
|
||||
const url = new URL(redirect_uri);
|
||||
url.searchParams.set('client_id', newClientId);
|
||||
if (state) url.searchParams.set('state', state);
|
||||
return res.json({ redirect: url.toString() });
|
||||
});
|
||||
|
||||
// ---- OAuth client CRUD ----
|
||||
|
||||
oauthApiRouter.get('/clients', authenticate, (req: Request, res: Response) => {
|
||||
|
||||
Reference in New Issue
Block a user