From 5128959b472b6729b66474bfbf09d1b4e19da300 Mon Sep 17 00:00:00 2001 From: Ned Wolpert Date: Thu, 8 Oct 2026 06:29:22 -0700 Subject: [PATCH 1/3] docs: style-guide follow-ups, SDK typecheck fix, and refreshed OG image - fix(sdk): ceremonies.test.ts imported types from the nonexistent '../dist/src'; import them from '../src/types' so `npm run typecheck` (and therefore `prepublishOnly`) passes. - site: replace decorative /// with classed spans; drop italic heading accents and italic glosses; remove dead CSS. - og-image: plain tagline (no italic accent), drop hardcoded version, regenerate og-image.png from the SVG. - ADR titles: noun phrases within the heading rules (0001, 0004, 0006, 0008, 0010, 0011, 0016, 0018); index updated, file names unchanged. - ADR 0015: correct the deviceId consequence (JwtClaims has no ttl or device field; PkAuthJwtIssuer passes Optional.empty()). - SECURITY.md: supported line is 2.x; 1.x is no longer supported. Co-Authored-By: Claude Opus 5.5 --- SECURITY.md | 7 +- .../passkeys-browser/test/ceremonies.test.ts | 11 +- .../adr/0001-record-architecture-decisions.md | 2 +- docs/adr/0004-dagger-for-dropwizard.md | 2 +- docs/adr/0006-userlookup-spi-not-owned.md | 2 +- docs/adr/0008-dynamodb-single-table-design.md | 2 +- docs/adr/0010-dropwizard-track-latest.md | 2 +- docs/adr/0011-spring-boot-4.md | 2 +- docs/adr/0015-stateful-access-tokens.md | 7 +- docs/adr/0016-user-deletion-fan-out.md | 2 +- docs/adr/0018-remove-sonarqube-cloud.md | 2 +- docs/adr/README.md | 16 +-- site/index.html | 116 +++++++++--------- site/og-image.png | Bin 154760 -> 203880 bytes site/og-image.svg | 4 +- 15 files changed, 85 insertions(+), 92 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index d27cbed6..6ae00adc 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -4,14 +4,15 @@ pk-auth is an authentication library, so security reports are handled with prior ## Supported versions -Fixes land on the latest published `1.x` line. Maven Central and npm releases are immutable, so a +Fixes land on the latest published `2.x` line. Maven Central and npm releases are immutable, so a security fix ships as a new patch (or minor) release rather than a re-publish of an affected version. Upgrading to the latest release picks up the fix. | Version | Supported | | -------------------- | ----------------------------- | -| Latest `1.x` release | :white_check_mark: | -| Older `1.x` releases | Fix only via the next release | +| Latest `2.x` release | :white_check_mark: | +| Older `2.x` releases | Fix only via the next release | +| `1.x` | :x: (upgrade to `2.x`) | | `0.x` (pre-stable) | :x: | The browser SDK (`@pk-auth/passkeys-browser`) shares the same version line as the JVM artifacts and diff --git a/clients/passkeys-browser/test/ceremonies.test.ts b/clients/passkeys-browser/test/ceremonies.test.ts index 564492f5..658a51d7 100644 --- a/clients/passkeys-browser/test/ceremonies.test.ts +++ b/clients/passkeys-browser/test/ceremonies.test.ts @@ -9,9 +9,12 @@ import { encodeRegistrationResponse, } from "../src/ceremonies"; import type { + FinishAuthenticationRequest, FinishAuthenticationResponse, FinishRegistrationRequest, FinishRegistrationResponse, PublicKeyCredentialCreationOptionsJson, - PublicKeyCredentialRequestOptionsJson, StartRegistrationRequest, StartRegistrationResponse, + PublicKeyCredentialRequestOptionsJson, + StartAuthenticationRequest, StartAuthenticationResponse, + StartRegistrationRequest, StartRegistrationResponse, } from "../src/types"; import { decodeJson, @@ -25,12 +28,6 @@ import { import * as http from "node:http"; import {CeremonyService} from "./helpers/ceremony"; import {FakeAuthenticator} from "./helpers/fakeAuthenticator"; -import { - FinishAuthenticationRequest, - FinishAuthenticationResponse, - StartAuthenticationRequest, - StartAuthenticationResponse -} from "../dist/src"; const CREATE_OPTIONS_JSON: PublicKeyCredentialCreationOptionsJson = { rp: { id: "example.com", name: "Example" }, diff --git a/docs/adr/0001-record-architecture-decisions.md b/docs/adr/0001-record-architecture-decisions.md index 30653cc7..9e9be3c5 100644 --- a/docs/adr/0001-record-architecture-decisions.md +++ b/docs/adr/0001-record-architecture-decisions.md @@ -1,4 +1,4 @@ -# 1. Record architecture decisions +# 1. Architecture decision records Date: 2026-05-12 diff --git a/docs/adr/0004-dagger-for-dropwizard.md b/docs/adr/0004-dagger-for-dropwizard.md index ac681b84..d4a0b06e 100644 --- a/docs/adr/0004-dagger-for-dropwizard.md +++ b/docs/adr/0004-dagger-for-dropwizard.md @@ -1,4 +1,4 @@ -# 4. Use Dagger 2 for the Dropwizard adapter's DI +# 4. Dagger 2 for Dropwizard adapter wiring Date: 2026-05-14 diff --git a/docs/adr/0006-userlookup-spi-not-owned.md b/docs/adr/0006-userlookup-spi-not-owned.md index c3604fa7..5b6321db 100644 --- a/docs/adr/0006-userlookup-spi-not-owned.md +++ b/docs/adr/0006-userlookup-spi-not-owned.md @@ -1,4 +1,4 @@ -# 6. `UserLookup` is an SPI, not an owned table +# 6. `UserLookup` as a host-implemented SPI Date: 2026-05-15 diff --git a/docs/adr/0008-dynamodb-single-table-design.md b/docs/adr/0008-dynamodb-single-table-design.md index 958d3612..38167841 100644 --- a/docs/adr/0008-dynamodb-single-table-design.md +++ b/docs/adr/0008-dynamodb-single-table-design.md @@ -1,4 +1,4 @@ -# 8. DynamoDB single-table design for auth items, separate users table +# 8. DynamoDB single-table design with a separate users table Date: 2026-05-14 diff --git a/docs/adr/0010-dropwizard-track-latest.md b/docs/adr/0010-dropwizard-track-latest.md index dd4ebed8..2864a46c 100644 --- a/docs/adr/0010-dropwizard-track-latest.md +++ b/docs/adr/0010-dropwizard-track-latest.md @@ -1,4 +1,4 @@ -# 10. Track latest Dropwizard rather than pin to 4.x +# 10. Latest Dropwizard release line over a 4.x pin Date: 2026-05-15 diff --git a/docs/adr/0011-spring-boot-4.md b/docs/adr/0011-spring-boot-4.md index dc4d11f6..2f813937 100644 --- a/docs/adr/0011-spring-boot-4.md +++ b/docs/adr/0011-spring-boot-4.md @@ -1,4 +1,4 @@ -# 11. Spring Boot 4 / Spring Security 7 for the Spring starter +# 11. Spring Boot 4 and Spring Security 7 Date: 2026-05-16 diff --git a/docs/adr/0015-stateful-access-tokens.md b/docs/adr/0015-stateful-access-tokens.md index f71d111b..f8573603 100644 --- a/docs/adr/0015-stateful-access-tokens.md +++ b/docs/adr/0015-stateful-access-tokens.md @@ -93,10 +93,9 @@ Adapter wiring: - Con: the store holds one row per issued token. Hosts that issue at high volume (millions per day) and do not need fast revocation should stay with `RevocationCheck` and a small deny-list. The library does not auto-detect this, and the operator picks the binding. -- Con: the `ttl` field on `JwtClaims` is not yet a first-class device-id channel. When stateful, - `record(...)` always passes `Optional.empty()` for `deviceId`. A future ADR (when refresh tokens - land) extends this surface to bind issued JWTs to a refresh family or device for "log out this - device" granularity. +- Con: `JwtClaims` carries no device identifier, so `PkAuthJwtIssuer` always passes + `Optional.empty()` for `deviceId` to `record(...)`. Binding issued JWTs to a refresh family or + device, for "log out this device" granularity, is left to a future ADR. - Con: the validator's hot path now includes a store lookup. For the noop case this is a hash-lookup-then-return, and for JDBI it is one indexed query per validate. Adopters needing the absolute lowest validation latency (for example CDN-near edge validation) should benchmark before diff --git a/docs/adr/0016-user-deletion-fan-out.md b/docs/adr/0016-user-deletion-fan-out.md index c727af9b..c81cffd0 100644 --- a/docs/adr/0016-user-deletion-fan-out.md +++ b/docs/adr/0016-user-deletion-fan-out.md @@ -1,4 +1,4 @@ -# 16. User deletion fan-out is sequential and best-effort +# 16. Sequential best-effort user deletion fan-out Date: 2026-05-16 diff --git a/docs/adr/0018-remove-sonarqube-cloud.md b/docs/adr/0018-remove-sonarqube-cloud.md index b0dd806a..d7c20d8e 100644 --- a/docs/adr/0018-remove-sonarqube-cloud.md +++ b/docs/adr/0018-remove-sonarqube-cloud.md @@ -1,4 +1,4 @@ -# 18. Remove SonarQube Cloud; enforce coverage with native JaCoCo line + branch gates +# 18. Native JaCoCo coverage gates replacing SonarQube Cloud Date: 2026-06-11 diff --git a/docs/adr/README.md b/docs/adr/README.md index 1227e29f..ac19b3d6 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -8,23 +8,23 @@ ADR is added and the prior one is marked `Superseded by NNNN`. See | # | Status | Date | Title | |---|---|---|---| -| [0001](./0001-record-architecture-decisions.md) | Accepted | 2026-05-12 | Record architecture decisions | +| [0001](./0001-record-architecture-decisions.md) | Accepted | 2026-05-12 | Architecture decision records | | [0002](./0002-webauthn4j-over-yubico.md) | Accepted | 2026-05-13 | WebAuthn4J over Yubico java-webauthn-server | | [0003](./0003-jdbi-over-jpa.md) | Accepted | 2026-05-14 | JDBI over JPA | -| [0004](./0004-dagger-for-dropwizard.md) | Accepted | 2026-05-14 | Use Dagger 2 for the Dropwizard adapter's DI | +| [0004](./0004-dagger-for-dropwizard.md) | Accepted | 2026-05-14 | Dagger 2 for Dropwizard adapter wiring | | [0005](./0005-stateless-jwt-default.md) | Accepted | 2026-05-14 | Stateless JWT as the default post-ceremony credential | -| [0006](./0006-userlookup-spi-not-owned.md) | Accepted | 2026-05-15 | `UserLookup` is an SPI, not an owned table | +| [0006](./0006-userlookup-spi-not-owned.md) | Accepted | 2026-05-15 | `UserLookup` as a host-implemented SPI | | [0007](./0007-dynamodb-local-vs-localstack.md) | Accepted | 2026-05-14 | DynamoDB Local over LocalStack for integration tests | -| [0008](./0008-dynamodb-single-table-design.md) | Accepted | 2026-05-14 | DynamoDB single-table design for auth items, separate users table | +| [0008](./0008-dynamodb-single-table-design.md) | Accepted | 2026-05-14 | DynamoDB single-table design with a separate users table | | [0009](./0009-jackson-3-over-jackson-2.md) | Accepted | 2026-05-13 | Jackson 3 (`tools.jackson`) over Jackson 2 (`com.fasterxml.jackson`) | -| [0010](./0010-dropwizard-track-latest.md) | Accepted | 2026-05-15 | Track latest Dropwizard rather than pin to 4.x | -| [0011](./0011-spring-boot-4.md) | Accepted | 2026-05-16 | Spring Boot 4 / Spring Security 7 for the Spring starter | +| [0010](./0010-dropwizard-track-latest.md) | Accepted | 2026-05-15 | Latest Dropwizard release line over a 4.x pin | +| [0011](./0011-spring-boot-4.md) | Accepted | 2026-05-16 | Spring Boot 4 and Spring Security 7 | | [0012](./0012-micronaut-4.md) | Accepted | 2026-05-16 | Micronaut 4 for the Micronaut adapter | | [0013](./0013-refresh-tokens-family-rotation.md) | Accepted | 2026-05-16 | Rotating refresh tokens with family-based replay detection | | [0014](./0014-per-audience-ttl-policy.md) | Accepted | 2026-05-16 | Per-audience JWT TTL via a TokenTtlPolicy SPI | | [0015](./0015-stateful-access-tokens.md) | Accepted | 2026-05-16 | Stateful access tokens via AccessTokenStore SPI | -| [0016](./0016-user-deletion-fan-out.md) | Accepted | 2026-05-16 | User deletion fan-out is sequential and best-effort | +| [0016](./0016-user-deletion-fan-out.md) | Accepted | 2026-05-16 | Sequential best-effort user deletion fan-out | | [0017](./0017-sonarqube-cloud-static-analysis.md) | Superseded by [0018](./0018-remove-sonarqube-cloud.md) | 2026-06-11 | SonarQube Cloud for static analysis and coverage tracking | -| [0018](./0018-remove-sonarqube-cloud.md) | Accepted | 2026-06-11 | Remove SonarQube Cloud; enforce coverage with native JaCoCo line + branch gates | +| [0018](./0018-remove-sonarqube-cloud.md) | Accepted | 2026-06-11 | Native JaCoCo coverage gates replacing SonarQube Cloud | | [0019](./0019-crypto-agility-post-quantum-readiness.md) | Accepted | 2026-06-17 | Crypto-agility and post-quantum readiness for passkey algorithms | | [0020](./0020-browser-sdk-testing-strategy.md) | Accepted | 2026-06-18 | Browser SDK testing strategy | diff --git a/site/index.html b/site/index.html index a574d295..a3c0d18b 100644 --- a/site/index.html +++ b/site/index.html @@ -328,8 +328,8 @@ .wordmark .mark .dot { fill: var(--accent); } .wordmark .mark .ring { stroke: var(--accent); } .wordmark .mark { width: 26px; height: 26px; display: inline-block; } - .wordmark strong { font-weight: 600; font-variant: small-caps; letter-spacing: 0.16em; } - .wordmark em { font-style: italic; color: var(--ink-muted); font-size: 13px; letter-spacing: 0.06em; } + .wordmark .wordmark-name { font-weight: 600; font-variant: small-caps; letter-spacing: 0.16em; } + .wordmark .wordmark-tag { color: var(--ink-muted); font-size: 13px; letter-spacing: 0.06em; } .nav-wrap { display: flex; align-items: center; gap: 22px; } nav.primary { display: flex; gap: 26px; align-items: center; } @@ -478,7 +478,6 @@ font-optical-sizing: auto; } h2 { font-size: clamp(34px, 4.2vw, 54px); margin-bottom: var(--s5); max-width: 18ch; } - h2 em { font-style: italic; color: var(--accent-text); } h3 { font-size: 23px; margin-bottom: var(--s4); letter-spacing: -0.01em; } h4 { font-size: 16px; font-variant: small-caps; letter-spacing: 0.14em; @@ -545,7 +544,7 @@ animation: rise .9s .4s ease-out backwards; } .framework-chips span { display: inline-flex; align-items: center; gap: 8px; } - .framework-chips i { + .framework-chips .marker { width: 6px; height: 6px; background: var(--brass); display: inline-block; transform: rotate(45deg); } @@ -654,9 +653,9 @@ font-family: var(--mono); font-size: 12px; color: var(--ink-muted); content: attr(data-idx); letter-spacing: 0.1em; } - .boundary-col li b { display: block; font-weight: 600; color: var(--ink); margin-bottom: 2px; } - .boundary-col li i.gloss { color: var(--ink-muted); font-style: italic; font-weight: 400; } - .boundary-col--isnt li b { + .boundary-col li .item-label { display: block; font-weight: 600; color: var(--ink); margin-bottom: 2px; } + .boundary-col li .gloss { color: var(--ink-muted); font-weight: 400; } + .boundary-col--isnt li .item-label { color: var(--accent-text); text-decoration: line-through; text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent); text-decoration-thickness: 1px; @@ -773,9 +772,9 @@ text-align: right; border-right: 1px solid var(--rule); padding-right: 16px; white-space: nowrap; } - .step-num b { + .step-num .step-index { display: block; font-family: var(--serif); font-size: 42px; color: var(--accent-text); - font-style: italic; font-weight: 400; letter-spacing: 0; margin-bottom: 8px; + font-weight: 400; letter-spacing: 0; margin-bottom: 8px; font-variant-numeric: lining-nums; } .step-body h3 { margin-bottom: 8px; } @@ -803,7 +802,6 @@ margin-top: var(--s5); font-size: 14.5px; color: var(--ink-muted); line-height: 1.6; max-width: 60ch; } - .try-caption strong { color: var(--ink); font-weight: 600; } /* ============== MODULES ============== */ .module-intro { @@ -816,10 +814,10 @@ display: flex; gap: 22px; flex-wrap: wrap; align-self: end; padding-bottom: 6px; } .module-key span { display: inline-flex; align-items: center; gap: 8px; } - .module-key i { width: 10px; height: 10px; display: inline-block; transform: rotate(45deg); } - .module-key .req i { background: var(--accent); } - .module-key .pick i { background: var(--brass); } - .module-key .opt i { background: var(--patina); } + .module-key .marker { width: 10px; height: 10px; display: inline-block; transform: rotate(45deg); } + .module-key .req .marker { background: var(--accent); } + .module-key .pick .marker { background: var(--brass); } + .module-key .opt .marker { background: var(--patina); } .module-groups { display: grid; gap: 0; } .module-group { @@ -859,7 +857,7 @@ .module-group.g-opt .module-card { border-left-color: var(--patina); } .module-card-top { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; } .module-card-name { font-family: var(--mono); font-size: 13.5px; color: var(--ink); letter-spacing: -0.01em; } - .module-card-name b { color: var(--accent-text); font-weight: 500; } + .module-card-name .group-id { color: var(--accent-text); font-weight: 500; } .module-card .tag { font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--ink-muted); white-space: nowrap; flex-shrink: 0; @@ -913,7 +911,6 @@ font-family: var(--serif); font-size: 15px; color: var(--ink-soft); line-height: 1.6; } .wire-note + .wire-note { margin-top: 14px; border-left-color: var(--patina); } - .wire-note strong { color: var(--accent-text); font-weight: 600; } .wire-note code { font-size: 12.5px; } /* ============== SECURITY ============== */ @@ -955,7 +952,6 @@ } .maturity p { font-size: 15.5px; color: var(--ink-soft); line-height: 1.6; max-width: 78ch; } .maturity p + p { margin-top: 12px; } - .maturity strong { color: var(--accent-text); font-weight: 600; } /* ============== FOOTER ============== */ footer.site { @@ -1011,7 +1007,7 @@ text-align: left; border-right: 0; padding-right: 0; padding-bottom: 4px; border-bottom: 1px solid var(--rule); padding-top: 0; } - .step-num b { display: inline; margin-right: 14px; font-size: 34px; } + .step-num .step-index { display: inline; margin-right: 14px; font-size: 34px; } .footer-grid { grid-template-columns: 1fr; } .code { font-size: 12px; padding: 22px 18px; } .hero h1 .rule { display: none; } @@ -1037,8 +1033,8 @@ - pk-auth - WebAuthn on the JVM + pk-auth + WebAuthn on the JVM