Files
accounted/supabase/migrations/20260518120000_oauth_client_registrations.sql
T
Mattsson 16164ea14c Fix/mcp fixes and bugs (#518)
* feat(voucher): add create voucher and correct entry previews; update commit methods

* feat: add support for pending operations in API key scopes and OAuth client management

- Introduced new API key scopes for reading and approving pending operations.
- Updated the scope groups to include pending operations.
- Added new tools for listing and managing pending operations.
- Implemented OAuth client registration and revocation endpoints.
- Created a UI panel for managing OAuth clients, including registration and revocation.
- Added tests for pending operations tools and OAuth allowlist functionality.
- Implemented a database migration for OAuth client registrations with appropriate policies and constraints.

* feat: Implement OAuth client registration rate limiting and enhance security measures

- Added IP-based rate limiting to the OAuth client registration endpoint to prevent enumeration attacks.
- Introduced a service-role client for allowlist lookups, ensuring trust boundaries are maintained.
- Updated error responses to be uniform across different types of redirect URI validation failures.
- Enhanced tests to reflect changes in OAuth scope handling, ensuring fallback to read-only scopes when no scopes are provided.
- Improved handling of high-risk pending operations, requiring explicit confirmation for approvals.
- Added audit logging for OAuth client revocations and pending operation approvals/rejections to maintain a security audit trail.
- Refactored API key scope management to include default read-only scopes for OAuth-issued keys and added segregation-of-duties checks.
2026-05-18 19:02:42 +02:00

62 lines
2.5 KiB
SQL

-- OAuth dynamic client registration allowlist.
--
-- The /api/mcp-oauth/{register,authorize} endpoints used to hardcode a
-- regex allowlist of redirect URIs (claude.ai/api/*, claude.com/api/*,
-- localhost). That blocked self-hosted custom apps from completing OAuth
-- against gnubok, even though the rest of the flow (PKCE, refresh
-- rotation, AES-256-GCM auth codes) is provider-agnostic.
--
-- This table lets users register their own redirect URIs through the
-- settings UI. The hardcoded patterns remain in code as the built-in
-- fallback (so Claude continues to work without seeding rows).
--
-- Defense against open-redirect abuse:
-- * exact URI match only (no regex)
-- * registration requires owner/admin role (enforced in API route)
-- * unique constraint on redirect_uri so two users can't both claim it
-- * revoke flips revoked_at instead of deleting (preserves audit trail)
CREATE TABLE public.oauth_client_registrations (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES auth.users ON DELETE CASCADE NOT NULL,
client_name TEXT NOT NULL,
redirect_uri TEXT NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
revoked_at TIMESTAMPTZ
);
-- Only one active registration per URI. Allows the same URI to be
-- re-registered after revocation (partial unique index).
CREATE UNIQUE INDEX oauth_client_registrations_uri_active
ON public.oauth_client_registrations (redirect_uri)
WHERE revoked_at IS NULL;
CREATE INDEX oauth_client_registrations_user_id_idx
ON public.oauth_client_registrations (user_id);
ALTER TABLE public.oauth_client_registrations ENABLE ROW LEVEL SECURITY;
-- Users see and manage only their own registrations.
CREATE POLICY "oauth_client_registrations_select_own"
ON public.oauth_client_registrations FOR SELECT
USING (user_id = auth.uid());
CREATE POLICY "oauth_client_registrations_insert_own"
ON public.oauth_client_registrations FOR INSERT
WITH CHECK (user_id = auth.uid());
CREATE POLICY "oauth_client_registrations_update_own"
ON public.oauth_client_registrations FOR UPDATE
USING (user_id = auth.uid())
WITH CHECK (user_id = auth.uid());
CREATE POLICY "oauth_client_registrations_delete_own"
ON public.oauth_client_registrations FOR DELETE
USING (user_id = auth.uid());
CREATE TRIGGER oauth_client_registrations_set_updated_at
BEFORE UPDATE ON public.oauth_client_registrations
FOR EACH ROW EXECUTE FUNCTION public.update_updated_at_column();
NOTIFY pgrst, 'reload schema';