feat(auth): add WebAuthn passkey support with migrations, routes, and tests

This commit is contained in:
2025-10-29 17:50:14 +01:00
parent ec6e7f04f2
commit ca30b20873
23 changed files with 1511 additions and 83 deletions
@@ -0,0 +1 @@
DROP TABLE IF EXISTS user_passkeys;
@@ -0,0 +1,19 @@
CREATE TABLE user_passkeys (
id UUID PRIMARY KEY,
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
credential_id BYTEA NOT NULL UNIQUE,
public_key BYTEA NOT NULL,
credential JSONB NOT NULL,
sign_count BIGINT NOT NULL,
transports TEXT[] NOT NULL DEFAULT '{}',
aaguid UUID,
nickname TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
last_used_at TIMESTAMPTZ,
revoked_at TIMESTAMPTZ,
revoked_by UUID,
revoked_reason TEXT
);
CREATE INDEX user_passkeys_user_id_idx ON user_passkeys (user_id);
@@ -0,0 +1 @@
DROP TABLE IF EXISTS webauthn_challenges;
@@ -0,0 +1,13 @@
CREATE TABLE webauthn_challenges (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id) ON DELETE CASCADE,
purpose TEXT NOT NULL,
challenge BYTEA NOT NULL,
state BYTEA NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
expires_at TIMESTAMPTZ NOT NULL,
CONSTRAINT webauthn_challenges_purpose_check CHECK (purpose IN ('registration', 'authentication'))
);
CREATE INDEX webauthn_challenges_user_id_idx ON webauthn_challenges (user_id);
CREATE INDEX webauthn_challenges_expires_at_idx ON webauthn_challenges (expires_at);
@@ -0,0 +1,2 @@
ALTER TABLE user_memberships
ADD COLUMN role TEXT NOT NULL DEFAULT 'user';
@@ -0,0 +1,2 @@
ALTER TABLE user_memberships
DROP COLUMN role;