template-saas-database-v2/ddl/schemas/auth/tables/02-tokens.sql
rckrdmrd 3ce06fbce4 Initial commit - Database de template-saas migrado desde monorepo
Migración desde workspace-v2/projects/template-saas/apps/database
Este repositorio es parte del estándar multi-repo v2

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-16 08:07:11 -06:00

89 lines
3.1 KiB
SQL

-- ============================================
-- TEMPLATE-SAAS: Auth Tokens
-- Schema: auth
-- Version: 1.0.0
-- ============================================
-- Generic tokens (password reset, email verification, etc.)
CREATE TABLE auth.tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants.tenants(id) ON DELETE CASCADE, -- NULL for pre-signup tokens
user_id UUID REFERENCES users.users(id) ON DELETE CASCADE,
-- Token data
token_hash VARCHAR(255) UNIQUE NOT NULL,
type auth.token_type NOT NULL,
-- For API keys
name VARCHAR(200), -- User-defined name
prefix VARCHAR(10), -- First chars for identification (e.g., "sk_live_")
last_used_at TIMESTAMPTZ,
-- Scope/permissions (for API keys)
scopes JSONB DEFAULT '[]'::jsonb,
-- Expiration
expires_at TIMESTAMPTZ,
is_revoked BOOLEAN DEFAULT FALSE,
revoked_at TIMESTAMPTZ,
-- Metadata
metadata JSONB DEFAULT '{}'::jsonb,
-- Audit
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
created_by UUID
);
-- Refresh tokens (separate for better management)
CREATE TABLE auth.refresh_tokens (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID NOT NULL REFERENCES tenants.tenants(id) ON DELETE CASCADE,
user_id UUID NOT NULL REFERENCES users.users(id) ON DELETE CASCADE,
session_id UUID REFERENCES auth.sessions(id) ON DELETE CASCADE,
-- Token
token_hash VARCHAR(255) UNIQUE NOT NULL,
-- Rotation tracking
family_id UUID NOT NULL, -- For refresh token rotation
generation INT DEFAULT 1,
-- Status
is_revoked BOOLEAN DEFAULT FALSE,
revoked_at TIMESTAMPTZ,
-- Expiration
expires_at TIMESTAMPTZ NOT NULL,
-- Audit
created_at TIMESTAMPTZ DEFAULT NOW() NOT NULL,
used_at TIMESTAMPTZ
);
-- Indexes
CREATE INDEX idx_tokens_user ON auth.tokens(user_id) WHERE NOT is_revoked;
CREATE INDEX idx_tokens_type ON auth.tokens(type) WHERE NOT is_revoked;
CREATE INDEX idx_tokens_tenant ON auth.tokens(tenant_id) WHERE NOT is_revoked;
CREATE INDEX idx_tokens_api_key ON auth.tokens(prefix) WHERE type = 'api_key' AND NOT is_revoked;
CREATE INDEX idx_refresh_tokens_user ON auth.refresh_tokens(user_id) WHERE NOT is_revoked;
CREATE INDEX idx_refresh_tokens_family ON auth.refresh_tokens(family_id);
CREATE INDEX idx_refresh_tokens_session ON auth.refresh_tokens(session_id);
-- RLS
ALTER TABLE auth.tokens ENABLE ROW LEVEL SECURITY;
ALTER TABLE auth.refresh_tokens ENABLE ROW LEVEL SECURITY;
CREATE POLICY tokens_tenant_isolation ON auth.tokens
USING (tenant_id IS NULL OR tenant_id = current_setting('app.current_tenant_id', true)::UUID);
CREATE POLICY refresh_tokens_tenant_isolation ON auth.refresh_tokens
USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
-- Comments
COMMENT ON TABLE auth.tokens IS 'Generic tokens for various auth purposes';
COMMENT ON TABLE auth.refresh_tokens IS 'JWT refresh tokens with rotation support';
COMMENT ON COLUMN auth.tokens.prefix IS 'Visible prefix for API key identification';
COMMENT ON COLUMN auth.refresh_tokens.family_id IS 'Group ID for refresh token rotation (detect reuse)';