packages feed

shomei-migrations-0.2.0.0: migrations/shomei/0023-shomei-oauth-clients.sql

SET LOCAL search_path = pg_catalog, pg_temp;

-- OAuth2 / OIDC clients: the relying parties that drive the authorization-code flow.
--
-- client_id is the TypeID text rendering of oauth_client_id (prefix 'oauthclient'), matching how
-- shomei_service_accounts derives its client_id. A client_id is public and copy-pasteable;
-- secrecy lives entirely in the secret.
--
-- secret_hash is a lowercase 64-char SHA-256 hex digest, the same format the service accounts use,
-- so Shomei.Workflow.ServiceToken.verifyServiceSecret verifies both. It is NULL for exactly the
-- public clients (SPAs, native apps), which hold no secret and whose only binding between the
-- authorize and token requests is PKCE.
--
-- client_type is 'confidential' or 'public'.
--
-- redirect_uris is a jsonb array of absolute URI texts, compared by EXACT STRING EQUALITY at
-- authorize time. No prefix matching, no wildcards: a redirect_uri that is not registered must
-- never receive a redirect, or the endpoint becomes an open redirector.
--
-- allowed_scopes is a jsonb array of scope texts (matching shomei_service_accounts.allowed_scopes),
-- the ceiling on what an authorize request may ask for.
--
-- status is 'active' or 'revoked'. A revoked client keeps its row so audit events naming it still
-- resolve, and so a revoked client_id is never recycled.
--
-- Unlike a service account, an oauth client has NO backing shomei_users row: it is never a token
-- subject. The user it acts for is the one who authenticated at /oauth/authorize.
CREATE TABLE IF NOT EXISTS shomei.shomei_oauth_clients (
  oauth_client_id uuid        PRIMARY KEY,
  client_id       text        NOT NULL UNIQUE,
  secret_hash     text        NULL,
  client_type     text        NOT NULL,
  display_name    text        NOT NULL,
  redirect_uris   jsonb       NOT NULL,
  allowed_scopes  jsonb       NOT NULL,
  status          text        NOT NULL,
  created_at      timestamptz NOT NULL,
  revoked_at      timestamptz NULL
);