Build git-lfs with Go 1.25.14, stop serving the runner stage from the
layer cache so Debian security updates land, move typescript and
@astrojs/check out of the shipped dependencies, bump the nested copies
of browserslist, js-yaml, nanoid and sharp to patched versions, and
update browserslist in the website lockfile.
Claude-Session: https://claude.ai/code/session_01Tp9pmi65a8k5jLMQFLf4JX
* feat(auth): API keys for programmatic access
Adds the @better-auth/api-key plugin so scripts and CI pipelines can call
the existing endpoints with an x-api-key header instead of a session
cookie. Keys are owned by a user, hashed at rest, prefixed gm_, never
expire unless an expiry is chosen, and are not rate limited. A small
guard plugin refuses key management calls that arrive with a key, so a
leaked key cannot mint or revoke keys.
New API Keys section on the Authentication tab with create, show once,
copy and revoke. Migration 0017 adds the api_keys table with the
validator fixture. docs/API.md documents the header and the calls
automation needs. An e2e spec covers create, use, refuse and revoke over
HTTP. bun.nix regenerated for the new package.
Closes#314
Claude-Session: https://claude.ai/code/session_01Tp9pmi65a8k5jLMQFLf4JX
* fix(e2e): send Origin on cookie-authenticated key management calls
Better Auth rejects a cookie-authenticated POST without an Origin header (403 MISSING_OR_NULL_ORIGIN). Browsers always send one, the Playwright request context does not, so the spec sets it on the create and delete calls. Also asserts the guard's 403 code and documents the Origin requirement for scripts that manage keys with a session.
Claude-Session: https://claude.ai/code/session_01Tp9pmi65a8k5jLMQFLf4JX
better-auth, @better-auth/oauth-provider and @better-auth/sso move from
1.6.23 to 1.7.2. This is the first stable line with the oauth-provider fix
for unbound resource indicators (Dependabot alert #55); no 1.6.x release
has it.
1.7 keys accounts by (issuer, accountId) and looks the credential account
up with issuer "local:credential" on sign-in, so migration 0016 adds the
column and backfills existing rows: local accounts get local:credential,
SSO accounts take their provider's issuer, other OAuth accounts get the
local:oauth namespace. It also adds jwks.alg and jwks.crv, the 1.7
oauth-provider columns, and the oauth_resources, oauth_client_resources
and oauth_client_assertions tables.
A database that booted the reverted 1.7.0-rc.4 build (on main for a few
minutes on 2026-08-06, and any dev database from then) already has part of
that schema without a 0016 record, which makes 0016 fail on every boot.
repairStrandedBetterAuth17Schema drops the leftovers before migrate runs,
in the same way the #312 repair handles stranded SSO columns; the
migration validator exercises it.
createOAuthClient no longer takes "type"; the SSO applications route sends
application_type (web or native) and reads it back with the legacy column
as fallback. bun.nix is regenerated. reset-users writes the issuer.
Supersedes #374.
Claude-Session: https://claude.ai/code/session_01Tp9pmi65a8k5jLMQFLf4JX
Fixes the @better-auth/oauth-provider advisory (unbound resource
indicators could yield access tokens for unauthorized audiences,
Dependabot #55). No patched 1.6.x exists; 1.7.0-rc.4 is the first
patched line.
The 1.7 oauth-provider expects a wider schema: new nullable columns on
oauth_clients / oauth_access_tokens / oauth_refresh_tokens /
oauth_consents (back-channel logout, DPoP, resource indicators, refresh
token rotation) and three new tables (oauth_resources,
oauth_client_resources, oauth_client_assertions). Migration 0014 is
purely additive; validate-migrations gains the matching upgrade fixture.
better-auth 1.6.23 (fixes GHSA high stored XSS via javascript: redirect_uri), esbuild >=0.28.1 override for www (GHSA low), Astro 7 / @astrojs/node 11 / @astrojs/react 6 / @astrojs/mdx 7 / lucide-react 1.x (inline GitHub icon replaces removed brand icon) and all in-range updates on both the app and the website. The remaining @better-auth/oauth-provider medium advisory is patched upstream only in 1.7-rc and will be picked up when 1.7 stable lands.
Resolves#306. SSO sign-in via OIDC (Authentik / Keycloak / etc.) now links the
SSO identity to an existing email/password admin instead of bouncing to /login
with `?error=UNKNOWN`. Account-linking is gated on the operator-supplied
**Domain** field — cross-domain claims from a compromised IdP are refused.
Also bundles the deprecated `oidcProvider` → `@better-auth/oauth-provider`
migration. **Operators using the OAuth-provider feature must rotate registered
client secrets after upgrade** (legacy plaintext → hashed storage; see the
0012 migration notes).
Verified end-to-end on the pr-307 image against a real Authentik instance:
SSO login lands on the dashboard, `accounts` table gets both `credential` and
`authentik` rows for the same user. See PR description for full details.
Updates `better-auth` and `@better-auth/sso` from 1.5.5 to 1.6.11 to
pick up the patch fixes that have landed since (OAuth state CSRF
verification, scrypt non-blocking password hashing, account cookie
comparison fix, session freshness alignment, etc.). All 270 local
tests pass against the new version.
The only behavioral surface to watch:
- `freshAge` now aligns with session `createdAt` instead of
`updatedAt`. Not applicable here — we don't gate anything on
session freshness.
- 1.6.2 adds OAuth state-parameter CSRF verification. Applies to
OIDC/SAML SSO flows; no code changes needed.
- 1.6 emits a deprecation warning for `oidc-provider` in favor of
`@better-auth/oauth-provider`. The plugin still works in 1.6.x;
migrating it is a separate cleanup.
Prep work for an upcoming header-auth fix (issue #29 follow-up).
Removed 5 overrides whose constraints have since been picked up naturally
by the transitive dep graph. Verified by removing each and confirming the
resolved version (and the dep tree) is identical to what the override
produced:
- defu ^6.1.7 → still resolves 6.1.7
- fast-xml-parser ^5.5.6 → still resolves 5.5.6
- node-forge ^1.3.3 → package not in tree at all (override was dead)
- rollup >=4.59.0 → still resolves 4.59.0
- svgo ^4.0.1 → still resolves 4.0.1
Kept overrides that are still doing real work:
- @esbuild-kit/esm-loader → npm:tsx@^4.21.0 — deliberate replacement shim
- @xmldom/xmldom ^0.8.13, devalue ^5.8.1, fast-uri ^3.1.2,
fast-xml-builder ^1.1.7, kysely ^0.28.17 — active CVE pins (#289)
- lodash ^4.18.1 — pins to the newer 4.18.x line over the legacy 4.17.x
that transitive deps still pull
- picomatch ^4.0.4 — without it, picomatch@2.3.2 is added as a duplicate
copy via a transitive that asks for 2.x
Future drift would be caught by Dependabot + the weekly Docker Scout
scan; the overrides above remain because they currently affect the tree.
Patches 9 Docker Scout HIGH alerts surfaced by the weekly image scan:
- @xmldom/xmldom 0.8.12 → 0.8.13 (CVE-2026-41672/3/4/5)
- devalue 5.6.4 → 5.8.1 (CVE-2026-42570)
- kysely 0.28.16 → 0.28.17 (CVE-2026-44635)
- fast-uri (new override) → ^3.1.2 (CVE-2026-6321, CVE-2026-6322)
- fast-xml-builder (new override) → ^1.1.7 (CVE-2026-44665)
All five resolve to fixed versions after `bun install`. Tests and astro
build pass locally.
Remaining open Docker Scout alerts (git-lfs Go stdlib, gnutls28, nghttp2)
are base-image or upstream-binary issues, not addressable via npm.
The useConfigStatus hook treated `githubConfig.username` and
`giteaConfig.username` as required for the dashboard to render. In
practice neither is required at runtime — the GitHub token is
self-authenticating via listForAuthenticatedUser, and a Gitea username
isn't needed under single-org or flat mirror strategies.
Users who configured via env vars without GITHUB_USERNAME / GITEA_USERNAME
set (or who left those blank in the form, which is only client-side
`required`) ended up with empty strings in their config row. Mirroring
ran fine — tokens alone are sufficient — but the dashboard refused to
fetch and rendered all zeros because useConfigStatus failed the gate.
Drop the username checks from the gate. The `githubOwner` field is still
exported for consumers that want to display an owner; only the gate is
relaxed. Cache-hit and fresh-fetch branches both updated.