31 lines
1.4 KiB
SQL
31 lines
1.4 KiB
SQL
-- Passkeys (WebAuthn discoverable credentials): an alternative to the email
|
|||
|
|
-- magic link. A user may register several (one per device/authenticator).
|
||
|
|
CREATE TABLE IF NOT EXISTS passkeys (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
user_id INTEGER NOT NULL REFERENCES users (id) ON DELETE CASCADE,
|
||
|
|
credential_id TEXT NOT NULL UNIQUE,
|
||
|
|
public_key TEXT NOT NULL,
|
||
|
|
sign_count INTEGER NOT NULL DEFAULT 0,
|
||
|
|
label TEXT NOT NULL DEFAULT '',
|
||
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now')),
|
||
|
|
last_used_at TEXT NULL
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_passkeys_user ON passkeys (user_id);
|
||
|
|
|
||
|
|
-- Short-lived, single-use WebAuthn challenges bridging the "options" and
|
||
|
|
-- "verify" calls of both the registration and login ceremonies. user_id is
|
||
|
|
-- set for a registration (tied to the signed-in caller) and NULL for a login
|
||
|
|
-- attempt, since who's logging in isn't known until the credential comes back.
|
||
|
|
CREATE TABLE IF NOT EXISTS webauthn_challenges (
|
||
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||
|
|
user_id INTEGER NULL REFERENCES users (id) ON DELETE CASCADE,
|
||
|
|
purpose TEXT NOT NULL CHECK (purpose IN ('register', 'login')),
|
||
|
|
challenge TEXT NOT NULL,
|
||
|
|
expires_at TEXT NOT NULL,
|
||
|
|
consumed_at TEXT NULL,
|
||
|
|
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%SZ', 'now'))
|
||
|
|
);
|
||
|
|
|
||
|
|
CREATE INDEX IF NOT EXISTS idx_webauthn_challenges_expiry ON webauthn_challenges (expires_at);
|